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