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