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 } |