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