1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.servlets.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.WriteListener;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.eclipse.jetty.util.ByteArrayOutputStream2;
34
35
36
37
38
39
40
41 public abstract class AbstractCompressedStream extends ServletOutputStream
42 {
43 private final String _encoding;
44 protected final String _vary;
45 protected final CompressedResponseWrapper _wrapper;
46 protected final HttpServletResponse _response;
47 protected OutputStream _out;
48 protected ByteArrayOutputStream2 _bOut;
49 protected DeflaterOutputStream _compressedOutputStream;
50 protected boolean _closed;
51 protected boolean _doNotCompress;
52
53
54
55
56
57 public AbstractCompressedStream(String encoding,HttpServletRequest request, CompressedResponseWrapper wrapper,String vary)
58 throws IOException
59 {
60 _encoding=encoding;
61 _wrapper = wrapper;
62 _response = (HttpServletResponse)wrapper.getResponse();
63 _vary=vary;
64
65 if (_wrapper.getMinCompressSize()==0)
66 doCompress();
67 }
68
69
70
71
72
73 public void resetBuffer()
74 {
75 if (_response.isCommitted() || _compressedOutputStream!=null )
76 throw new IllegalStateException("Committed");
77 _closed = false;
78 _out = null;
79 _bOut = null;
80 _doNotCompress = false;
81 }
82
83
84 public void setBufferSize(int bufferSize)
85 {
86 if (_bOut!=null && _bOut.getBuf().length<bufferSize)
87 {
88 ByteArrayOutputStream2 b = new ByteArrayOutputStream2(bufferSize);
89 b.write(_bOut.getBuf(),0,_bOut.size());
90 _bOut=b;
91 }
92 }
93
94
95 public void setContentLength()
96 {
97 if (_doNotCompress)
98 {
99 long length=_wrapper.getContentLength();
100 if (length>=0)
101 {
102 if (length < Integer.MAX_VALUE)
103 _response.setContentLength((int)length);
104 else
105 _response.setHeader("Content-Length",Long.toString(length));
106 }
107 }
108 }
109
110
111
112
113
114 @Override
115 public void flush() throws IOException
116 {
117 if (_out == null || _bOut != null)
118 {
119 long length=_wrapper.getContentLength();
120 if (length > 0 && length < _wrapper.getMinCompressSize())
121 doNotCompress(false);
122 else
123 doCompress();
124 }
125
126 _out.flush();
127 }
128
129
130
131
132
133 @Override
134 public void close() throws IOException
135 {
136 if (_closed)
137 return;
138
139 if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null)
140 flush();
141 else
142 {
143 if (_bOut != null)
144 {
145 long length=_wrapper.getContentLength();
146 if (length < 0)
147 {
148 length = _bOut.getCount();
149 _wrapper.setContentLength(length);
150 }
151 if (length < _wrapper.getMinCompressSize())
152 doNotCompress(false);
153 else
154 doCompress();
155 }
156 else if (_out == null)
157 {
158
159 doNotCompress(false);
160 }
161
162 if (_compressedOutputStream != null)
163 _compressedOutputStream.close();
164 else
165 _out.close();
166 _closed = true;
167 }
168 }
169
170
171
172
173
174
175
176 public void finish() throws IOException
177 {
178 if (!_closed)
179 {
180 if (_out == null || _bOut != null)
181 {
182 long length=_wrapper.getContentLength();
183 if (length<0 &&_bOut==null || length >= 0 && length < _wrapper.getMinCompressSize())
184 doNotCompress(false);
185 else
186 doCompress();
187 }
188
189 if (_compressedOutputStream != null && !_closed)
190 {
191 _closed = true;
192 _compressedOutputStream.close();
193 }
194 }
195 }
196
197
198
199
200
201 @Override
202 public void write(int b) throws IOException
203 {
204 checkOut(1);
205 _out.write(b);
206 }
207
208
209
210
211
212 @Override
213 public void write(byte b[]) throws IOException
214 {
215 checkOut(b.length);
216 _out.write(b);
217 }
218
219
220
221
222
223 @Override
224 public void write(byte b[], int off, int len) throws IOException
225 {
226 checkOut(len);
227 _out.write(b,off,len);
228 }
229
230
231
232
233
234
235 public void doCompress() throws IOException
236 {
237 if (_compressedOutputStream==null)
238 {
239 if (_response.isCommitted())
240 throw new IllegalStateException();
241
242 if (_encoding!=null)
243 {
244 setHeader("Content-Encoding", _encoding);
245 if (_response.containsHeader("Content-Encoding"))
246 {
247 addHeader("Vary",_vary);
248 _out=_compressedOutputStream=createStream();
249 if (_out!=null)
250 {
251 if (_bOut!=null)
252 {
253 _out.write(_bOut.getBuf(),0,_bOut.getCount());
254 _bOut=null;
255 }
256
257 String etag=_wrapper.getETag();
258 if (etag!=null)
259 setHeader("ETag",etag.substring(0,etag.length()-1)+'-'+_encoding+'"');
260 return;
261 }
262 }
263 }
264
265 doNotCompress(true);
266 }
267 }
268
269
270
271
272
273
274
275 public void doNotCompress(boolean sendVary) throws IOException
276 {
277 if (_compressedOutputStream != null)
278 throw new IllegalStateException("Compressed output stream is already assigned.");
279 if (_out == null || _bOut != null)
280 {
281 if (sendVary)
282 addHeader("Vary",_vary);
283 if (_wrapper.getETag()!=null)
284 setHeader("ETag",_wrapper.getETag());
285
286 _doNotCompress = true;
287
288 _out = _response.getOutputStream();
289 setContentLength();
290
291 if (_bOut != null)
292 _out.write(_bOut.getBuf(),0,_bOut.getCount());
293 _bOut = null;
294 }
295 }
296
297
298
299
300
301
302
303
304
305 private void checkOut(int lengthToWrite) throws IOException
306 {
307 if (_closed)
308 throw new IOException("CLOSED");
309
310 if (_out == null)
311 {
312
313 if (lengthToWrite>_wrapper.getBufferSize())
314 {
315
316 long length=_wrapper.getContentLength();
317 if (length>=0 && length<_wrapper.getMinCompressSize())
318 doNotCompress(false);
319 else
320 doCompress();
321 }
322 else
323 {
324
325 _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize());
326 }
327 }
328
329 else if (_bOut !=null)
330 {
331
332
333
334 if (lengthToWrite>=(_bOut.getBuf().length - _bOut.getCount()))
335 {
336
337 long length=_wrapper.getContentLength();
338 if (length>=0 && length<_wrapper.getMinCompressSize())
339 doNotCompress(false);
340 else
341 doCompress();
342 }
343 }
344 }
345
346 public OutputStream getOutputStream()
347 {
348 return _out;
349 }
350
351 public boolean isClosed()
352 {
353 return _closed;
354 }
355
356
357
358
359 protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
360 {
361 return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
362 }
363
364 protected void addHeader(String name,String value)
365 {
366 _response.addHeader(name, value);
367 }
368
369 protected void setHeader(String name,String value)
370 {
371 _response.setHeader(name, value);
372 }
373
374 @Override
375 public void setWriteListener(WriteListener writeListener)
376 {
377
378
379 }
380
381
382 @Override
383 public boolean isReady()
384 {
385
386 return false;
387 }
388
389
390
391
392
393
394
395 protected abstract DeflaterOutputStream createStream() throws IOException;
396
397
398 }