Mercurial Hosting > luan
comparison src/org/eclipse/jetty/http/gzip/AbstractCompressedStream.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 |
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.http.gzip; | |
| 20 | |
| 21 import java.io.IOException; | |
| 22 import java.io.OutputStream; | |
| 23 import java.io.OutputStreamWriter; | |
| 24 import java.io.PrintWriter; | |
| 25 import java.io.UnsupportedEncodingException; | |
| 26 import java.util.zip.DeflaterOutputStream; | |
| 27 | |
| 28 import javax.servlet.ServletOutputStream; | |
| 29 import javax.servlet.http.HttpServletRequest; | |
| 30 import javax.servlet.http.HttpServletResponse; | |
| 31 | |
| 32 import org.eclipse.jetty.util.ByteArrayOutputStream2; | |
| 33 | |
| 34 /* ------------------------------------------------------------ */ | |
| 35 /** | |
| 36 * Skeletal implementation of a CompressedStream. This class adds compression features to a ServletOutputStream and takes care of setting response headers, etc. | |
| 37 * Major work and configuration is done here. Subclasses using different kinds of compression only have to implement the abstract methods doCompress() and | |
| 38 * setContentEncoding() using the desired compression and setting the appropriate Content-Encoding header string. | |
| 39 */ | |
| 40 public abstract class AbstractCompressedStream extends ServletOutputStream | |
| 41 { | |
| 42 private final String _encoding; | |
| 43 protected final String _vary; | |
| 44 protected final CompressedResponseWrapper _wrapper; | |
| 45 protected final HttpServletResponse _response; | |
| 46 protected OutputStream _out; | |
| 47 protected ByteArrayOutputStream2 _bOut; | |
| 48 protected DeflaterOutputStream _compressedOutputStream; | |
| 49 protected boolean _closed; | |
| 50 protected boolean _doNotCompress; | |
| 51 | |
| 52 /** | |
| 53 * Instantiates a new compressed stream. | |
| 54 * | |
| 55 */ | |
| 56 public AbstractCompressedStream(String encoding,HttpServletRequest request, CompressedResponseWrapper wrapper,String vary) | |
| 57 throws IOException | |
| 58 { | |
| 59 _encoding=encoding; | |
| 60 _wrapper = wrapper; | |
| 61 _response = (HttpServletResponse)wrapper.getResponse(); | |
| 62 _vary=vary; | |
| 63 | |
| 64 if (_wrapper.getMinCompressSize()==0) | |
| 65 doCompress(); | |
| 66 } | |
| 67 | |
| 68 /* ------------------------------------------------------------ */ | |
| 69 /** | |
| 70 * Reset buffer. | |
| 71 */ | |
| 72 public void resetBuffer() | |
| 73 { | |
| 74 if (_response.isCommitted() || _compressedOutputStream!=null ) | |
| 75 throw new IllegalStateException("Committed"); | |
| 76 _closed = false; | |
| 77 _out = null; | |
| 78 _bOut = null; | |
| 79 _doNotCompress = false; | |
| 80 } | |
| 81 | |
| 82 /* ------------------------------------------------------------ */ | |
| 83 public void setBufferSize(int bufferSize) | |
| 84 { | |
| 85 if (_bOut!=null && _bOut.getBuf().length<bufferSize) | |
| 86 { | |
| 87 ByteArrayOutputStream2 b = new ByteArrayOutputStream2(bufferSize); | |
| 88 b.write(_bOut.getBuf(),0,_bOut.size()); | |
| 89 _bOut=b; | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 /* ------------------------------------------------------------ */ | |
| 94 public void setContentLength() | |
| 95 { | |
| 96 if (_doNotCompress) | |
| 97 { | |
| 98 long length=_wrapper.getContentLength(); | |
| 99 if (length>=0) | |
| 100 { | |
| 101 if (length < Integer.MAX_VALUE) | |
| 102 _response.setContentLength((int)length); | |
| 103 else | |
| 104 _response.setHeader("Content-Length",Long.toString(length)); | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 /* ------------------------------------------------------------ */ | |
| 110 /** | |
| 111 * @see java.io.OutputStream#flush() | |
| 112 */ | |
| 113 @Override | |
| 114 public void flush() throws IOException | |
| 115 { | |
| 116 if (_out == null || _bOut != null) | |
| 117 { | |
| 118 long length=_wrapper.getContentLength(); | |
| 119 if (length > 0 && length < _wrapper.getMinCompressSize()) | |
| 120 doNotCompress(false); | |
| 121 else | |
| 122 doCompress(); | |
| 123 } | |
| 124 | |
| 125 _out.flush(); | |
| 126 } | |
| 127 | |
| 128 /* ------------------------------------------------------------ */ | |
| 129 /** | |
| 130 * @see java.io.OutputStream#close() | |
| 131 */ | |
| 132 @Override | |
| 133 public void close() throws IOException | |
| 134 { | |
| 135 if (_closed) | |
| 136 return; | |
| 137 | |
| 138 if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null) | |
| 139 flush(); | |
| 140 else | |
| 141 { | |
| 142 if (_bOut != null) | |
| 143 { | |
| 144 long length=_wrapper.getContentLength(); | |
| 145 if (length < 0) | |
| 146 { | |
| 147 length = _bOut.getCount(); | |
| 148 _wrapper.setContentLength(length); | |
| 149 } | |
| 150 if (length < _wrapper.getMinCompressSize()) | |
| 151 doNotCompress(false); | |
| 152 else | |
| 153 doCompress(); | |
| 154 } | |
| 155 else if (_out == null) | |
| 156 { | |
| 157 // No output | |
| 158 doNotCompress(false); | |
| 159 } | |
| 160 | |
| 161 if (_compressedOutputStream != null) | |
| 162 _compressedOutputStream.close(); | |
| 163 else | |
| 164 _out.close(); | |
| 165 _closed = true; | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 /** | |
| 170 * Finish. | |
| 171 * | |
| 172 * @throws IOException | |
| 173 * Signals that an I/O exception has occurred. | |
| 174 */ | |
| 175 public void finish() throws IOException | |
| 176 { | |
| 177 if (!_closed) | |
| 178 { | |
| 179 if (_out == null || _bOut != null) | |
| 180 { | |
| 181 long length=_wrapper.getContentLength(); | |
| 182 if (length >= 0 && length < _wrapper.getMinCompressSize()) | |
| 183 doNotCompress(false); | |
| 184 else | |
| 185 doCompress(); | |
| 186 } | |
| 187 | |
| 188 if (_compressedOutputStream != null && !_closed) | |
| 189 { | |
| 190 _closed = true; | |
| 191 _compressedOutputStream.close(); | |
| 192 } | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 /* ------------------------------------------------------------ */ | |
| 197 /** | |
| 198 * @see java.io.OutputStream#write(int) | |
| 199 */ | |
| 200 @Override | |
| 201 public void write(int b) throws IOException | |
| 202 { | |
| 203 checkOut(1); | |
| 204 _out.write(b); | |
| 205 } | |
| 206 | |
| 207 /* ------------------------------------------------------------ */ | |
| 208 /** | |
| 209 * @see java.io.OutputStream#write(byte[]) | |
| 210 */ | |
| 211 @Override | |
| 212 public void write(byte b[]) throws IOException | |
| 213 { | |
| 214 checkOut(b.length); | |
| 215 _out.write(b); | |
| 216 } | |
| 217 | |
| 218 /* ------------------------------------------------------------ */ | |
| 219 /** | |
| 220 * @see java.io.OutputStream#write(byte[], int, int) | |
| 221 */ | |
| 222 @Override | |
| 223 public void write(byte b[], int off, int len) throws IOException | |
| 224 { | |
| 225 checkOut(len); | |
| 226 _out.write(b,off,len); | |
| 227 } | |
| 228 | |
| 229 /** | |
| 230 * Do compress. | |
| 231 * | |
| 232 * @throws IOException Signals that an I/O exception has occurred. | |
| 233 */ | |
| 234 public void doCompress() throws IOException | |
| 235 { | |
| 236 if (_compressedOutputStream==null) | |
| 237 { | |
| 238 if (_response.isCommitted()) | |
| 239 throw new IllegalStateException(); | |
| 240 | |
| 241 if (_encoding!=null) | |
| 242 { | |
| 243 setHeader("Content-Encoding", _encoding); | |
| 244 if (_response.containsHeader("Content-Encoding")) | |
| 245 { | |
| 246 addHeader("Vary",_vary); | |
| 247 _out=_compressedOutputStream=createStream(); | |
| 248 if (_out!=null) | |
| 249 { | |
| 250 if (_bOut!=null) | |
| 251 { | |
| 252 _out.write(_bOut.getBuf(),0,_bOut.getCount()); | |
| 253 _bOut=null; | |
| 254 } | |
| 255 | |
| 256 String etag=_wrapper.getETag(); | |
| 257 if (etag!=null) | |
| 258 setHeader("ETag",etag.substring(0,etag.length()-1)+'-'+_encoding+'"'); | |
| 259 return; | |
| 260 } | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 doNotCompress(true); // Send vary as it could have been compressed if encoding was present | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 /** | |
| 269 * Do not compress. | |
| 270 * | |
| 271 * @throws IOException | |
| 272 * Signals that an I/O exception has occurred. | |
| 273 */ | |
| 274 public void doNotCompress(boolean sendVary) throws IOException | |
| 275 { | |
| 276 if (_compressedOutputStream != null) | |
| 277 throw new IllegalStateException("Compressed output stream is already assigned."); | |
| 278 if (_out == null || _bOut != null) | |
| 279 { | |
| 280 if (sendVary) | |
| 281 addHeader("Vary",_vary); | |
| 282 if (_wrapper.getETag()!=null) | |
| 283 setHeader("ETag",_wrapper.getETag()); | |
| 284 | |
| 285 _doNotCompress = true; | |
| 286 | |
| 287 _out = _response.getOutputStream(); | |
| 288 setContentLength(); | |
| 289 | |
| 290 if (_bOut != null) | |
| 291 _out.write(_bOut.getBuf(),0,_bOut.getCount()); | |
| 292 _bOut = null; | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 /** | |
| 297 * Check out. | |
| 298 * | |
| 299 * @param lengthToWrite | |
| 300 * the length | |
| 301 * @throws IOException | |
| 302 * Signals that an I/O exception has occurred. | |
| 303 */ | |
| 304 private void checkOut(int lengthToWrite) throws IOException | |
| 305 { | |
| 306 if (_closed) | |
| 307 throw new IOException("CLOSED"); | |
| 308 | |
| 309 if (_out == null) | |
| 310 { | |
| 311 // If this first write is larger than buffer size, then we are committing now | |
| 312 if (lengthToWrite>_wrapper.getBufferSize()) | |
| 313 { | |
| 314 // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress | |
| 315 long length=_wrapper.getContentLength(); | |
| 316 if (length>=0 && length<_wrapper.getMinCompressSize()) | |
| 317 doNotCompress(false); // Not compressing by size, so no vary on request headers | |
| 318 else | |
| 319 doCompress(); | |
| 320 } | |
| 321 else | |
| 322 { | |
| 323 // start aggregating writes into a buffered output stream | |
| 324 _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize()); | |
| 325 } | |
| 326 } | |
| 327 // else are we aggregating writes? | |
| 328 else if (_bOut !=null) | |
| 329 { | |
| 330 // We are aggregating into the buffered output stream. | |
| 331 | |
| 332 // If this write fills the buffer, then we are committing | |
| 333 if (lengthToWrite>=(_bOut.getBuf().length - _bOut.getCount())) | |
| 334 { | |
| 335 // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress | |
| 336 long length=_wrapper.getContentLength(); | |
| 337 if (length>=0 && length<_wrapper.getMinCompressSize()) | |
| 338 doNotCompress(false); // Not compressing by size, so no vary on request headers | |
| 339 else | |
| 340 doCompress(); | |
| 341 } | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 /** | |
| 346 * @see org.eclipse.jetty.http.gzip.CompressedStream#getOutputStream() | |
| 347 */ | |
| 348 public OutputStream getOutputStream() | |
| 349 { | |
| 350 return _out; | |
| 351 } | |
| 352 | |
| 353 /** | |
| 354 * @see org.eclipse.jetty.http.gzip.CompressedStream#isClosed() | |
| 355 */ | |
| 356 public boolean isClosed() | |
| 357 { | |
| 358 return _closed; | |
| 359 } | |
| 360 | |
| 361 /** | |
| 362 * Allows derived implementations to replace PrintWriter implementation. | |
| 363 */ | |
| 364 protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException | |
| 365 { | |
| 366 return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); | |
| 367 } | |
| 368 | |
| 369 protected void addHeader(String name,String value) | |
| 370 { | |
| 371 _response.addHeader(name, value); | |
| 372 } | |
| 373 | |
| 374 protected void setHeader(String name,String value) | |
| 375 { | |
| 376 _response.setHeader(name, value); | |
| 377 } | |
| 378 | |
| 379 /** | |
| 380 * Create the stream fitting to the underlying compression type. | |
| 381 * | |
| 382 * @throws IOException | |
| 383 * Signals that an I/O exception has occurred. | |
| 384 */ | |
| 385 protected abstract DeflaterOutputStream createStream() throws IOException; | |
| 386 | |
| 387 | |
| 388 } |
