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