comparison src/org/eclipse/jetty/server/HttpWriter.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 23ec25435b8c
comparison
equal deleted inserted replaced
801:6a21393191c1 802:3428c60d7cfc
1 //
2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
21 import java.io.IOException;
22 import java.io.OutputStreamWriter;
23 import java.io.Writer;
24
25 import org.eclipse.jetty.http.AbstractGenerator;
26 import org.eclipse.jetty.util.ByteArrayOutputStream2;
27 import org.eclipse.jetty.util.StringUtil;
28
29 /** OutputWriter.
30 * A writer that can wrap a {@link HttpOutput} stream and provide
31 * character encodings.
32 *
33 * The UTF-8 encoding is done by this class and no additional
34 * buffers or Writers are used.
35 * The UTF-8 code was inspired by http://javolution.org
36 */
37 public class HttpWriter extends Writer
38 {
39 public static final int MAX_OUTPUT_CHARS = 512;
40
41 private static final int WRITE_CONV = 0;
42 private static final int WRITE_ISO1 = 1;
43 private static final int WRITE_UTF8 = 2;
44
45 final HttpOutput _out;
46 final AbstractGenerator _generator;
47 int _writeMode;
48 int _surrogate;
49
50 /* ------------------------------------------------------------ */
51 public HttpWriter(HttpOutput out)
52 {
53 _out=out;
54 _generator=_out._generator;
55 _surrogate=0; // AS lastUTF16CodePoint
56 }
57
58 /* ------------------------------------------------------------ */
59 public void setCharacterEncoding(String encoding)
60 {
61 if (encoding == null || StringUtil.__ISO_8859_1.equalsIgnoreCase(encoding))
62 {
63 _writeMode = WRITE_ISO1;
64 }
65 else if (StringUtil.__UTF8.equalsIgnoreCase(encoding))
66 {
67 _writeMode = WRITE_UTF8;
68 }
69 else
70 {
71 _writeMode = WRITE_CONV;
72 if (_out._characterEncoding == null || !_out._characterEncoding.equalsIgnoreCase(encoding))
73 _out._converter = null; // Set lazily in getConverter()
74 }
75
76 _out._characterEncoding = encoding;
77 if (_out._bytes==null)
78 _out._bytes = new ByteArrayOutputStream2(MAX_OUTPUT_CHARS);
79 }
80
81 /* ------------------------------------------------------------ */
82 @Override
83 public void close() throws IOException
84 {
85 _out.close();
86 }
87
88 /* ------------------------------------------------------------ */
89 @Override
90 public void flush() throws IOException
91 {
92 _out.flush();
93 }
94
95 /* ------------------------------------------------------------ */
96 @Override
97 public void write (String s,int offset, int length) throws IOException
98 {
99 while (length > MAX_OUTPUT_CHARS)
100 {
101 write(s, offset, MAX_OUTPUT_CHARS);
102 offset += MAX_OUTPUT_CHARS;
103 length -= MAX_OUTPUT_CHARS;
104 }
105
106 if (_out._chars==null)
107 {
108 _out._chars = new char[MAX_OUTPUT_CHARS];
109 }
110 char[] chars = _out._chars;
111 s.getChars(offset, offset + length, chars, 0);
112 write(chars, 0, length);
113 }
114
115 /* ------------------------------------------------------------ */
116 @Override
117 public void write (char[] s,int offset, int length) throws IOException
118 {
119 HttpOutput out = _out;
120
121 while (length > 0)
122 {
123 out._bytes.reset();
124 int chars = length>MAX_OUTPUT_CHARS?MAX_OUTPUT_CHARS:length;
125
126 switch (_writeMode)
127 {
128 case WRITE_CONV:
129 {
130 Writer converter=getConverter();
131 converter.write(s, offset, chars);
132 converter.flush();
133 }
134 break;
135
136 case WRITE_ISO1:
137 {
138 byte[] buffer=out._bytes.getBuf();
139 int bytes=out._bytes.getCount();
140
141 if (chars>buffer.length-bytes)
142 chars=buffer.length-bytes;
143
144 for (int i = 0; i < chars; i++)
145 {
146 int c = s[offset+i];
147 buffer[bytes++]=(byte)(c<256?c:'?'); // ISO-1 and UTF-8 match for 0 - 255
148 }
149 if (bytes>=0)
150 out._bytes.setCount(bytes);
151
152 break;
153 }
154
155 case WRITE_UTF8:
156 {
157 byte[] buffer=out._bytes.getBuf();
158 int bytes=out._bytes.getCount();
159
160 if (bytes+chars>buffer.length)
161 chars=buffer.length-bytes;
162
163 for (int i = 0; i < chars; i++)
164 {
165 int code = s[offset+i];
166
167 // Do we already have a surrogate?
168 if(_surrogate==0)
169 {
170 // No - is this char code a surrogate?
171 if(Character.isHighSurrogate((char)code))
172 {
173 _surrogate=code; // UCS-?
174 continue;
175 }
176 }
177 // else handle a low surrogate
178 else if(Character.isLowSurrogate((char)code))
179 {
180 code = Character.toCodePoint((char)_surrogate, (char)code); // UCS-4
181 }
182 // else UCS-2
183 else
184 {
185 code=_surrogate; // UCS-2
186 _surrogate=0; // USED
187 i--;
188 }
189
190 if ((code & 0xffffff80) == 0)
191 {
192 // 1b
193 if (bytes>=buffer.length)
194 {
195 chars=i;
196 break;
197 }
198 buffer[bytes++]=(byte)(code);
199 }
200 else
201 {
202 if((code&0xfffff800)==0)
203 {
204 // 2b
205 if (bytes+2>buffer.length)
206 {
207 chars=i;
208 break;
209 }
210 buffer[bytes++]=(byte)(0xc0|(code>>6));
211 buffer[bytes++]=(byte)(0x80|(code&0x3f));
212 }
213 else if((code&0xffff0000)==0)
214 {
215 // 3b
216 if (bytes+3>buffer.length)
217 {
218 chars=i;
219 break;
220 }
221 buffer[bytes++]=(byte)(0xe0|(code>>12));
222 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
223 buffer[bytes++]=(byte)(0x80|(code&0x3f));
224 }
225 else if((code&0xff200000)==0)
226 {
227 // 4b
228 if (bytes+4>buffer.length)
229 {
230 chars=i;
231 break;
232 }
233 buffer[bytes++]=(byte)(0xf0|(code>>18));
234 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
235 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
236 buffer[bytes++]=(byte)(0x80|(code&0x3f));
237 }
238 else if((code&0xf4000000)==0)
239 {
240 // 5b
241 if (bytes+5>buffer.length)
242 {
243 chars=i;
244 break;
245 }
246 buffer[bytes++]=(byte)(0xf8|(code>>24));
247 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
248 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
249 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
250 buffer[bytes++]=(byte)(0x80|(code&0x3f));
251 }
252 else if((code&0x80000000)==0)
253 {
254 // 6b
255 if (bytes+6>buffer.length)
256 {
257 chars=i;
258 break;
259 }
260 buffer[bytes++]=(byte)(0xfc|(code>>30));
261 buffer[bytes++]=(byte)(0x80|((code>>24)&0x3f));
262 buffer[bytes++]=(byte)(0x80|((code>>18)&0x3f));
263 buffer[bytes++]=(byte)(0x80|((code>>12)&0x3f));
264 buffer[bytes++]=(byte)(0x80|((code>>6)&0x3f));
265 buffer[bytes++]=(byte)(0x80|(code&0x3f));
266 }
267 else
268 {
269 buffer[bytes++]=(byte)('?');
270 }
271
272 _surrogate=0; // USED
273
274 if (bytes==buffer.length)
275 {
276 chars=i+1;
277 break;
278 }
279 }
280 }
281 out._bytes.setCount(bytes);
282 break;
283 }
284 default:
285 throw new IllegalStateException();
286 }
287
288 out._bytes.writeTo(out);
289 length-=chars;
290 offset+=chars;
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 }