KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > servlets > DefaultServlet


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.catalina.servlets;
20
21
22 import java.io.BufferedInputStream JavaDoc;
23 import java.io.ByteArrayInputStream JavaDoc;
24 import java.io.ByteArrayOutputStream JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.FileInputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.InputStreamReader JavaDoc;
30 import java.io.OutputStreamWriter JavaDoc;
31 import java.io.PrintWriter JavaDoc;
32 import java.io.RandomAccessFile JavaDoc;
33 import java.io.Reader JavaDoc;
34 import java.io.StringReader JavaDoc;
35 import java.io.StringWriter JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.StringTokenizer JavaDoc;
39
40 import javax.naming.InitialContext JavaDoc;
41 import javax.naming.NameClassPair JavaDoc;
42 import javax.naming.NamingEnumeration JavaDoc;
43 import javax.naming.NamingException JavaDoc;
44 import javax.naming.directory.DirContext JavaDoc;
45 import javax.servlet.ServletException JavaDoc;
46 import javax.servlet.ServletOutputStream JavaDoc;
47 import javax.servlet.UnavailableException JavaDoc;
48 import javax.servlet.http.HttpServlet JavaDoc;
49 import javax.servlet.http.HttpServletRequest JavaDoc;
50 import javax.servlet.http.HttpServletResponse JavaDoc;
51 import javax.xml.transform.Source JavaDoc;
52 import javax.xml.transform.Transformer JavaDoc;
53 import javax.xml.transform.TransformerException JavaDoc;
54 import javax.xml.transform.TransformerFactory JavaDoc;
55 import javax.xml.transform.stream.StreamResult JavaDoc;
56 import javax.xml.transform.stream.StreamSource JavaDoc;
57
58 import org.apache.catalina.Globals;
59 import org.apache.catalina.util.ServerInfo;
60 import org.apache.catalina.util.StringManager;
61 import org.apache.catalina.util.URLEncoder;
62 import org.apache.naming.resources.CacheEntry;
63 import org.apache.naming.resources.ProxyDirContext;
64 import org.apache.naming.resources.Resource;
65 import org.apache.naming.resources.ResourceAttributes;
66
67
68 /**
69  * The default resource-serving servlet for most web applications,
70  * used to serve static resources such as HTML pages and images.
71  *
72  * @author Craig R. McClanahan
73  * @author Remy Maucherat
74  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
75  */

