1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
37
38
39
40 public abstract class AbstractCompressedStream extends ServletOutputStream
41 {
42 private final String _encoding;
43 protected HttpServletRequest _request;
44 protected HttpServletResponse _response;
45 protected OutputStream _out;
46 protected ByteArrayOutputStream2 _bOut;
47 protected DeflaterOutputStream _compressedOutputStream;
48 protected boolean _closed;
49 protected int _bufferSize;
50 protected int _minCompressSize;
51 protected long _contentLength;
52 protected boolean _doNotCompress;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public AbstractCompressedStream(String encoding,HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minCompressSize)
71 throws IOException
72 {
73 _encoding=encoding;
74 _request = request;
75 _response = response;
76 _contentLength = contentLength;
77 _bufferSize = bufferSize;
78 _minCompressSize = minCompressSize;
79 if (minCompressSize == 0)
80 doCompress();
81 }
82
83
84
85
86 public void resetBuffer()
87 {
88 if (_response.isCommitted())
89 throw new IllegalStateException("Committed");
90 _closed = false;
91 _out = null;
92 _bOut = null;
93 if (_compressedOutputStream != null)
94 _response.setHeader("Content-Encoding",null);
95 _compressedOutputStream = null;
96 _doNotCompress = false;
97 }
98
99
100
101
102
103
104
105 public void setContentLength(long length)
106 {
107 _contentLength = length;
108 if (_doNotCompress && length >= 0)
109 {
110 if (_contentLength < Integer.MAX_VALUE)
111 _response.setContentLength((int)_contentLength);
112 else
113 _response.setHeader("Content-Length",Long.toString(_contentLength));
114 }
115 }
116
117
118
119
120
121 @Override
122 public void flush() throws IOException
123 {
124 if (_out == null || _bOut != null)
125 {
126 if (_contentLength > 0 && _contentLength < _minCompressSize)
127 doNotCompress();
128 else
129 doCompress();
130 }
131
132 _out.flush();
133 }
134
135
136
137
138
139 @Override
140 public void close() throws IOException
141 {
142 if (_closed)
143 return;
144
145 if (_request.getAttribute("javax.servlet.include.request_uri") != null)
146 flush();
147 else
148 {
149 if (_bOut != null)
150 {
151 if (_contentLength < 0)
152 _contentLength = _bOut.getCount();
153 if (_contentLength < _minCompressSize)
154 doNotCompress();
155 else
156 doCompress();
157 }
158 else if (_out == null)
159 {
160 doNotCompress();
161 }
162
163 if (_compressedOutputStream != null)
164 _compressedOutputStream.close();
165 else
166 _out.close();
167 _closed = true;
168 }
169 }
170
171
172
173
174
175
176
177 public void finish() throws IOException
178 {
179 if (!_closed)
180 {
181 if (_out == null || _bOut != null)
182 {
183 if (_contentLength > 0 && _contentLength < _minCompressSize)
184 doNotCompress();
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 setHeader("Content-Encoding", _encoding);
243 if (_response.containsHeader("Content-Encoding"))
244 {
245 _out=_compressedOutputStream=createStream();
246
247 if (_bOut!=null)
248 {
249 _out.write(_bOut.getBuf(),0,_bOut.getCount());
250 _bOut=null;
251 }
252 }
253 else
254 doNotCompress();
255 }
256 }
257
258
259
260
261
262
263
264 public void doNotCompress() throws IOException
265 {
266 if (_compressedOutputStream != null)
267 throw new IllegalStateException("Compressed output stream is already assigned.");
268 if (_out == null || _bOut != null)
269 {
270 _doNotCompress = true;
271
272 _out = _response.getOutputStream();
273 setContentLength(_contentLength);
274
275 if (_bOut != null)
276 _out.write(_bOut.getBuf(),0,_bOut.getCount());
277 _bOut = null;
278 }
279 }
280
281
282
283
284
285
286
287
288
289 private void checkOut(int length) throws IOException
290 {
291 if (_closed)
292 throw new IOException("CLOSED");
293
294 if (_out == null)
295 {
296 if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
297 doNotCompress();
298 else if (length > _minCompressSize)
299 doCompress();
300 else
301 _out = _bOut = new ByteArrayOutputStream2(_bufferSize);
302 }
303 else if (_bOut != null)
304 {
305 if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
306 doNotCompress();
307 else if (length >= (_bOut.getBuf().length - _bOut.getCount()))
308 doCompress();
309 }
310 }
311
312
313
314
315 public OutputStream getOutputStream()
316 {
317 return _out;
318 }
319
320
321
322
323 public boolean isClosed()
324 {
325 return _closed;
326 }
327
328
329
330
331 protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
332 {
333 return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
334 }
335
336 protected void setHeader(String name,String value)
337 {
338 _response.setHeader(name, value);
339 }
340
341
342
343
344
345
346
347 protected abstract DeflaterOutputStream createStream() throws IOException;
348
349 }