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