76
77 public class DefaultServlet
78     extends HttpServlet JavaDoc {
79
80
81     // ----------------------------------------------------- Instance Variables
82

83
84     /**
85      * The debugging detail level for this servlet.
86      */

87     protected int debug = 0;
88
89
90     /**
91      * The input buffer size to use when serving resources.
92      */

93     protected int input = 2048;
94
95
96     /**
97      * Should we generate directory listings?
98      */

99     protected boolean listings = false;
100
101
102     /**
103      * Read only flag. By default, it's set to true.
104      */

105     protected boolean readOnly = true;
106
107
108     /**
109      * The output buffer size to use when serving resources.
110      */

111     protected int output = 2048;
112
113
114     /**
115      * Array containing the safe characters set.
116      */

117     protected static URLEncoder urlEncoder;
118
119
120     /**
121      * Allow customized directory listing per directory.
122      */

123     protected String JavaDoc localXsltFile = null;
124
125
126     /**
127      * Allow customized directory listing per instance.
128      */

129     protected String JavaDoc globalXsltFile = null;
130
131
132     /**
133      * Allow a readme file to be included.
134      */

135     protected String JavaDoc readmeFile = null;
136
137
138     /**
139      * Proxy directory context.
140      */

141     protected ProxyDirContext resources = null;
142
143
144     /**
145      * File encoding to be used when reading static files. If none is specified
146      * the platform default is used.
147      */

148     protected String JavaDoc fileEncoding = null;
149     
150     
151     /**
152      * Minimum size for sendfile usage in bytes.
153      */

154     protected int sendfileSize = 48 * 1024;
155     
156     
157     /**
158      * Full range marker.
159      */

160     protected static ArrayList JavaDoc FULL = new ArrayList JavaDoc();
161     
162     
163     // ----------------------------------------------------- Static Initializer
164

165
166     /**
167      * GMT timezone - all HTTP dates are on GMT
168      */

169     static {
170         urlEncoder = new URLEncoder();
171         urlEncoder.addSafeCharacter('-');
172         urlEncoder.addSafeCharacter('_');
173         urlEncoder.addSafeCharacter('.');
174         urlEncoder.addSafeCharacter('*');
175         urlEncoder.addSafeCharacter('/');
176     }
177
178
179     /**
180      * MIME multipart separation string
181      */

182     protected static final String JavaDoc mimeSeparation = "CATALINA_MIME_BOUNDARY";
183
184
185     /**
186      * JNDI resources name.
187      */

188     protected static final String JavaDoc RESOURCES_JNDI_NAME = "java:/comp/Resources";
189
190
191     /**
192      * The string manager for this package.
193      */

194     protected static StringManager sm =
195         StringManager.getManager(Constants.Package);
196
197
198     /**
199      * Size of file transfer buffer in bytes.
200      */

201     protected static final int BUFFER_SIZE = 4096;
202
203
204     // --------------------------------------------------------- Public Methods
205

206
207     /**
208      * Finalize this servlet.
209      */

210     public void destroy() {
211     }
212
213
214     /**
215      * Initialize this servlet.
216      */

217     public void init() throws ServletException JavaDoc {
218
219         if (getServletConfig().getInitParameter("debug") != null)
220             debug = Integer.parseInt(getServletConfig().getInitParameter("debug"));
221
222         if (getServletConfig().getInitParameter("input") != null)
223             input = Integer.parseInt(getServletConfig().getInitParameter("input"));
224
225         if (getServletConfig().getInitParameter("output") != null)
226             output = Integer.parseInt(getServletConfig().getInitParameter("output"));
227
228         listings = Boolean.parseBoolean(getServletConfig().getInitParameter("listings"));
229
230         if (getServletConfig().getInitParameter("readonly") != null)
231             readOnly = Boolean.parseBoolean(getServletConfig().getInitParameter("readonly"));
232
233         if (getServletConfig().getInitParameter("sendfileSize") != null)
234             sendfileSize =
235                 Integer.parseInt(getServletConfig().getInitParameter("sendfileSize")) * 1024;
236
237         fileEncoding = getServletConfig().getInitParameter("fileEncoding");
238
239         globalXsltFile = getServletConfig().getInitParameter("globalXsltFile");
240         localXsltFile = getServletConfig().getInitParameter("localXsltFile");
241         readmeFile = getServletConfig().getInitParameter("readmeFile");
242
243         // Sanity check on the specified buffer sizes
244
if (input < 256)
245             input = 256;
246         if (output < 256)
247             output = 256;
248
249         if (debug > 0) {
250             log("DefaultServlet.init: input buffer size=" + input +
251                 ", output buffer size=" + output);
252         }
253
254         // Load the proxy dir context.
255
resources = (ProxyDirContext) getServletContext()
256             .getAttribute(Globals.RESOURCES_ATTR);
257         if (resources == null) {
258             try {
259                 resources =
260                     (ProxyDirContext) new InitialContext JavaDoc()
261                     .lookup(RESOURCES_JNDI_NAME);
262             } catch (NamingException JavaDoc e) {
263                 // Failed
264
throw new ServletException JavaDoc("No resources", e);
265             }
266         }
267
268         if (resources == null) {
269             throw new UnavailableException JavaDoc("No resources");
270         }
271
272     }
273
274
275     // ------------------------------------------------------ Protected Methods
276

277
278     /**
279      * Return the relative path associated with this servlet.
280      *
281      * @param request The servlet request we are processing
282      */

283     protected String JavaDoc getRelativePath(HttpServletRequest JavaDoc request) {
284
285         // Are we being processed by a RequestDispatcher.include()?
286
if (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) {
287             String JavaDoc result = (String JavaDoc) request.getAttribute(
288                                             Globals.INCLUDE_PATH_INFO_ATTR);
289             if (result == null)
290                 result = (String JavaDoc) request.getAttribute(
291                                             Globals.INCLUDE_SERVLET_PATH_ATTR);
292             if ((result == null) || (result.equals("")))
293                 result = "/";
294             return (result);
295         }
296
297         // No, extract the desired path directly from the request
298
String JavaDoc result = request.getPathInfo();
299         if (result == null) {
300             result = request.getServletPath();
301         }
302         if ((result == null) || (result.equals(""))) {
303             result = "/";
304         }
305         return (result);
306
307     }
308
309
310     /**
311      * Process a GET request for the specified resource.
312      *
313      * @param request The servlet request we are processing
314      * @param response The servlet response we are creating
315      *
316      * @exception IOException if an input/output error occurs
317      * @exception ServletException if a servlet-specified error occurs
318      */

319     protected void doGet(HttpServletRequest JavaDoc request,
320                          HttpServletResponse JavaDoc response)
321         throws IOException JavaDoc, ServletException JavaDoc {
322
323         // Serve the requested resource, including the data content
324
serveResource(request, response, true);
325
326     }
327
328
329     /**
330      * Process a HEAD request for the specified resource.
331      *
332      * @param request The servlet request we are processing
333      * @param response The servlet response we are creating
334      *
335      * @exception IOException if an input/output error occurs
336      * @exception ServletException if a servlet-specified error occurs
337      */

338     protected void doHead(HttpServletRequest JavaDoc request,
339                           HttpServletResponse JavaDoc response)
340         throws IOException JavaDoc, ServletException JavaDoc {
341
342         // Serve the requested resource, without the data content
343
serveResource(request, response, false);
344
345     }
346
347
348     /**
349      * Process a POST request for the specified resource.
350      *
351      * @param request The servlet request we are processing
352      * @param response The servlet response we are creating
353      *
354      * @exception IOException if an input/output error occurs
355      * @exception ServletException if a servlet-specified error occurs
356      */

357     protected void doPost(HttpServletRequest JavaDoc request,
358                           HttpServletResponse JavaDoc response)
359         throws IOException JavaDoc, ServletException JavaDoc {
360         doGet(request, response);
361     }
362
363
364     /**
365      * Process a POST request for the specified resource.
366      *
367      * @param req The servlet request we are processing
368      * @param resp The servlet response we are creating
369      *
370      * @exception IOException if an input/output error occurs
371      * @exception ServletException if a servlet-specified error occurs
372      */

373     protected void doPut(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc resp)
374         throws ServletException JavaDoc, IOException JavaDoc {
375
376         if (readOnly) {
377             resp.sendError(HttpServletResponse.SC_FORBIDDEN);
378             return;
379         }
380
381         String JavaDoc path = getRelativePath(req);
382
383         boolean exists = true;
384         try {
385             resources.lookup(path);
386         } catch (NamingException JavaDoc e) {
387             exists = false;
388         }
389
390         boolean result = true;
391
392         // Temp. content file used to support partial PUT
393
File JavaDoc contentFile = null;
394
395         Range range = parseContentRange(req, resp);
396
397         InputStream JavaDoc resourceInputStream = null;
398
399         // Append data specified in ranges to existing content for this
400
// resource - create a temp. file on the local filesystem to
401
// perform this operation
402
// Assume just one range is specified for now
403
if (range != null) {
404             contentFile = executePartialPut(req, range, path);
405             resourceInputStream = new FileInputStream JavaDoc(contentFile);
406         } else {
407             resourceInputStream = req.getInputStream();
408         }
409
410         try {
411             Resource newResource = new Resource(resourceInputStream);
412             // FIXME: Add attributes
413
if (exists) {
414                 resources.rebind(path, newResource);
415             } else {
416                 resources.bind(path, newResource);
417             }
418         } catch(NamingException JavaDoc e) {
419             result = false;
420         }
421
422         if (result) {
423             if (exists) {
424                 resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
425             } else {
426                 resp.setStatus(HttpServletResponse.SC_CREATED);
427             }
428         } else {
429             resp.sendError(HttpServletResponse.SC_CONFLICT);
430         }
431
432     }
433
434
435     /**
436      * Handle a partial PUT. New content specified in request is appended to
437      * existing content in oldRevisionContent (if present). This code does
438      * not support simultaneous partial updates to the same resource.
439      */

440     protected File JavaDoc executePartialPut(HttpServletRequest JavaDoc req, Range range,
441                                      String JavaDoc path)
442         throws IOException JavaDoc {
443
444         // Append data specified in ranges to existing content for this
445
// resource - create a temp. file on the local filesystem to
446
// perform this operation
447
File JavaDoc tempDir = (File JavaDoc) getServletContext().getAttribute
448             ("javax.servlet.context.tempdir");
449         // Convert all '/' characters to '.' in resourcePath
450
String JavaDoc convertedResourcePath = path.replace('/', '.');
451         File JavaDoc contentFile = new File JavaDoc(tempDir, convertedResourcePath);
452         if (contentFile.createNewFile()) {
453             // Clean up contentFile when Tomcat is terminated
454
contentFile.deleteOnExit();
455         }
456
457         RandomAccessFile JavaDoc randAccessContentFile =
458             new RandomAccessFile JavaDoc(contentFile, "rw");
459
460         Resource oldResource = null;
461         try {
462             Object JavaDoc obj = resources.lookup(path);
463             if (obj instanceof Resource)
464                 oldResource = (Resource) obj;
465         } catch (NamingException JavaDoc e) {
466             ;
467         }
468
469         // Copy data in oldRevisionContent to contentFile
470
if (oldResource != null) {
471             BufferedInputStream JavaDoc bufOldRevStream =
472                 new BufferedInputStream JavaDoc(oldResource.streamContent(),
473                                         BUFFER_SIZE);
474
475             int numBytesRead;
476             byte[] copyBuffer = new byte[BUFFER_SIZE];
477             while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) {
478                 randAccessContentFile.write(copyBuffer, 0, numBytesRead);
479             }
480
481             bufOldRevStream.close();
482         }
483
484         randAccessContentFile.setLength(range.length);
485
486         // Append data in request input stream to contentFile
487
randAccessContentFile.seek(range.start);
488         int numBytesRead;
489         byte[] transferBuffer = new byte[BUFFER_SIZE];
490         BufferedInputStream JavaDoc requestBufInStream =
491             new BufferedInputStream JavaDoc(req.getInputStream(), BUFFER_SIZE);
492         while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) {
493             randAccessContentFile.write(transferBuffer, 0, numBytesRead);
494         }
495         randAccessContentFile.close();
496         requestBufInStream.close();
497
498         return contentFile;
499
500     }
501
502
503     /**
504      * Process a POST request for the specified resource.
505      *
506      * @param req The servlet request we are processing
507      * @param resp The servlet response we are creating
508      *
509      * @exception IOException if an input/output error occurs
510      * @exception ServletException if a servlet-specified error occurs
511      */

