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.HashSet;
27 import java.util.Set;
28 import java.util.StringTokenizer;
29 import java.util.zip.DeflaterOutputStream;
30 import java.util.zip.GZIPOutputStream;
31
32 import javax.servlet.AsyncEvent;
33 import javax.servlet.AsyncListener;
34 import javax.servlet.ServletException;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.http.HttpServletResponse;
37
38 import org.eclipse.jetty.http.HttpMethod;
39 import org.eclipse.jetty.server.Request;
40 import org.eclipse.jetty.server.handler.HandlerWrapper;
41 import org.eclipse.jetty.util.log.Log;
42 import org.eclipse.jetty.util.log.Logger;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class GzipHandler extends HandlerWrapper
62 {
63 private static final Logger LOG = Log.getLogger(GzipHandler.class);
64
65 final protected Set<String> _mimeTypes=new HashSet<>();
66 protected boolean _excludeMimeTypes=false;
67 protected Set<String> _excludedUA;
68 protected int _bufferSize = 8192;
69 protected int _minGzipSize = 256;
70 protected String _vary = "Accept-Encoding, User-Agent";
71
72
73
74
75
76 public GzipHandler()
77 {
78 }
79
80
81
82
83
84
85
86 public Set<String> getMimeTypes()
87 {
88 return _mimeTypes;
89 }
90
91
92
93
94
95
96
97
98 public void setMimeTypes(Set<String> mimeTypes)
99 {
100 _excludeMimeTypes=false;
101 _mimeTypes.clear();
102 _mimeTypes.addAll(mimeTypes);
103 }
104
105
106
107
108
109
110
111
112 public void setMimeTypes(String mimeTypes)
113 {
114 if (mimeTypes != null)
115 {
116 _excludeMimeTypes=false;
117 _mimeTypes.clear();
118 StringTokenizer tok = new StringTokenizer(mimeTypes,",",false);
119 while (tok.hasMoreTokens())
120 {
121 _mimeTypes.add(tok.nextToken());
122 }
123 }
124 }
125
126
127
128
129
130 public void setExcludeMimeTypes(boolean exclude)
131 {
132 _excludeMimeTypes=exclude;
133 }
134
135
136
137
138
139
140
141 public Set<String> getExcluded()
142 {
143 return _excludedUA;
144 }
145
146
147
148
149
150
151
152
153 public void setExcluded(Set<String> excluded)
154 {
155 _excludedUA = excluded;
156 }
157
158
159
160
161
162
163
164
165 public void setExcluded(String excluded)
166 {
167 if (excluded != null)
168 {
169 _excludedUA = new HashSet<String>();
170 StringTokenizer tok = new StringTokenizer(excluded,",",false);
171 while (tok.hasMoreTokens())
172 _excludedUA.add(tok.nextToken());
173 }
174 }
175
176
177
178
179
180 public String getVary()
181 {
182 return _vary;
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196 public void setVary(String vary)
197 {
198 _vary = vary;
199 }
200
201
202
203
204
205
206
207 public int getBufferSize()
208 {
209 return _bufferSize;
210 }
211
212
213
214
215
216
217
218
219 public void setBufferSize(int bufferSize)
220 {
221 _bufferSize = bufferSize;
222 }
223
224
225
226
227
228
229
230 public int getMinGzipSize()
231 {
232 return _minGzipSize;
233 }
234
235
236
237
238
239
240
241
242 public void setMinGzipSize(int minGzipSize)
243 {
244 _minGzipSize = minGzipSize;
245 }
246
247
248
249
250
251 @Override
252 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
253 {
254 if (_handler!=null && isStarted())
255 {
256 String ae = request.getHeader("accept-encoding");
257 if (ae != null && ae.indexOf("gzip")>=0 && !response.containsHeader("Content-Encoding")
258 && !HttpMethod.HEAD.is(request.getMethod()))
259 {
260 if (_excludedUA!=null)
261 {
262 String ua = request.getHeader("User-Agent");
263 if (_excludedUA.contains(ua))
264 {
265 _handler.handle(target,baseRequest, request, response);
266 return;
267 }
268 }
269
270 final CompressedResponseWrapper wrappedResponse = newGzipResponseWrapper(request,response);
271
272 boolean exceptional=true;
273 try
274 {
275 _handler.handle(target, baseRequest, request, wrappedResponse);
276 exceptional=false;
277 }
278 finally
279 {
280 if (request.isAsyncStarted())
281 {
282 request.getAsyncContext().addListener(new AsyncListener()
283 {
284
285 @Override
286 public void onTimeout(AsyncEvent event) throws IOException
287 {
288 }
289
290 @Override
291 public void onStartAsync(AsyncEvent event) throws IOException
292 {
293 }
294
295 @Override
296 public void onError(AsyncEvent event) throws IOException
297 {
298 }
299
300 @Override
301 public void onComplete(AsyncEvent event) throws IOException
302 {
303 try
304 {
305 wrappedResponse.finish();
306 }
307 catch(IOException e)
308 {
309 LOG.warn(e);
310 }
311 }
312 });
313 }
314 else if (exceptional && !response.isCommitted())
315 {
316 wrappedResponse.resetBuffer();
317 wrappedResponse.noCompression();
318 }
319 else
320 wrappedResponse.finish();
321 }
322 }
323 else
324 {
325 _handler.handle(target,baseRequest, request, response);
326 }
327 }
328 }
329
330
331
332
333
334
335
336
337 protected CompressedResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
338 {
339 return new CompressedResponseWrapper(request,response)
340 {
341 {
342 super.setMimeTypes(GzipHandler.this._mimeTypes,GzipHandler.this._excludeMimeTypes);
343 super.setBufferSize(GzipHandler.this._bufferSize);
344 super.setMinCompressSize(GzipHandler.this._minGzipSize);
345 }
346
347 @Override
348 protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
349 {
350 return new AbstractCompressedStream("gzip",request,this,_vary)
351 {
352 @Override
353 protected DeflaterOutputStream createStream() throws IOException
354 {
355 return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
356 }
357 };
358 }
359
360 @Override
361 protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
362 {
363 return GzipHandler.this.newWriter(out,encoding);
364 }
365 };
366 }
367
368
369
370
371
372
373
374
375
376 protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
377 {
378 return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
379 }
380 }