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
239 if (_response.containsHeader("Content-Encoding"))
240 {
241 _out=_compressedOutputStream=createStream();
242
243 if (_bOut!=null)
244 {
245 _out.write(_bOut.getBuf(),0,_bOut.getCount());
246 _bOut=null;
247 }
248 }
249 else
250 doNotCompress();
251 }
252 }
253
254
255
256
257
258
259
260 public void doNotCompress() throws IOException
261 {
262 if (_compressedOutputStream != null)
263 throw new IllegalStateException("Compressed output stream is already assigned.");
264 if (_out == null || _bOut != null)
265 {
266 _doNotCompress = true;
267
268 _out = _response.getOutputStream();
269 setContentLength(_contentLength);
270
271 if (_bOut != null)
272 _out.write(_bOut.getBuf(),0,_bOut.getCount());
273 _bOut = null;
274 }
275 }
276
277
278
279
280
281
282
283
284
285 private void checkOut(int length) throws IOException
286 {
287 if (_closed)
288 throw new IOException("CLOSED");
289
290 if (_out == null)
291 {
292 if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
293 doNotCompress();
294 else if (length > _minCompressSize)
295 doCompress();
296 else
297 _out = _bOut = new ByteArrayOutputStream2(_bufferSize);
298 }
299 else if (_bOut != null)
300 {
301 if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
302 doNotCompress();
303 else if (length >= (_bOut.getBuf().length - _bOut.getCount()))
304 doCompress();
305 }
306 }
307
308
309
310
311 public OutputStream getOutputStream()
312 {
313 return _out;
314 }
315
316
317
318
319 public boolean isClosed()
320 {
321 return _closed;
322 }
323
324
325
326
327 protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
328 {
329 return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
330 }
331
332 protected void setHeader(String name,String value)
333 {
334 _response.setHeader(name, value);
335 }
336
337
338
339
340
341
342
343 protected abstract DeflaterOutputStream createStream() throws IOException;
344
345 }