1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.servlet;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.lang.reflect.Method;
20 import java.net.MalformedURLException;
21 import java.net.URL;
22 import java.util.Enumeration;
23 import java.util.List;
24 import java.util.Map;
25 import javax.servlet.RequestDispatcher;
26 import javax.servlet.ServletContext;
27 import javax.servlet.ServletException;
28 import javax.servlet.UnavailableException;
29 import javax.servlet.http.HttpServlet;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32
33 import org.eclipse.jetty.http.HttpContent;
34 import org.eclipse.jetty.http.HttpFields;
35 import org.eclipse.jetty.http.HttpHeaderValues;
36 import org.eclipse.jetty.http.HttpHeaders;
37 import org.eclipse.jetty.http.HttpMethods;
38 import org.eclipse.jetty.http.MimeTypes;
39 import org.eclipse.jetty.io.Buffer;
40 import org.eclipse.jetty.io.ByteArrayBuffer;
41 import org.eclipse.jetty.io.WriterOutputStream;
42 import org.eclipse.jetty.server.Connector;
43 import org.eclipse.jetty.server.Dispatcher;
44 import org.eclipse.jetty.server.HttpConnection;
45 import org.eclipse.jetty.server.InclusiveByteRange;
46 import org.eclipse.jetty.server.ResourceCache;
47 import org.eclipse.jetty.server.Response;
48 import org.eclipse.jetty.server.handler.ContextHandler;
49 import org.eclipse.jetty.server.nio.NIOConnector;
50 import org.eclipse.jetty.server.ssl.SslConnector;
51 import org.eclipse.jetty.util.IO;
52 import org.eclipse.jetty.util.MultiPartOutputStream;
53 import org.eclipse.jetty.util.URIUtil;
54 import org.eclipse.jetty.util.log.Log;
55 import org.eclipse.jetty.util.resource.FileResource;
56 import org.eclipse.jetty.util.resource.Resource;
57 import org.eclipse.jetty.util.resource.ResourceCollection;
58 import org.eclipse.jetty.util.resource.ResourceFactory;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 public class DefaultServlet extends HttpServlet implements ResourceFactory
127 {
128 private ServletContext _servletContext;
129 private ContextHandler _contextHandler;
130
131 private boolean _acceptRanges=true;
132 private boolean _dirAllowed=true;
133 private boolean _welcomeServlets=true;
134 private boolean _welcomeExactServlets=false;
135 private boolean _redirectWelcome=false;
136 private boolean _gzip=true;
137
138 private Resource _resourceBase;
139 private NIOResourceCache _nioCache;
140 private ResourceCache _bioCache;
141
142 private MimeTypes _mimeTypes;
143 private String[] _welcomes;
144 private boolean _useFileMappedBuffer=false;
145 private ByteArrayBuffer _cacheControl;
146 private String _relativeResourceBase;
147 private ServletHandler _servletHandler;
148 private ServletHolder _defaultHolder;
149
150
151
152 @Override
153 public void init()
154 throws UnavailableException
155 {
156 _servletContext=getServletContext();
157 ContextHandler.Context scontext=ContextHandler.getCurrentContext();
158 if (scontext==null)
159 _contextHandler=((ContextHandler.Context)_servletContext).getContextHandler();
160 else
161 _contextHandler = ContextHandler.getCurrentContext().getContextHandler();
162
163 _mimeTypes = _contextHandler.getMimeTypes();
164
165 _welcomes = _contextHandler.getWelcomeFiles();
166 if (_welcomes==null)
167 _welcomes=new String[] {"index.html","index.jsp"};
168
169 _acceptRanges=getInitBoolean("acceptRanges",_acceptRanges);
170 _dirAllowed=getInitBoolean("dirAllowed",_dirAllowed);
171 _redirectWelcome=getInitBoolean("redirectWelcome",_redirectWelcome);
172 _gzip=getInitBoolean("gzip",_gzip);
173
174 if ("exact".equals(getInitParameter("welcomeServlets")))
175 {
176 _welcomeExactServlets=true;
177 _welcomeServlets=false;
178 }
179 else
180 _welcomeServlets=getInitBoolean("welcomeServlets", _welcomeServlets);
181
182 if (getInitParameter("aliases")!=null)
183 _contextHandler.setAliases(getInitBoolean("aliases",false));
184
185 boolean aliases=_contextHandler.isAliases();
186 if (!aliases && !FileResource.getCheckAliases())
187 throw new IllegalStateException("Alias checking disabled");
188 if (aliases)
189 _servletContext.log("Aliases are enabled");
190
191 _useFileMappedBuffer=getInitBoolean("useFileMappedBuffer",_useFileMappedBuffer);
192
193 _relativeResourceBase = getInitParameter("relativeResourceBase");
194
195 String rb=getInitParameter("resourceBase");
196 if (rb!=null)
197 {
198 if (_relativeResourceBase!=null)
199 throw new UnavailableException("resourceBase & relativeResourceBase");
200 try{_resourceBase=_contextHandler.newResource(rb);}
201 catch (Exception e)
202 {
203 Log.warn(Log.EXCEPTION,e);
204 throw new UnavailableException(e.toString());
205 }
206 }
207
208 String t=getInitParameter("cacheControl");
209 if (t!=null)
210 _cacheControl=new ByteArrayBuffer(t);
211
212 try
213 {
214 String cache_type =getInitParameter("cacheType");
215 int max_cache_size=getInitInt("maxCacheSize", -2);
216 int max_cached_file_size=getInitInt("maxCachedFileSize", -2);
217 int max_cached_files=getInitInt("maxCachedFiles", -2);
218
219 if (cache_type==null || "nio".equals(cache_type)|| "both".equals(cache_type))
220 {
221 if (max_cache_size==-2 || max_cache_size>0)
222 {
223 _nioCache=new NIOResourceCache(_mimeTypes);
224 _nioCache.setUseFileMappedBuffer(_useFileMappedBuffer);
225 if (max_cache_size>0)
226 _nioCache.setMaxCacheSize(max_cache_size);
227 if (max_cached_file_size>=-1)
228 _nioCache.setMaxCachedFileSize(max_cached_file_size);
229 if (max_cached_files>=-1)
230 _nioCache.setMaxCachedFiles(max_cached_files);
231 _nioCache.start();
232 }
233 }
234 if ("bio".equals(cache_type)|| "both".equals(cache_type))
235 {
236 if (max_cache_size==-2 || max_cache_size>0)
237 {
238 _bioCache=new ResourceCache(_mimeTypes);
239 if (max_cache_size>0)
240 _bioCache.setMaxCacheSize(max_cache_size);
241 if (max_cached_file_size>=-1)
242 _bioCache.setMaxCachedFileSize(max_cached_file_size);
243 if (max_cached_files>=-1)
244 _bioCache.setMaxCachedFiles(max_cached_files);
245 _bioCache.start();
246 }
247 }
248 if (_nioCache==null)
249 _bioCache=null;
250
251 }
252 catch (Exception e)
253 {
254 Log.warn(Log.EXCEPTION,e);
255 throw new UnavailableException(e.toString());
256 }
257
258 _servletHandler= (ServletHandler) _contextHandler.getChildHandlerByClass(ServletHandler.class);
259 for (ServletHolder h :_servletHandler.getServlets())
260 if (h.getServletInstance()==this)
261 _defaultHolder=h;
262
263 if (Log.isDebugEnabled()) Log.debug("resource base = "+_resourceBase);
264 }
265
266
267 @Override
268 public String getInitParameter(String name)
269 {
270 String value=getServletContext().getInitParameter("org.eclipse.jetty.servlet.Default."+name);
271 if (value==null)
272 value=super.getInitParameter(name);
273 return value;
274 }
275
276
277 private boolean getInitBoolean(String name, boolean dft)
278 {
279 String value=getInitParameter(name);
280 if (value==null || value.length()==0)
281 return dft;
282 return (value.startsWith("t")||
283 value.startsWith("T")||
284 value.startsWith("y")||
285 value.startsWith("Y")||
286 value.startsWith("1"));
287 }
288
289
290 private int getInitInt(String name, int dft)
291 {
292 String value=getInitParameter(name);
293 if (value==null)
294 value=getInitParameter(name);
295 if (value!=null && value.length()>0)
296 return Integer.parseInt(value);
297 return dft;
298 }
299
300
301
302
303
304
305
306
307
308 public Resource getResource(String pathInContext)
309 {
310 Resource r=null;
311 if (_relativeResourceBase!=null)
312 pathInContext=URIUtil.addPaths(_relativeResourceBase,pathInContext);
313
314 try
315 {
316 if (_resourceBase!=null)
317 r = _resourceBase.addPath(pathInContext);
318 else
319 {
320 URL u = _servletContext.getResource(pathInContext);
321 r = _contextHandler.newResource(u);
322 }
323
324 if (Log.isDebugEnabled())
325 Log.debug("RESOURCE "+pathInContext+"="+r);
326 }
327 catch (IOException e)
328 {
329 Log.ignore(e);
330 }
331 return r;
332 }
333
334
335 @Override
336 protected void doGet(HttpServletRequest request, HttpServletResponse response)
337 throws ServletException, IOException
338 {
339 String servletPath=null;
340 String pathInfo=null;
341 Enumeration reqRanges = null;
342 Boolean included =request.getAttribute(Dispatcher.INCLUDE_REQUEST_URI)!=null;
343 if (included!=null && included.booleanValue())
344 {
345 servletPath=(String)request.getAttribute(Dispatcher.INCLUDE_SERVLET_PATH);
346 pathInfo=(String)request.getAttribute(Dispatcher.INCLUDE_PATH_INFO);
347 if (servletPath==null)
348 {
349 servletPath=request.getServletPath();
350 pathInfo=request.getPathInfo();
351 }
352 }
353 else
354 {
355 included = Boolean.FALSE;
356 servletPath = request.getServletPath();
357 pathInfo = request.getPathInfo();
358
359
360 reqRanges = request.getHeaders(HttpHeaders.RANGE);
361 if (!hasDefinedRange(reqRanges))
362 reqRanges = null;
363 }
364
365 String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
366 boolean endsWithSlash=pathInContext.endsWith(URIUtil.SLASH);
367
368
369 String pathInContextGz=null;
370 boolean gzip=false;
371 if (!included.booleanValue() && _gzip && reqRanges==null && !endsWithSlash )
372 {
373 String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING);
374 if (accept!=null && accept.indexOf("gzip")>=0)
375 gzip=true;
376 }
377
378
379 Resource resource=null;
380 HttpContent content=null;
381
382 Connector connector = HttpConnection.getCurrentConnection().getConnector();
383 ResourceCache cache=(connector instanceof NIOConnector && !(connector instanceof SslConnector)) ?_nioCache:_bioCache;
384 try
385 {
386
387 if (gzip)
388 {
389 pathInContextGz=pathInContext+".gz";
390
391 if (cache==null)
392 {
393 resource=getResource(pathInContextGz);
394 }
395 else
396 {
397 content=cache.lookup(pathInContextGz,this);
398
399 if (content!=null)
400 resource=content.getResource();
401 else
402 resource=getResource(pathInContextGz);
403 }
404
405 if (resource==null || !resource.exists()|| resource.isDirectory())
406 {
407 if (cache!=null && content==null)
408 {
409 String real_path=_servletContext.getRealPath(pathInContextGz);
410 if (real_path!=null)
411 cache.miss(pathInContextGz,_contextHandler.newResource(real_path));
412 }
413 gzip=false;
414 pathInContextGz=null;
415 }
416 }
417
418
419 if (!gzip)
420 {
421 if (cache==null)
422 resource=getResource(pathInContext);
423 else
424 {
425 content=cache.lookup(pathInContext,this);
426
427 if (content!=null)
428 resource=content.getResource();
429 else
430 resource=getResource(pathInContext);
431 }
432 }
433
434 if (Log.isDebugEnabled())
435 Log.debug("resource="+resource+(content!=null?" content":""));
436
437
438 if (resource==null || !resource.exists())
439 response.sendError(HttpServletResponse.SC_NOT_FOUND);
440 else if (!resource.isDirectory())
441 {
442 if (endsWithSlash && _contextHandler.isAliases() && pathInContext.length()>1)
443 {
444 String q=request.getQueryString();
445 pathInContext=pathInContext.substring(0,pathInContext.length()-1);
446 if (q!=null&&q.length()!=0)
447 pathInContext+="?"+q;
448 response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(_servletContext.getContextPath(),pathInContext)));
449 }
450 else
451 {
452
453 if (content==null)
454 content=new UnCachedContent(resource);
455
456 if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
457 {
458 if (gzip)
459 {
460 response.setHeader(HttpHeaders.CONTENT_ENCODING,"gzip");
461 String mt=_servletContext.getMimeType(pathInContext);
462 if (mt!=null)
463 response.setContentType(mt);
464 }
465 sendData(request,response,included.booleanValue(),resource,content,reqRanges);
466 }
467 }
468 }
469 else
470 {
471 String welcome=null;
472
473 if (!endsWithSlash || (pathInContext.length()==1 && request.getAttribute("org.eclipse.jetty.server.nullPathInfo")!=null))
474 {
475 StringBuffer buf=request.getRequestURL();
476 synchronized(buf)
477 {
478 int param=buf.lastIndexOf(";");
479 if (param<0)
480 buf.append('/');
481 else
482 buf.insert(param,'/');
483 String q=request.getQueryString();
484 if (q!=null&&q.length()!=0)
485 {
486 buf.append('?');
487 buf.append(q);
488 }
489 response.setContentLength(0);
490 response.sendRedirect(response.encodeRedirectURL(buf.toString()));
491 }
492 }
493
494 else if (null!=(welcome=getWelcomeFile(pathInContext)))
495 {
496 if (_redirectWelcome)
497 {
498
499 response.setContentLength(0);
500 String q=request.getQueryString();
501 if (q!=null&&q.length()!=0)
502 response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths( _servletContext.getContextPath(),welcome)+"?"+q));
503 else
504 response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths( _servletContext.getContextPath(),welcome)));
505 }
506 else
507 {
508
509 RequestDispatcher dispatcher=request.getRequestDispatcher(welcome);
510 if (dispatcher!=null)
511 {
512 if (included.booleanValue())
513 dispatcher.include(request,response);
514 else
515 {
516 request.setAttribute("org.eclipse.jetty.server.welcome",welcome);
517 dispatcher.forward(request,response);
518 }
519 }
520 }
521 }
522 else
523 {
524 content=new UnCachedContent(resource);
525 if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
526 sendDirectory(request,response,resource,pathInContext);
527 }
528 }
529 }
530 catch(IllegalArgumentException e)
531 {
532 Log.warn(Log.EXCEPTION,e);
533 if(!response.isCommitted())
534 response.sendError(500, e.getMessage());
535 }
536 finally
537 {
538 if (content!=null)
539 content.release();
540 else if (resource!=null)
541 resource.release();
542 }
543
544 }
545
546
547 private boolean hasDefinedRange(Enumeration reqRanges)
548 {
549 return (reqRanges!=null && reqRanges.hasMoreElements());
550 }
551
552
553 @Override
554 protected void doPost(HttpServletRequest request, HttpServletResponse response)
555 throws ServletException, IOException
556 {
557 doGet(request,response);
558 }
559
560
561
562
563
564 @Override
565 protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
566 {
567 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
568 }
569
570
571 @Override
572 protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
573 throws ServletException, IOException
574 {
575 resp.setHeader("Allow", "GET,HEAD,POST,OPTIONS");
576 }
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591 private String getWelcomeFile(String pathInContext) throws MalformedURLException, IOException
592 {
593 if (_welcomes==null)
594 return null;
595
596 String welcome_servlet=null;
597 for (int i=0;i<_welcomes.length;i++)
598 {
599 String welcome_in_context=URIUtil.addPaths(pathInContext,_welcomes[i]);
600 Resource welcome=getResource(welcome_in_context);
601 if (welcome!=null && welcome.exists())
602 return _welcomes[i];
603
604 if ((_welcomeServlets || _welcomeExactServlets) && welcome_servlet==null)
605 {
606 Map.Entry entry=_servletHandler.getHolderEntry(welcome_in_context);
607 if (entry!=null && entry.getValue()!=_defaultHolder &&
608 (_welcomeServlets || (_welcomeExactServlets && entry.getKey().equals(welcome_in_context))))
609 welcome_servlet=welcome_in_context;
610
611 }
612 }
613 return welcome_servlet;
614 }
615
616
617
618
619 protected boolean passConditionalHeaders(HttpServletRequest request,HttpServletResponse response, Resource resource, HttpContent content)
620 throws IOException
621 {
622 try
623 {
624 if (!request.getMethod().equals(HttpMethods.HEAD) )
625 {
626 String ifms=request.getHeader(HttpHeaders.IF_MODIFIED_SINCE);
627 if (ifms!=null)
628 {
629 if (content!=null)
630 {
631 Buffer mdlm=content.getLastModified();
632 if (mdlm!=null)
633 {
634 if (ifms.equals(mdlm.toString()))
635 {
636 response.reset();
637 response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
638 response.flushBuffer();
639 return false;
640 }
641 }
642 }
643
644 long ifmsl=request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
645 if (ifmsl!=-1)
646 {
647 if (resource.lastModified()/1000 <= ifmsl/1000)
648 {
649 response.reset();
650 response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
651 response.flushBuffer();
652 return false;
653 }
654 }
655 }
656
657
658 long date=request.getDateHeader(HttpHeaders.IF_UNMODIFIED_SINCE);
659
660 if (date!=-1)
661 {
662 if (resource.lastModified()/1000 > date/1000)
663 {
664 response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
665 return false;
666 }
667 }
668
669 }
670 }
671 catch(IllegalArgumentException iae)
672 {
673 if(!response.isCommitted())
674 response.sendError(400, iae.getMessage());
675 throw iae;
676 }
677 return true;
678 }
679
680
681
682 protected void sendDirectory(HttpServletRequest request,
683 HttpServletResponse response,
684 Resource resource,
685 String pathInContext)
686 throws IOException
687 {
688 if (!_dirAllowed)
689 {
690 response.sendError(HttpServletResponse.SC_FORBIDDEN);
691 return;
692 }
693
694 byte[] data=null;
695 String base = URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH);
696
697
698 if (_resourceBase instanceof ResourceCollection)
699 resource=_resourceBase.addPath(pathInContext);
700 else if (_contextHandler.getBaseResource() instanceof ResourceCollection)
701 resource=_contextHandler.getBaseResource().addPath(pathInContext);
702
703 String dir = resource.getListHTML(base,pathInContext.length()>1);
704 if (dir==null)
705 {
706 response.sendError(HttpServletResponse.SC_FORBIDDEN,
707 "No directory");
708 return;
709 }
710
711 data=dir.getBytes("UTF-8");
712 response.setContentType("text/html; charset=UTF-8");
713 response.setContentLength(data.length);
714 response.getOutputStream().write(data);
715 }
716
717
718 protected void sendData(HttpServletRequest request,
719 HttpServletResponse response,
720 boolean include,
721 Resource resource,
722 HttpContent content,
723 Enumeration reqRanges)
724 throws IOException
725 {
726 long content_length=content==null?resource.length():content.getContentLength();
727
728
729 OutputStream out =null;
730 try{out = response.getOutputStream();}
731 catch(IllegalStateException e) {out = new WriterOutputStream(response.getWriter());}
732
733 if ( reqRanges == null || !reqRanges.hasMoreElements() || content_length<0)
734 {
735
736 if (include)
737 {
738 resource.writeTo(out,0,content_length);
739 }
740 else
741 {
742
743 if (out instanceof HttpConnection.Output)
744 {
745 if (response instanceof Response)
746 {
747 writeOptionHeaders(((Response)response).getHttpFields());
748 ((HttpConnection.Output)out).sendContent(content);
749 }
750 else if (content.getBuffer()!=null)
751 {
752 writeHeaders(response,content,content_length);
753 ((HttpConnection.Output)out).sendContent(content.getBuffer());
754 }
755 else
756 {
757 writeHeaders(response,content,content_length);
758 resource.writeTo(out,0,content_length);
759 }
760 }
761 else
762 {
763
764 writeHeaders(response,content,content_length);
765 resource.writeTo(out,0,content_length);
766 }
767 }
768 }
769 else
770 {
771
772 List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,content_length);
773
774
775 if (ranges==null || ranges.size()==0)
776 {
777 writeHeaders(response, content, content_length);
778 response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
779 response.setHeader(HttpHeaders.CONTENT_RANGE,
780 InclusiveByteRange.to416HeaderRangeString(content_length));
781 resource.writeTo(out,0,content_length);
782 return;
783 }
784
785
786
787 if ( ranges.size()== 1)
788 {
789 InclusiveByteRange singleSatisfiableRange =
790 (InclusiveByteRange)ranges.get(0);
791 long singleLength = singleSatisfiableRange.getSize(content_length);
792 writeHeaders(response,content,singleLength );
793 response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
794 response.setHeader(HttpHeaders.CONTENT_RANGE,
795 singleSatisfiableRange.toHeaderRangeString(content_length));
796 resource.writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength);
797 return;
798 }
799
800
801
802
803
804 writeHeaders(response,content,-1);
805 String mimetype=content.getContentType().toString();
806 MultiPartOutputStream multi = new MultiPartOutputStream(out);
807 response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
808
809
810
811
812 String ctp;
813 if (request.getHeader(HttpHeaders.REQUEST_RANGE)!=null)
814 ctp = "multipart/x-byteranges; boundary=";
815 else
816 ctp = "multipart/byteranges; boundary=";
817 response.setContentType(ctp+multi.getBoundary());
818
819 InputStream in=resource.getInputStream();
820 long pos=0;
821
822
823 int length=0;
824 String[] header = new String[ranges.size()];
825 for (int i=0;i<ranges.size();i++)
826 {
827 InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
828 header[i]=ibr.toHeaderRangeString(content_length);
829 length+=
830 ((i>0)?2:0)+
831 2+multi.getBoundary().length()+2+
832 HttpHeaders.CONTENT_TYPE.length()+2+mimetype.length()+2+
833 HttpHeaders.CONTENT_RANGE.length()+2+header[i].length()+2+
834 2+
835 (ibr.getLast(content_length)-ibr.getFirst(content_length))+1;
836 }
837 length+=2+2+multi.getBoundary().length()+2+2;
838 response.setContentLength(length);
839
840 for (int i=0;i<ranges.size();i++)
841 {
842 InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
843 multi.startPart(mimetype,new String[]{HttpHeaders.CONTENT_RANGE+": "+header[i]});
844
845 long start=ibr.getFirst(content_length);
846 long size=ibr.getSize(content_length);
847 if (in!=null)
848 {
849
850 if (start<pos)
851 {
852 in.close();
853 in=resource.getInputStream();
854 pos=0;
855 }
856 if (pos<start)
857 {
858 in.skip(start-pos);
859 pos=start;
860 }
861 IO.copy(in,multi,size);
862 pos+=size;
863 }
864 else
865
866 (resource).writeTo(multi,start,size);
867
868 }
869 if (in!=null)
870 in.close();
871 multi.close();
872 }
873 return;
874 }
875
876
877 protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
878 throws IOException
879 {
880 if (content.getContentType()!=null && response.getContentType()==null)
881 response.setContentType(content.getContentType().toString());
882
883 if (response instanceof Response)
884 {
885 Response r=(Response)response;
886 HttpFields fields = r.getHttpFields();
887
888 if (content.getLastModified()!=null)
889 fields.put(HttpHeaders.LAST_MODIFIED_BUFFER,content.getLastModified(),content.getResource().lastModified());
890 else if (content.getResource()!=null)
891 {
892 long lml=content.getResource().lastModified();
893 if (lml!=-1)
894 fields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,lml);
895 }
896
897 if (count != -1)
898 r.setLongContentLength(count);
899
900 writeOptionHeaders(fields);
901 }
902 else
903 {
904 long lml=content.getResource().lastModified();
905 if (lml>=0)
906 response.setDateHeader(HttpHeaders.LAST_MODIFIED,lml);
907
908 if (count != -1)
909 {
910 if (count<Integer.MAX_VALUE)
911 response.setContentLength((int)count);
912 else
913 response.setHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(count));
914 }
915
916 writeOptionHeaders(response);
917 }
918 }
919
920
921 protected void writeOptionHeaders(HttpFields fields) throws IOException
922 {
923 if (_acceptRanges)
924 fields.put(HttpHeaders.ACCEPT_RANGES_BUFFER,HttpHeaderValues.BYTES_BUFFER);
925
926 if (_cacheControl!=null)
927 fields.put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl);
928 }
929
930
931 protected void writeOptionHeaders(HttpServletResponse response) throws IOException
932 {
933 if (_acceptRanges)
934 response.setHeader(HttpHeaders.ACCEPT_RANGES,"bytes");
935
936 if (_cacheControl!=null)
937 response.setHeader(HttpHeaders.CACHE_CONTROL,_cacheControl.toString());
938 }
939
940
941
942
943
944 @Override
945 public void destroy()
946 {
947 try
948 {
949 if (_nioCache!=null)
950 _nioCache.stop();
951 }
952 catch(Exception e)
953 {
954 Log.warn(Log.EXCEPTION,e);
955 }
956 finally
957 {
958 try
959 {
960 if (_bioCache!=null)
961 _bioCache.stop();
962 }
963 catch(Exception e)
964 {
965 Log.warn(Log.EXCEPTION,e);
966 }
967 finally
968 {
969 super.destroy();
970 }
971 }
972 }
973
974
975
976
977 private class UnCachedContent implements HttpContent
978 {
979 Resource _resource;
980
981 UnCachedContent(Resource resource)
982 {
983 _resource=resource;
984 }
985
986
987 public Buffer getContentType()
988 {
989 return _mimeTypes.getMimeByExtension(_resource.toString());
990 }
991
992
993 public Buffer getLastModified()
994 {
995 return null;
996 }
997
998
999 public Buffer getBuffer()
1000 {
1001 return null;
1002 }
1003
1004
1005 public long getContentLength()
1006 {
1007 return _resource.length();
1008 }
1009
1010
1011 public InputStream getInputStream() throws IOException
1012 {
1013 return _resource.getInputStream();
1014 }
1015
1016
1017 public Resource getResource()
1018 {
1019 return _resource;
1020 }
1021
1022
1023 public void release()
1024 {
1025 _resource.release();
1026 _resource=null;
1027 }
1028
1029 }
1030 }