1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.server.handler;
20
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.net.MalformedURLException;
24
25 import javax.servlet.RequestDispatcher;
26 import javax.servlet.ServletException;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.eclipse.jetty.http.HttpFields;
31 import org.eclipse.jetty.http.HttpHeader;
32 import org.eclipse.jetty.http.HttpMethod;
33 import org.eclipse.jetty.http.HttpStatus;
34 import org.eclipse.jetty.http.MimeTypes;
35 import org.eclipse.jetty.io.WriterOutputStream;
36 import org.eclipse.jetty.server.Request;
37 import org.eclipse.jetty.server.Response;
38 import org.eclipse.jetty.server.handler.ContextHandler.Context;
39 import org.eclipse.jetty.util.URIUtil;
40 import org.eclipse.jetty.util.log.Log;
41 import org.eclipse.jetty.util.log.Logger;
42 import org.eclipse.jetty.util.resource.Resource;
43
44
45
46
47
48
49
50
51
52
53
54
55 public class ResourceHandler extends HandlerWrapper
56 {
57 private static final Logger LOG = Log.getLogger(ResourceHandler.class);
58
59 ContextHandler _context;
60 Resource _baseResource;
61 Resource _defaultStylesheet;
62 Resource _stylesheet;
63 String[] _welcomeFiles={"index.html"};
64 MimeTypes _mimeTypes = new MimeTypes();
65 String _cacheControl;
66 boolean _directory;
67 boolean _etags;
68
69
70 public ResourceHandler()
71 {
72
73 }
74
75
76 public MimeTypes getMimeTypes()
77 {
78 return _mimeTypes;
79 }
80
81
82 public void setMimeTypes(MimeTypes mimeTypes)
83 {
84 _mimeTypes = mimeTypes;
85 }
86
87
88
89
90
91 public boolean isDirectoriesListed()
92 {
93 return _directory;
94 }
95
96
97
98
99
100 public void setDirectoriesListed(boolean directory)
101 {
102 _directory = directory;
103 }
104
105
106
107
108
109 public boolean isEtags()
110 {
111 return _etags;
112 }
113
114
115
116
117
118 public void setEtags(boolean etags)
119 {
120 _etags = etags;
121 }
122
123
124 @Override
125 public void doStart()
126 throws Exception
127 {
128 Context scontext = ContextHandler.getCurrentContext();
129 _context = (scontext==null?null:scontext.getContextHandler());
130
131 super.doStart();
132 }
133
134
135
136
137
138 public Resource getBaseResource()
139 {
140 if (_baseResource==null)
141 return null;
142 return _baseResource;
143 }
144
145
146
147
148
149 public String getResourceBase()
150 {
151 if (_baseResource==null)
152 return null;
153 return _baseResource.toString();
154 }
155
156
157
158
159
160
161 public void setBaseResource(Resource base)
162 {
163 _baseResource=base;
164 }
165
166
167
168
169
170 public void setResourceBase(String resourceBase)
171 {
172 try
173 {
174 setBaseResource(Resource.newResource(resourceBase));
175 }
176 catch (Exception e)
177 {
178 LOG.warn(e.toString());
179 LOG.debug(e);
180 throw new IllegalArgumentException(resourceBase);
181 }
182 }
183
184
185
186
187
188 public Resource getStylesheet()
189 {
190 if(_stylesheet != null)
191 {
192 return _stylesheet;
193 }
194 else
195 {
196 if(_defaultStylesheet == null)
197 {
198 try
199 {
200 _defaultStylesheet = Resource.newResource(this.getClass().getResource("/jetty-dir.css"));
201 }
202 catch(IOException e)
203 {
204 LOG.warn(e.toString());
205 LOG.debug(e);
206 }
207 }
208 return _defaultStylesheet;
209 }
210 }
211
212
213
214
215
216 public void setStylesheet(String stylesheet)
217 {
218 try
219 {
220 _stylesheet = Resource.newResource(stylesheet);
221 if(!_stylesheet.exists())
222 {
223 LOG.warn("unable to find custom stylesheet: " + stylesheet);
224 _stylesheet = null;
225 }
226 }
227 catch(Exception e)
228 {
229 LOG.warn(e.toString());
230 LOG.debug(e);
231 throw new IllegalArgumentException(stylesheet.toString());
232 }
233 }
234
235
236
237
238
239 public String getCacheControl()
240 {
241 return _cacheControl.toString();
242 }
243
244
245
246
247
248 public void setCacheControl(String cacheControl)
249 {
250 _cacheControl=cacheControl;
251 }
252
253
254
255
256 public Resource getResource(String path) throws MalformedURLException
257 {
258 if (path==null || !path.startsWith("/"))
259 throw new MalformedURLException(path);
260
261 Resource base = _baseResource;
262 if (base==null)
263 {
264 if (_context==null)
265 return null;
266 base=_context.getBaseResource();
267 if (base==null)
268 return null;
269 }
270
271 try
272 {
273 path=URIUtil.canonicalPath(path);
274 return base.addPath(path);
275 }
276 catch(Exception e)
277 {
278 LOG.ignore(e);
279 }
280
281 return null;
282 }
283
284
285 protected Resource getResource(HttpServletRequest request) throws MalformedURLException
286 {
287 String servletPath;
288 String pathInfo;
289 Boolean included = request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null;
290 if (included != null && included.booleanValue())
291 {
292 servletPath = (String)request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
293 pathInfo = (String)request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
294
295 if (servletPath == null && pathInfo == null)
296 {
297 servletPath = request.getServletPath();
298 pathInfo = request.getPathInfo();
299 }
300 }
301 else
302 {
303 servletPath = request.getServletPath();
304 pathInfo = request.getPathInfo();
305 }
306
307 String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
308 return getResource(pathInContext);
309 }
310
311
312
313 public String[] getWelcomeFiles()
314 {
315 return _welcomeFiles;
316 }
317
318
319 public void setWelcomeFiles(String[] welcomeFiles)
320 {
321 _welcomeFiles=welcomeFiles;
322 }
323
324
325 protected Resource getWelcome(Resource directory) throws MalformedURLException, IOException
326 {
327 for (int i=0;i<_welcomeFiles.length;i++)
328 {
329 Resource welcome=directory.addPath(_welcomeFiles[i]);
330 if (welcome.exists() && !welcome.isDirectory())
331 return welcome;
332 }
333
334 return null;
335 }
336
337
338
339
340
341 @Override
342 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
343 {
344 if (baseRequest.isHandled())
345 return;
346
347 boolean skipContentBody = false;
348
349 if(!HttpMethod.GET.is(request.getMethod()))
350 {
351 if(!HttpMethod.HEAD.is(request.getMethod()))
352 {
353
354 super.handle(target, baseRequest, request, response);
355 return;
356 }
357 skipContentBody = true;
358 }
359
360 Resource resource = getResource(request);
361
362 if (resource==null || !resource.exists())
363 {
364 if (target.endsWith("/jetty-dir.css"))
365 {
366 resource = getStylesheet();
367 if (resource==null)
368 return;
369 response.setContentType("text/css");
370 }
371 else
372 {
373
374 super.handle(target, baseRequest, request, response);
375 return;
376 }
377 }
378
379
380 baseRequest.setHandled(true);
381
382 if (resource.isDirectory())
383 {
384 if (!request.getPathInfo().endsWith(URIUtil.SLASH))
385 {
386 response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)));
387 return;
388 }
389
390 Resource welcome=getWelcome(resource);
391 if (welcome!=null && welcome.exists())
392 resource=welcome;
393 else
394 {
395 doDirectory(request,response,resource);
396 baseRequest.setHandled(true);
397 return;
398 }
399 }
400
401
402 long last_modified=resource.lastModified();
403 String etag=null;
404 if (_etags)
405 {
406
407 String ifnm = request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
408 etag=resource.getWeakETag();
409 if (ifnm!=null && resource!=null && ifnm.equals(etag))
410 {
411 response.setStatus(HttpStatus.NOT_MODIFIED_304);
412 baseRequest.getResponse().getHttpFields().put(HttpHeader.ETAG,etag);
413 return;
414 }
415 }
416
417
418 if (last_modified>0)
419 {
420 long if_modified=request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
421 if (if_modified>0 && last_modified/1000<=if_modified/1000)
422 {
423 response.setStatus(HttpStatus.NOT_MODIFIED_304);
424 return;
425 }
426 }
427
428 String mime=_mimeTypes.getMimeByExtension(resource.toString());
429 if (mime==null)
430 mime=_mimeTypes.getMimeByExtension(request.getPathInfo());
431
432
433 doResponseHeaders(response,resource,mime!=null?mime.toString():null);
434 response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),last_modified);
435 if (_etags)
436 baseRequest.getResponse().getHttpFields().put(HttpHeader.ETAG,etag);
437
438 if(skipContentBody)
439 return;
440
441 OutputStream out =null;
442 try {out = response.getOutputStream();}
443 catch(IllegalStateException e) {out = new WriterOutputStream(response.getWriter());}
444
445
446
447
448
449
450
451
452
453 {
454
455 resource.writeTo(out,0,resource.length());
456 }
457 }
458
459
460 protected void doDirectory(HttpServletRequest request,HttpServletResponse response, Resource resource)
461 throws IOException
462 {
463 if (_directory)
464 {
465 String listing = resource.getListHTML(request.getRequestURI(),request.getPathInfo().lastIndexOf("/") > 0);
466 response.setContentType("text/html; charset=UTF-8");
467 response.getWriter().println(listing);
468 }
469 else
470 response.sendError(HttpStatus.FORBIDDEN_403);
471 }
472
473
474
475
476
477
478
479
480
481 protected void doResponseHeaders(HttpServletResponse response, Resource resource, String mimeType)
482 {
483 if (mimeType!=null)
484 response.setContentType(mimeType);
485
486 long length=resource.length();
487
488 if (response instanceof Response)
489 {
490 HttpFields fields = ((Response)response).getHttpFields();
491
492 if (length>0)
493 fields.putLongField(HttpHeader.CONTENT_LENGTH,length);
494
495 if (_cacheControl!=null)
496 fields.put(HttpHeader.CACHE_CONTROL,_cacheControl);
497 }
498 else
499 {
500 if (length>0)
501 response.setHeader(HttpHeader.CONTENT_LENGTH.asString(),Long.toString(length));
502
503 if (_cacheControl!=null)
504 response.setHeader(HttpHeader.CACHE_CONTROL.asString(),_cacheControl.toString());
505 }
506
507 }
508 }