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