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 }