512     protected void doDelete(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc resp)
513         throws ServletException JavaDoc, IOException JavaDoc {
514
515         if (readOnly) {
516             resp.sendError(HttpServletResponse.SC_FORBIDDEN);
517             return;
518         }
519
520         String JavaDoc path = getRelativePath(req);
521
522         boolean exists = true;
523         try {
524             resources.lookup(path);
525         } catch (NamingException JavaDoc e) {
526             exists = false;
527         }
528
529         if (exists) {
530             boolean result = true;
531             try {
532                 resources.unbind(path);
533             } catch (NamingException JavaDoc e) {
534                 result = false;
535             }
536             if (result) {
537                 resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
538             } else {
539                 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
540             }
541         } else {
542             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
543         }
544
545     }
546
547
548     /**
549      * Check if the conditions specified in the optional If headers are
550      * satisfied.
551      *
552      * @param request The servlet request we are processing
553      * @param response The servlet response we are creating
554      * @param resourceAttributes The resource information
555      * @return boolean true if the resource meets all the specified conditions,
556      * and false if any of the conditions is not satisfied, in which case
557      * request processing is stopped
558      */

559     protected boolean checkIfHeaders(HttpServletRequest JavaDoc request,
560                                      HttpServletResponse JavaDoc response,
561                                      ResourceAttributes resourceAttributes)
562         throws IOException JavaDoc {
563
564         return checkIfMatch(request, response, resourceAttributes)
565             && checkIfModifiedSince(request, response, resourceAttributes)
566             && checkIfNoneMatch(request, response, resourceAttributes)
567             && checkIfUnmodifiedSince(request, response, resourceAttributes);
568
569     }
570
571
572     /**
573      * Get the ETag associated with a file.
574      *
575      * @param resourceAttributes The resource information
576      */

