Mercurial Hosting > luan
comparison src/org/eclipse/jetty/server/HttpWriter.java @ 984:7b0fa315e835
simplify HttpWriter
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Sun, 16 Oct 2016 23:11:15 -0600 |
| parents | 23ec25435b8c |
| children | 8fef34f665e7 |
comparison
equal
deleted
inserted
replaced
| 983:23ec25435b8c | 984:7b0fa315e835 |
|---|---|
| 32 * | 32 * |
| 33 * The UTF-8 encoding is done by this class and no additional | 33 * The UTF-8 encoding is done by this class and no additional |
| 34 * buffers or Writers are used. | 34 * buffers or Writers are used. |
| 35 * The UTF-8 code was inspired by http://javolution.org | 35 * The UTF-8 code was inspired by http://javolution.org |
| 36 */ | 36 */ |
| 37 public class HttpWriter extends Writer | 37 public final class HttpWriter extends Writer |
| 38 { | 38 { |
| 39 public static final int MAX_OUTPUT_CHARS = 512; | 39 private static final int MAX_OUTPUT_CHARS = 512; |
| 40 | 40 |
| 41 private static final int WRITE_CONV = 0; | 41 private static final int WRITE_CONV = 0; |
| 42 private static final int WRITE_ISO1 = 1; | 42 private static final int WRITE_ISO1 = 1; |
| 43 private static final int WRITE_UTF8 = 2; | 43 private static final int WRITE_UTF8 = 2; |
| 44 | 44 |
| 45 final HttpOutput _out; | 45 private final HttpOutput _out; |
| 46 final HttpGenerator _generator; | 46 private int _writeMode; |
| 47 int _writeMode; | 47 private int _surrogate; |
| 48 int _surrogate; | 48 |
| 49 | 49 public HttpWriter(HttpOutput out) |
| 50 /* ------------------------------------------------------------ */ | 50 { |
| 51 public HttpWriter(HttpOutput out) | 51 _out = out; |
| 52 { | 52 _surrogate = 0; // AS lastUTF16CodePoint |
| 53 _out=out; | 53 } |
| 54 _generator=_out._generator; | 54 |
| 55 _surrogate=0; // AS lastUTF16CodePoint | 55 public void setCharacterEncoding(String encoding) |
| 56 } | 56 { |
| 57 | 57 if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding)) |
| 58 /* ------------------------------------------------------------ */ | 58 { |
| 59 public void setCharacterEncoding(String encoding) | 59 _writeMode = WRITE_ISO1; |
| 60 { | 60 } |
| 61 if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding)) | 61 else if (StringUtil.__UTF8.equalsIgnoreCase(encoding)) |
| 62 { | 62 { |
| 63 _writeMode = WRITE_ISO1; | 63 _writeMode = WRITE_UTF8; |
| 64 } | 64 } |
| 65 else if (StringUtil.__UTF8.equalsIgnoreCase(encoding)) | 65 else |
| 66 { | 66 { |
| 67 _writeMode = WRITE_UTF8; | 67 _writeMode = WRITE_CONV; |
| 68 } | 68 if (_out._characterEncoding == null || !_out._characterEncoding.equalsIgnoreCase(encoding)) |
| 69 else | 69 _out._converter = null; // Set lazily in getConverter() |
| 70 { | 70 } |
| 71 _writeMode = WRITE_CONV; | 71 |
| 72 if (_out._characterEncoding == null || !_out._characterEncoding.equalsIgnoreCase(encoding)) | 72 _out._characterEncoding = encoding; |
| 73 _out._converter = null; // Set lazily in getConverter() | 73 if (_out._bytes==null) |
| 74 } | 74 _out._bytes = new ByteArrayOutputStream2(MAX_OUTPUT_CHARS); |
| 75 | 75 } |
| 76 _out._characterEncoding = encoding; | 76 |
| 77 if (_out._bytes==null) | 77 @Override |
| 78 _out._bytes = new ByteArrayOutputStream2(MAX_OUTPUT_CHARS); | 78 public void close() throws IOException |
| 79 } | 79 { |
| 80 | 80 _out.close(); |
| 81 /* ------------------------------------------------------------ */ | 81 } |
| 82 @Override | 82 |
| 83 public void close() throws IOException | 83 @Override |
| 84 { | 84 public void flush() throws IOException |
| 85 _out.close(); | 85 { |
| 86 } | 86 _out.flush(); |
| 87 | 87 } |
| 88 /* ------------------------------------------------------------ */ | 88 |
| 89 @Override | 89 @Override |
| 90 public void flush() throws IOException | 90 public void write (String s,int offset, int length) throws IOException |
| 91 { | 91 { |
| 92 _out.flush(); | 92 while (length > MAX_OUTPUT_CHARS) |
| 93 } | 93 { |
| 94 | 94 write(s, offset, MAX_OUTPUT_CHARS); |
| 95 /* ------------------------------------------------------------ */ | 95 offset += MAX_OUTPUT_CHARS; |
| 96 @Override | 96 length -= MAX_OUTPUT_CHARS; |
| 97 public void write (String s,int offset, int length) throws IOException | 97 } |
| 98 { | 98 |
| 99 while (length > MAX_OUTPUT_CHARS) | 99 if (_out._chars==null) |
| 100 { | 100 { |
| 101 write(s, offset, MAX_OUTPUT_CHARS); | 101 _out._chars = new char[MAX_OUTPUT_CHARS]; |
| 102 offset += MAX_OUTPUT_CHARS; | 102 } |
| 103 length -= MAX_OUTPUT_CHARS; | 103 char[] chars = _out._chars; |
| 104 } | 104 s.getChars(offset, offset + length, chars, 0); |
| 105 | 105 write(chars, 0, length); |
| 106 if (_out._chars==null) | 106 } |
| 107 { | 107 |
| 108 _out._chars = new char[MAX_OUTPUT_CHARS]; | 108 @Override |
| 109 } | 109 public void write (char[] s,int offset, int length) throws IOException |
| 110 char[] chars = _out._chars; | 110 { |
| 111 s.getChars(offset, offset + length, chars, 0); | 111 HttpOutput out = _out; |
| 112 write(chars, 0, length); | 112 |
| 113 } | 113 while (length > 0) |
| 114 | 114 { |
| 115 /* ------------------------------------------------------------ */ | 115 out._bytes.reset(); |
| 116 @Override | 116 int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length; |
| 117 public void write (char[] s,int offset, int length) throws IOException | 117 |
| 118 { | 118 switch (_writeMode) |
| 119 HttpOutput out = _out; | 119 { |
| 120 | 120 case WRITE_CONV: |
| 121 while (length > 0) | 121 { |
| 122 { | 122 Writer converter = getConverter(); |
| 123 out._bytes.reset(); | 123 converter.write(s, offset, chars); |
| 124 int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length; | 124 converter.flush(); |
| 125 | 125 } |
| 126 switch (_writeMode) | 126 break; |
| 127 { | 127 |
| 128 case WRITE_CONV: | 128 case WRITE_ISO1: |
| 129 { | 129 { |
| 130 Writer converter=getConverter(); | 130 byte[] buffer=out._bytes.getBuf(); |
| 131 converter.write(s, offset, chars); | 131 int bytes=out._bytes.getCount(); |
| 132 converter.flush(); | 132 |
| 133 } | 133 if (chars>buffer.length-bytes) |
| 134 break; | 134 chars=buffer.length-bytes; |
| 135 | 135 |
| 136 case WRITE_ISO1: | 136 for (int i = 0; i < chars; i++) |
| 137 { | 137 { |
| 138 byte[] buffer=out._bytes.getBuf(); | 138 int c = s[offset+i]; |
| 139 int bytes=out._bytes.getCount(); | 139 buffer[bytes++]=(byte)(c<256?c:'?'); // ISO-1 and UTF-8 match for 0 - 255 |
| 140 | 140 } |
| 141 if (chars>buffer.length-bytes) | 141 if (bytes>=0) |
| 142 chars=buffer.length-bytes; | 142 out._bytes.setCount(bytes); |
| 143 | 143 |
| 144 for (int i = 0; i < chars; i++) | 144 break; |
| 145 { | 145 } |
| 146 int c = s[offset+i]; | 146 |
| 147 buffer[bytes++]=(byte)(c<256?c:'?'); // ISO-1 and UTF-8 match for 0 - 255 | 147 case WRITE_UTF8: |
| 148 } | 148 { |
| 149 if (bytes>=0) | 149 byte[] buffer=out._bytes.getBuf(); |
| 150 out._bytes.setCount(bytes); | 150 int bytes=out._bytes.getCount(); |
| 151 | 151 |
| 152 break; | 152 if (bytes+chars>buffer.length) |
| 153 } | 153 chars=buffer.length-bytes; |
| 154 | 154 |
| 155 case WRITE_UTF8: | 155 for (int i = 0; i < chars; i++) |
| 156 { | 156 { |
| 157 byte[] buffer=out._bytes.getBuf(); | 157 int code = s[offset+i]; |
| 158 int bytes=out._bytes.getCount(); | 158 |
| 159 | 159 // Do we already have a surrogate? |
| 160 if (bytes+chars>buffer.length) | 160 if(_surrogate==0) |
| 161 chars=buffer.length-bytes; | 161 { |
| 162 | 162 // No - is this char code a surrogate? |
| 163 for (int i = 0; i < chars; i++) | 163 if(Character.isHighSurrogate((char)code)) |
| 164 { | 164 { |
| 165 int code = s[offset+i]; | 165 _surrogate=code; // UCS-? |
| 166 | 166 continue; |
| 167 // Do we already have a surrogate? | 167 } |
| 168 if(_surrogate==0) | 168 } |
| 169 { | 169 // else handle a low surrogate |
| 170 // No - is this char code a surrogate? | 170 else if(Character.isLowSurrogate((char)code)) |
| 171 if(Character.isHighSurrogate((char)code)) | 171 { |
| 172 { | 172 code = Character.toCodePoint((char)_surrogate, (char)code); // UCS-4 |
| 173 _surrogate=code; // UCS-? | 173 } |
| 174 continue; | 174 // else UCS-2 |
| 175 } | 175 else |
| 176 } | 176 { |
| 177 // else handle a low surrogate | 177 code=_surrogate; // UCS-2 |
| 178 else if(Character.isLowSurrogate((char)code)) | 178 _surrogate=0; // USED |
| 179 { | 179 i--; |
| 180 code = Character.toCodePoint((char)_surrogate, (char)code); // UCS-4 | 180 } |
| 181 } | 181 |
| 182 // else UCS-2 | 182 if ((code & 0xffffff80) == 0) |
| 183 else | 183 { |
| 184 { | 184 // 1b |
| 185 code=_surrogate; // UCS-2 | 185 if (bytes>=buffer.length) |
| 186 _surrogate=0; // USED | 186 { |
| 187 i--; | 187 chars=i; |
| 188 } | 188 break; |
| 189 | 189 } |
| 190 if ((code & 0xffffff80) == 0) | 190 buffer[bytes++]=(byte)(code); |
| 191 { | 191 } |
| 192 // 1b | 192 else |
| 193 if (bytes>=buffer.length) | 193 { |
| 194 { | 194 if((code&0xfffff800)==0) |
| 195 chars=i; | 195 { |
| 196 break; | 196 // 2b |
| 197 } | 197 if (bytes+2>buffer.length) |
| 198 buffer[bytes++]=(byte)(code); | 198 { |
| 199 } | 199 chars=i; |
| 200 else | 200 break; |
| 201 { | 201 } |
| 202 if((code&0xfffff800)==0) | 202 buffer[bytes++]=(byte)(0xc0|(code>>6)); |
| 203 { | 203 buffer[bytes++]=(byte)(0x80|(code&0x3f)); |
| 204 // 2b | 204 } |
| 205 if (bytes+2>buffer.length) | 205 else if((code&0xffff0000)==0) |
| 206 { | 206 { |
| 207 chars=i; | 207 // 3b |
| 208 break; | 208 if (bytes+3>buffer.length) |
| 209 } | 209 { |
| 210 buffer[bytes++]=(byte)(0xc0|(code>>6)); | 210 chars=i; |
| 211 buffer[bytes++]=(byte)(0x80|(code&0x3f)); | 211 break; |
| 212 } | 212 } |
| 213 else if((code&0xffff0000)==0) | 213 buffer[bytes++]=(byte)(0xe0|(code>>12)); |
| 214 { | 214 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); |
| 215 // 3b | 215 buffer[bytes++]=(byte)(0x80|(code&0x3f)); |
| 216 if (bytes+3>buffer.length) | 216 } |
| 217 { | 217 else if((code&0xff200000)==0) |
| 218 chars=i; | 218 { |
| 219 break; | 219 // 4b |
| 220 } | 220 if (bytes+4>buffer.length) |
| 221 buffer[bytes++]=(byte)(0xe0|(code>>12)); | 221 { |
| 222 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); | 222 chars=i; |
| 223 buffer[bytes++]=(byte)(0x80|(code&0x3f)); | 223 break; |
| 224 } | 224 } |
| 225 else if((code&0xff200000)==0) | 225 buffer[bytes++]=(byte)(0xf0|(code>>18)); |
| 226 { | 226 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f)); |
| 227 // 4b | 227 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); |
| 228 if (bytes+4>buffer.length) | 228 buffer[bytes++]=(byte)(0x80|(code&0x3f)); |
| 229 { | 229 } |
| 230 chars=i; | 230 else if((code&0xf4000000)==0) |
| 231 break; | 231 { |
| 232 } | 232 // 5b |
| 233 buffer[bytes++]=(byte)(0xf0|(code>>18)); | 233 if (bytes+5>buffer.length) |
| 234 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f)); | 234 { |
| 235 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); | 235 chars=i; |
| 236 buffer[bytes++]=(byte)(0x80|(code&0x3f)); | 236 break; |
| 237 } | 237 } |
| 238 else if((code&0xf4000000)==0) | 238 buffer[bytes++]=(byte)(0xf8|(code>>24)); |
| 239 { | 239 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f)); |
| 240 // 5b | 240 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f)); |
| 241 if (bytes+5>buffer.length) | 241 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); |
| 242 { | 242 buffer[bytes++]=(byte)(0x80|(code&0x3f)); |
| 243 chars=i; | 243 } |
| 244 break; | 244 else if((code&0x80000000)==0) |
| 245 } | 245 { |
| 246 buffer[bytes++]=(byte)(0xf8|(code>>24)); | 246 // 6b |
| 247 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f)); | 247 if (bytes+6>buffer.length) |
| 248 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f)); | 248 { |
| 249 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); | 249 chars=i; |
| 250 buffer[bytes++]=(byte)(0x80|(code&0x3f)); | 250 break; |
| 251 } | 251 } |
| 252 else if((code&0x80000000)==0) | 252 buffer[bytes++]=(byte)(0xfc|(code>>30)); |
| 253 { | 253 buffer[bytes++]=(byte)(0x80|((code>>24)&0x3f)); |
| 254 // 6b | 254 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f)); |
| 255 if (bytes+6>buffer.length) | 255 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f)); |
| 256 { | 256 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); |
| 257 chars=i; | 257 buffer[bytes++]=(byte)(0x80|(code&0x3f)); |
| 258 break; | 258 } |
| 259 } | 259 else |
| 260 buffer[bytes++]=(byte)(0xfc|(code>>30)); | 260 { |
| 261 buffer[bytes++]=(byte)(0x80|((code>>24)&0x3f)); | 261 buffer[bytes++]=(byte)('?'); |
| 262 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f)); | 262 } |
| 263 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f)); | 263 |
| 264 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f)); | 264 _surrogate=0; // USED |
| 265 buffer[bytes++]=(byte)(0x80|(code&0x3f)); | 265 |
| 266 } | 266 if (bytes==buffer.length) |
| 267 else | 267 { |
| 268 { | 268 chars=i+1; |
| 269 buffer[bytes++]=(byte)('?'); | 269 break; |
| 270 } | 270 } |
| 271 | 271 } |
| 272 _surrogate=0; // USED | 272 } |
| 273 | 273 out._bytes.setCount(bytes); |
| 274 if (bytes==buffer.length) | 274 break; |
| 275 { | 275 } |
| 276 chars=i+1; | 276 default: |
| 277 break; | 277 throw new IllegalStateException(); |
| 278 } | 278 } |
| 279 } | 279 |
| 280 } | 280 out._bytes.writeTo(out); |
| 281 out._bytes.setCount(bytes); | 281 length-=chars; |
| 282 break; | 282 offset+=chars; |
| 283 } | 283 } |
| 284 default: | 284 } |
| 285 throw new IllegalStateException(); | 285 |
| 286 } | 286 private Writer getConverter() throws IOException |
| 287 | 287 { |
| 288 out._bytes.writeTo(out); | 288 if (_out._converter == null) |
| 289 length-=chars; | 289 _out._converter = new OutputStreamWriter(_out._bytes, _out._characterEncoding); |
| 290 offset+=chars; | 290 return _out._converter; |
| 291 } | 291 } |
| 292 } | |
| 293 | |
| 294 | |
| 295 /* ------------------------------------------------------------ */ | |
| 296 private Writer getConverter() throws IOException | |
| 297 { | |
| 298 if (_out._converter == null) | |
| 299 _out._converter = new OutputStreamWriter(_out._bytes, _out._characterEncoding); | |
| 300 return _out._converter; | |
| 301 } | |
| 302 } | 292 } |
