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