577     protected String JavaDoc getETag(ResourceAttributes resourceAttributes) {
578         String JavaDoc result = null;
579         if ((result = resourceAttributes.getETag(true)) != null) {
580             return result;
581         } else if ((result = resourceAttributes.getETag()) != null) {
582             return result;
583         } else {
584             return "W/\"" + resourceAttributes.getContentLength() + "-"
585                 + resourceAttributes.getLastModified() + "\"";
586         }
587     }
588
589
590     /**
591      * URL rewriter.
592      *
593      * @param path Path which has to be rewiten
594      */

595     protected String JavaDoc rewriteUrl(String JavaDoc path) {
596         return urlEncoder.encode( path );
597     }
598
599
600     /**
601      * Display the size of a file.
602      */

603     protected void displaySize(StringBuffer JavaDoc buf, int filesize) {
604
605         int leftside = filesize / 1024;
606         int rightside = (filesize % 1024) / 103; // makes 1 digit
607
// To avoid 0.0 for non-zero file, we bump to 0.1
608
if (leftside == 0 && rightside == 0 && filesize != 0)
609             rightside = 1;
610         buf.append(leftside).append(".").append(rightside);
611         buf.append(" KB");
612
613     }
614
615
616     /**
617      * Serve the specified resource, optionally including the data content.
618      *
619      * @param request The servlet request we are processing
620      * @param response The servlet response we are creating
621      * @param content Should the content be included?
622      *
623      * @exception IOException if an input/output error occurs
624      * @exception ServletException if a servlet-specified error occurs
625      */

