Mercurial Hosting > luan
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 } |
