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
27 import javax.servlet.ServletOutputStream;
28 import javax.servlet.WriteListener;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.eclipse.jetty.util.ByteArrayOutputStream2;
33
34
35
36
37
38
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 OutputStream _compressedOutputStream;
49 protected boolean _closed;
50 protected boolean _doNotCompress;
51
52
53
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
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
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
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
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
171
172
173
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 &&_bOut==null || 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
199
200 @Override
201 public void write(int b) throws IOException
202 {
203 checkOut(1);
204 _out.write(b);
205 }
206
207
208
209
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
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
231
232
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 {
259 int end = etag.length()-1;
260 if (etag.charAt(end)=='"')
261 setHeader("ETag",etag.substring(0,end)+"--"+_encoding+'"');
262 else
263 setHeader("ETag",etag+"--"+_encoding);
264 }
265 return;
266 }
267 }
268 }
269
270 doNotCompress(true);
271 }
272 }
273
274
275
276
277
278
279
280 public void doNotCompress(boolean sendVary) throws IOException
281 {
282 if (_compressedOutputStream != null)
283 throw new IllegalStateException("Compressed output stream is already assigned.");
284 if (_out == null || _bOut != null)
285 {
286 if (sendVary)
287 addHeader("Vary",_vary);
288 if (_wrapper.getETag()!=null)
289 setHeader("ETag",_wrapper.getETag());
290
291 _doNotCompress = true;
292
293 _out = _response.getOutputStream();
294 setContentLength();
295
296 if (_bOut != null)
297 _out.write(_bOut.getBuf(),0,_bOut.getCount());
298 _bOut = null;
299 }
300 }
301
302
303
304
305
306
307
308
309
310 private void checkOut(int lengthToWrite) throws IOException
311 {
312 if (_closed)
313 throw new IOException("CLOSED");
314
315 if (_out == null)
316 {
317
318 if (lengthToWrite>_wrapper.getBufferSize())
319 {
320
321 long length=_wrapper.getContentLength();
322 if (length>=0 && length<_wrapper.getMinCompressSize())
323 doNotCompress(false);
324 else
325 doCompress();
326 }
327 else
328 {
329
330 _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize());
331 }
332 }
333
334 else if (_bOut !=null)
335 {
336
337
338
339 if (lengthToWrite>=(_bOut.getBuf().length - _bOut.getCount()))
340 {
341
342 long length=_wrapper.getContentLength();
343 if (length>=0 && length<_wrapper.getMinCompressSize())
344 doNotCompress(false);
345 else
346 doCompress();
347 }
348 }
349 }
350
351 public OutputStream getOutputStream()
352 {
353 return _out;
354 }
355
356 public boolean isClosed()
357 {
358 return _closed;
359 }
360
361
362
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 @Override
380 public void setWriteListener(WriteListener writeListener)
381 {
382 throw new UnsupportedOperationException("Use AsyncGzipFilter");
383 }
384
385
386 @Override
387 public boolean isReady()
388 {
389 throw new UnsupportedOperationException("Use AsyncGzipFilter");
390 }
391
392
393
394
395
396
397
398 protected abstract OutputStream createStream() throws IOException;
399
400
401 }