626     protected void serveResource(HttpServletRequest JavaDoc request,
627                                  HttpServletResponse JavaDoc response,
628                                  boolean content)
629         throws IOException JavaDoc, ServletException JavaDoc {
630
631         // Identify the requested resource path
632
String JavaDoc path = getRelativePath(request);
633         if (debug > 0) {
634             if (content)
635                 log("DefaultServlet.serveResource: Serving resource '" +
636                     path + "' headers and data");
637             else
638                 log("DefaultServlet.serveResource: Serving resource '" +
639                     path + "' headers only");
640         }
641
642         CacheEntry cacheEntry = resources.lookupCache(path);
643
644         if (!cacheEntry.exists) {
645             // Check if we're included so we can return the appropriate
646
// missing resource name in the error
647
String JavaDoc requestUri = (String JavaDoc) request.getAttribute(
648                                             Globals.INCLUDE_REQUEST_URI_ATTR);
649             if (requestUri == null) {
650                 requestUri = request.getRequestURI();
651             } else {
652                 // We're included, and the response.sendError() below is going
653
// to be ignored by the resource that is including us.
654
// Therefore, the only way we can let the including resource
655
// know is by including warning message in response
656
response.getWriter().write(
657                     sm.getString("defaultServlet.missingResource",
658                     requestUri));
659             }
660
661             response.sendError(HttpServletResponse.SC_NOT_FOUND,
662                                requestUri);
663             return;
664         }
665
666         // If the resource is not a collection, and the resource path
667
// ends with "/" or "\", return NOT FOUND
668
if (cacheEntry.context == null) {
669             if (path.endsWith("/") || (path.endsWith("\\"))) {
670                 // Check if we're included so we can return the appropriate
671
// missing resource name in the error
672
String JavaDoc requestUri = (String JavaDoc) request.getAttribute(
673                                             Globals.INCLUDE_REQUEST_URI_ATTR);
674                 if (requestUri == null) {
675                     requestUri = request.getRequestURI();
676                 }
677                 response.sendError(HttpServletResponse.SC_NOT_FOUND,
678                                    requestUri);
679                 return;
680             }
681         }
682
683         // Check if the conditions specified in the optional If headers are
684
// satisfied.
685
if (cacheEntry.context == null) {
686
687             // Checking If headers
688
boolean included =
689                 (request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null);
690             if (!included
691                 && !checkIfHeaders(request, response, cacheEntry.attributes)) {
692                 return;
693             }
694
695         }
696
697         // Find content type.
698
String JavaDoc contentType = cacheEntry.attributes.getMimeType();
699         if (contentType == null) {
700             contentType = getServletContext().getMimeType(cacheEntry.name);
701             cacheEntry.attributes.setMimeType(contentType);
702         }
703
704         ArrayList JavaDoc ranges = null;
705         long contentLength = -1L;
706
707         if (cacheEntry.context != null) {
708
709             // Skip directory listings if we have been configured to
710
// suppress them
711
if (!listings) {
712                 response.sendError(HttpServletResponse.SC_NOT_FOUND,
713                                    request.getRequestURI());
714                 return;
715             }
716             contentType = "text/html;charset=UTF-8";
717
718         } else {
719
720             // Parse range specifier
721

722             ranges = parseRange(request, response, cacheEntry.attributes);
723
724             // ETag header
725
response.setHeader("ETag", getETag(cacheEntry.attributes));
726
727             // Last-Modified header
728
response.setHeader("Last-Modified",
729                     cacheEntry.attributes.getLastModifiedHttp());
730
731             // Get content length
732
contentLength = cacheEntry.attributes.getContentLength();
733             // Special case for zero length files, which would cause a
734
// (silent) ISE when setting the output buffer size
735
if (contentLength == 0L) {
736                 content = false;
737             }
738
739         }
740
741         ServletOutputStream JavaDoc ostream = null;
742         PrintWriter JavaDoc writer = null;
743
744         if (content) {
745
746             // Trying to retrieve the servlet output stream
747

748             try {
749                 ostream = response.getOutputStream();
750             } catch (IllegalStateException JavaDoc e) {
751                 // If it fails, we try to get a Writer instead if we're
752
// trying to serve a text file
753
if ( (contentType == null)
754                         || (contentType.startsWith("text"))
755                         || (contentType.endsWith("xml")) ) {
756                     writer = response.getWriter();
757                 } else {
758                     throw e;
759                 }
760             }
761
762         }
763
764         if ( (cacheEntry.context != null)
765                 || ( ((ranges == null) || (ranges.isEmpty()))
766                         && (request.getHeader("Range") == null) )
767                 || (ranges == FULL) ) {
768
769             // Set the appropriate output headers
770
if (contentType != null) {
771                 if (debug > 0)
772                     log("DefaultServlet.serveFile: contentType='" +
773                         contentType + "'");
774                 response.setContentType(contentType);
775             }
776             if ((cacheEntry.resource != null) && (contentLength >= 0)) {
777                 if (debug > 0)
778                     log("DefaultServlet.serveFile: contentLength=" +
779                         contentLength);
780                 if (contentLength < Integer.MAX_VALUE) {
781                     response.setContentLength((int) contentLength);
782                 } else {
783                     // Set the content-length as String to be able to use a long
784
response.setHeader("content-length", "" + contentLength);
785                 }
786             }
787
788             InputStream JavaDoc renderResult = null;
789             if (cacheEntry.context != null) {
790
791                 if (content) {
792                     // Serve the directory browser
793
renderResult =
794                         render(request.getContextPath(), cacheEntry);
795                 }
796
797             }
798
799             // Copy the input stream to our output stream (if requested)
800
if (content) {
801                 try {
802                     response.setBufferSize(output);
803                 } catch (IllegalStateException JavaDoc e) {
804                     // Silent catch
805
}
806                 if (ostream != null) {
807                     if (!checkSendfile(request, response, cacheEntry, contentLength, null))
808                         copy(cacheEntry, renderResult, ostream);
809                 } else {
810                     copy(cacheEntry, renderResult, writer);
811                 }
812             }
813
814         } else {
815
816             if ((ranges == null) || (ranges.isEmpty()))
817                 return;
818
819             // Partial content response.
820

821             response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
822
823             if (ranges.size() == 1) {
824
825                 Range range = (Range) ranges.get(0);
826                 response.addHeader("Content-Range", "bytes "
827                                    + range.start
828