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 }