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.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 DeflaterOutputStream _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 public void resetBuffer()
72 {
73 if (_response.isCommitted())
74 throw new IllegalStateException("Committed");
75 _closed = false;
76 _out = null;
77 _bOut = null;
78 if (_compressedOutputStream != null)
79 _response.setHeader("Content-Encoding",null);
80 _compressedOutputStream = null;
81 _doNotCompress = false;
82 }
83
84
85 public void setContentLength()
86 {
87 if (_doNotCompress)
88 {
89 long length=_wrapper.getContentLength();
90 if (length>=0)
91 {
92 if (length < Integer.MAX_VALUE)
93 _response.setContentLength((int)length);
94 else
95 _response.setHeader("Content-Length",Long.toString(length));
96 }
97 }
98 }
99
100
101
102
103
104 @Override
105 public void flush() throws IOException
106 {
107 if (_out == null || _bOut != null)
108 {
109 long length=_wrapper.getContentLength();
110 if (length > 0 && length < _wrapper.getMinCompressSize())
111 doNotCompress(false);
112 else
113 doCompress();
114 }
115
116 _out.flush();
117 }
118
119
120
121
122
123 @Override
124 public void close() throws IOException
125 {
126 if (_closed)
127 return;
128
129 if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null)
130 flush();
131 else
132 {
133 if (_bOut != null)
134 {
135 long length=_wrapper.getContentLength();
136 if (length < 0)
137 {
138 length = _bOut.getCount();
139 _wrapper.setContentLength(length);
140 }
141 if (length < _wrapper.getMinCompressSize())
142 doNotCompress(false);
143 else
144 doCompress();
145 }
146 else if (_out == null)
147 {
148
149 doNotCompress(false);
150 }
151
152 if (_compressedOutputStream != null)
153 _compressedOutputStream.close();
154 else
155 _out.close();
156 _closed = true;
157 }
158 }
159
160
161
162
163
164
165
166 public void finish() throws IOException
167 {
168 if (!_closed)
169 {
170 if (_out == null || _bOut != null)
171 {
172 long length=_wrapper.getContentLength();
173 if (length > 0 && length < _wrapper.getMinCompressSize())
174 doNotCompress(false);
175 else
176 doCompress();
177 }
178
179 if (_compressedOutputStream != null && !_closed)
180 {
181 _closed = true;
182 _compressedOutputStream.close();
183 }
184 }
185 }
186
187
188
189
190
191 @Override
192 public void write(int b) throws IOException
193 {
194 checkOut(1);
195 _out.write(b);
196 }
197
198
199
200
201
202 @Override
203 public void write(byte b[]) throws IOException
204 {
205 checkOut(b.length);
206 _out.write(b);
207 }
208
209
210
211
212
213 @Override
214 public void write(byte b[], int off, int len) throws IOException
215 {
216 checkOut(len);
217 _out.write(b,off,len);
218 }
219
220
221
222
223
224
225 public void doCompress() throws IOException
226 {
227 if (_compressedOutputStream==null)
228 {
229 if (_response.isCommitted())
230 throw new IllegalStateException();
231
232 if (_encoding!=null)
233 {
234 setHeader("Content-Encoding", _encoding);
235 if (_response.containsHeader("Content-Encoding"))
236 {
237 setHeader("Vary",_vary);
238 _out=_compressedOutputStream=createStream();
239 if (_out!=null)
240 {
241 if (_bOut!=null)
242 {
243 _out.write(_bOut.getBuf(),0,_bOut.getCount());
244 _bOut=null;
245 }
246
247 String etag=_wrapper.getETag();
248 if (etag!=null)
249 setHeader("ETag",etag.substring(0,etag.length()-1)+'-'+_encoding+'"');
250 return;
251 }
252 }
253 }
254
255 doNotCompress(true);
256 }
257 }
258
259
260
261
262
263
264
265 public void doNotCompress(boolean sendVary) throws IOException
266 {
267 if (_compressedOutputStream != null)
268 throw new IllegalStateException("Compressed output stream is already assigned.");
269 if (_out == null || _bOut != null)
270 {
271 if (sendVary)
272 setHeader("Vary",_vary);
273 if (_wrapper.getETag()!=null)
274 setHeader("ETag",_wrapper.getETag());
275
276 _doNotCompress = true;
277
278 _out = _response.getOutputStream();
279 setContentLength();
280
281 if (_bOut != null)
282 _out.write(_bOut.getBuf(),0,_bOut.getCount());
283 _bOut = null;
284 }
285 }
286
287
288
289
290
291
292
293
294
295 private void checkOut(int lengthToWrite) throws IOException
296 {
297 if (_closed)
298 throw new IOException("CLOSED");
299
300 if (_out == null)
301 {
302 long length=_wrapper.getContentLength();
303 if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
304 doNotCompress(false);
305 else if (lengthToWrite > _wrapper.getMinCompressSize())
306 doCompress();
307 else
308 _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize());
309 }
310 else if (_bOut != null)
311 {
312 long length=_wrapper.getContentLength();
313 if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
314 doNotCompress(false);
315 else if (lengthToWrite >= (_bOut.getBuf().length - _bOut.getCount()))
316 doCompress();
317 }
318 }
319
320
321
322
323 public OutputStream getOutputStream()
324 {
325 return _out;
326 }
327
328
329
330
331 public boolean isClosed()
332 {
333 return _closed;
334 }
335
336
337
338
339 protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
340 {
341 return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
342 }
343
344 protected void setHeader(String name,String value)
345 {
346 _response.setHeader(name, value);
347 }
348
349
350
351
352
353
354
355 protected abstract DeflaterOutputStream createStream() throws IOException;
356
357 }