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=resource.length();
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())
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,
739 InclusiveByteRange.to416HeaderRangeString(content_length));
740 resource.writeTo(out,0,content_length);
741 return;
742 }
743
744
745
746
747 if ( ranges.size()== 1)
748 {
749 InclusiveByteRange singleSatisfiableRange =
750 (InclusiveByteRange)ranges.get(0);
751 long singleLength = singleSatisfiableRange.getSize(content_length);
752 writeHeaders(response,content,singleLength );
753 response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
754 response.setHeader(HttpHeaders.CONTENT_RANGE,
755 singleSatisfiableRange.toHeaderRangeString(content_length));
756 resource.writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength);
757 return;
758 }
759
760
761
762
763
764
765 writeHeaders(response,content,-1);
766 String mimetype=content.getContentType().toString();
767 MultiPartOutputStream multi = new MultiPartOutputStream(out);
768 response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
769
770
771
772
773 String ctp;
774 if (request.getHeader(HttpHeaders.REQUEST_RANGE)!=null)
775 ctp = "multipart/x-byteranges; boundary=";
776 else
777 ctp = "multipart/byteranges; boundary=";
778 response.setContentType(ctp+multi.getBoundary());
779
780 InputStream in=resource.getInputStream();
781 long pos=0;
782
783
784 int length=0;
785 String[] header = new String[ranges.size()];
786 for (int i=0;i<ranges.size();i++)
787 {
788 InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
789 header[i]=ibr.toHeaderRangeString(content_length);
790 length+=
791 ((i>0)?2:0)+
792 2+multi.getBoundary().length()+2+
793 HttpHeaders.CONTENT_TYPE.length()+2+mimetype.length()+2+
794 HttpHeaders.CONTENT_RANGE.length()+2+header[i].length()+2+
795 2+
796 (ibr.getLast(content_length)-ibr.getFirst(content_length))+1;
797 }
798 length+=2+2+multi.getBoundary().length()+2+2;
799 response.setContentLength(length);
800
801 for (int i=0;i<ranges.size();i++)
802 {
803 InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
804 multi.startPart(mimetype,new String[]{HttpHeaders.CONTENT_RANGE+": "+header[i]});
805
806 long start=ibr.getFirst(content_length);
807 long size=ibr.getSize(content_length);
808 if (in!=null)
809 {
810
811 if (start<pos)
812 {
813 in.close();
814 in=resource.getInputStream();
815 pos=0;
816 }
817 if (pos<start)
818 {
819 in.skip(start-pos);
820 pos=start;
821 }
822 IO.copy(in,multi,size);
823 pos+=size;
824 }
825 else
826
827 (resource).writeTo(multi,start,size);
828
829 }
830 if (in!=null)
831 in.close();
832 multi.close();
833 }
834 return;
835 }
836
837
838 protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
839 throws IOException
840 {
841 if (content.getContentType()!=null && response.getContentType()==null)
842 response.setContentType(content.getContentType().toString());
843
844 if (response instanceof Response)
845 {
846 Response r=(Response)response;
847 HttpFields fields = r.getHttpFields();
848
849 if (content.getLastModified()!=null)
850 fields.put(HttpHeaders.LAST_MODIFIED_BUFFER,content.getLastModified(),content.getResource().lastModified());
851 else if (content.getResource()!=null)
852 {
853 long lml=content.getResource().lastModified();
854 if (lml!=-1)
855 fields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER,lml);
856 }
857
858 if (count != -1)
859 r.setLongContentLength(count);
860
861 writeOptionHeaders(fields);
862 }
863 else
864 {
865 long lml=content.getResource().lastModified();
866 if (lml>=0)
867 response.setDateHeader(HttpHeaders.LAST_MODIFIED,lml);
868
869 if (count != -1)
870 {
871 if (count<Integer.MAX_VALUE)
872 response.setContentLength((int)count);
873 else
874 response.setHeader(HttpHeaders.CONTENT_LENGTH,TypeUtil.toString(count));
875 }
876
877 writeOptionHeaders(response);
878 }
879 }
880
881
882 protected void writeOptionHeaders(HttpFields fields) throws IOException
883 {
884 if (_acceptRanges)
885 fields.put(HttpHeaders.ACCEPT_RANGES_BUFFER,HttpHeaderValues.BYTES_BUFFER);
886
887 if (_cacheControl!=null)
888 fields.put(HttpHeaders.CACHE_CONTROL_BUFFER,_cacheControl);
889 }
890
891
892 protected void writeOptionHeaders(HttpServletResponse response) throws IOException
893 {
894 if (_acceptRanges)
895 response.setHeader(HttpHeaders.ACCEPT_RANGES,"bytes");
896
897 if (_cacheControl!=null)
898 response.setHeader(HttpHeaders.CACHE_CONTROL,_cacheControl.toString());
899 }
900
901
902
903
904
905 public void destroy()
906 {
907 try
908 {
909 if (_nioCache!=null)
910 _nioCache.stop();
911 if (_bioCache!=null)
912 _bioCache.stop();
913 }
914 catch(Exception e)
915 {
916 Log.warn(Log.EXCEPTION,e);
917 }
918 finally
919 {
920 super.destroy();
921 }
922 }
923
924
925
926
927 private class UnCachedContent implements HttpContent
928 {
929 Resource _resource;
930
931 UnCachedContent(Resource resource)
932 {
933 _resource=resource;
934 }
935
936
937 public Buffer getContentType()
938 {
939 return _mimeTypes.getMimeByExtension(_resource.toString());
940 }
941
942
943 public Buffer getLastModified()
944 {
945 return null;
946 }
947
948
949 public Buffer getBuffer()
950 {
951 return null;
952 }
953
954
955 public long getContentLength()
956 {
957 return _resource.length();
958 }
959
960
961 public InputStream getInputStream() throws IOException
962 {
963 return _resource.getInputStream();
964 }
965
966
967 public Resource getResource()
968 {
969 return _resource;
970 }
971
972
973 public void release()
974 {
975 _resource.release();
976 _resource=null;
977 }
978
979 }
980
981
982
983 class NIOResourceCache extends ResourceCache
984 {
985
986 public NIOResourceCache(MimeTypes mimeTypes)
987 {
988 super(mimeTypes);
989 }
990
991
992 protected void fill(Content content) throws IOException
993 {
994 Buffer buffer=null;
995 Resource resource=content.getResource();
996 long length=resource.length();
997
998 if (_useFileMappedBuffer && resource.getFile()!=null)
999 {
1000 buffer = new DirectNIOBuffer(resource.getFile());
1001 }
1002 else
1003 {
1004 InputStream is = resource.getInputStream();
1005 try
1006 {
1007 Connector connector = HttpConnection.getCurrentConnection().getConnector();
1008 buffer = ((NIOConnector)connector).getUseDirectBuffers()?
1009 (NIOBuffer)new DirectNIOBuffer((int)length):
1010 (NIOBuffer)new IndirectNIOBuffer((int)length);
1011
1012 }
1013 catch(OutOfMemoryError e)
1014 {
1015 Log.warn(e.toString());
1016 Log.debug(e);
1017 buffer = new IndirectNIOBuffer((int) length);
1018 }
1019 buffer.readFrom(is,(int)length);
1020 is.close();
1021 }
1022 content.setBuffer(buffer);
1023 }
1024 }
1025 }