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 } |