Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: javax/servlet/http/HttpServlet.java


1   /*
2   * Copyright 2004 The Apache Software Foundation
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *     http://www.apache.org/licenses/LICENSE-2.0
9   *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16  package javax.servlet.http;
17  
18  import java.io.IOException;
19  import java.io.PrintWriter;
20  import java.io.OutputStreamWriter;
21  import java.io.UnsupportedEncodingException;
22  import java.lang.reflect.Method;
23  import java.text.MessageFormat;
24  import java.util.Enumeration;
25  import java.util.Locale;
26  import java.util.ResourceBundle;
27  
28  import javax.servlet.GenericServlet;
29  import javax.servlet.ServletException;
30  import javax.servlet.ServletOutputStream;
31  import javax.servlet.ServletRequest;
32  import javax.servlet.ServletResponse;
33  
34  
35  /**
36   *
37   * Provides an abstract class to be subclassed to create
38   * an HTTP servlet suitable for a Web site. A subclass of
39   * <code>HttpServlet</code> must override at least 
40   * one method, usually one of these:
41   *
42   * <ul>
43   * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
44   * <li> <code>doPost</code>, for HTTP POST requests
45   * <li> <code>doPut</code>, for HTTP PUT requests
46   * <li> <code>doDelete</code>, for HTTP DELETE requests
47   * <li> <code>init</code> and <code>destroy</code>, 
48   * to manage resources that are held for the life of the servlet
49   * <li> <code>getServletInfo</code>, which the servlet uses to
50   * provide information about itself 
51   * </ul>
52   *
53   * <p>There's almost no reason to override the <code>service</code>
54   * method. <code>service</code> handles standard HTTP
55   * requests by dispatching them to the handler methods
56   * for each HTTP request type (the <code>do</code><i>XXX</i>
57   * methods listed above).
58   *
59   * <p>Likewise, there's almost no reason to override the 
60   * <code>doOptions</code> and <code>doTrace</code> methods.
61   * 
62   * <p>Servlets typically run on multithreaded servers,
63   * so be aware that a servlet must handle concurrent
64   * requests and be careful to synchronize access to shared resources.
65   * Shared resources include in-memory data such as
66   * instance or class variables and external objects
67   * such as files, database connections, and network 
68   * connections.
69   * See the
70   * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
71   * Java Tutorial on Multithreaded Programming</a> for more
72   * information on handling multiple threads in a Java program.
73   *
74   * @author  Various
75   * @version  $Version$
76   *
77   */
78  
79  
80  
81  public abstract class HttpServlet extends GenericServlet
82      implements java.io.Serializable
83  {
84      private static final String METHOD_DELETE = "DELETE";
85      private static final String METHOD_HEAD = "HEAD";
86      private static final String METHOD_GET = "GET";
87      private static final String METHOD_OPTIONS = "OPTIONS";
88      private static final String METHOD_POST = "POST";
89      private static final String METHOD_PUT = "PUT";
90      private static final String METHOD_TRACE = "TRACE";
91  
92      private static final String HEADER_IFMODSINCE = "If-Modified-Since";
93      private static final String HEADER_LASTMOD = "Last-Modified";
94      
95      private static final String LSTRING_FILE =
96    "javax.servlet.http.LocalStrings";
97      private static ResourceBundle lStrings =
98    ResourceBundle.getBundle(LSTRING_FILE);
99     
100    
101    
102     
103     /**
104      * Does nothing, because this is an abstract class.
105      * 
106      */
107 
108     public HttpServlet() { }
109     
110     
111 
112     /**
113      *
114      * Called by the server (via the <code>service</code> method) to
115      * allow a servlet to handle a GET request. 
116      *
117      * <p>Overriding this method to support a GET request also
118      * automatically supports an HTTP HEAD request. A HEAD
119      * request is a GET request that returns no body in the
120      * response, only the request header fields.
121      *
122      * <p>When overriding this method, read the request data,
123      * write the response headers, get the response's writer or 
124      * output stream object, and finally, write the response data.
125      * It's best to include content type and encoding. When using
126      * a <code>PrintWriter</code> object to return the response,
127      * set the content type before accessing the
128      * <code>PrintWriter</code> object.
129      *
130      * <p>The servlet container must write the headers before
131      * committing the response, because in HTTP the headers must be sent
132      * before the response body.
133      *
134      * <p>Where possible, set the Content-Length header (with the
135      * {@link javax.servlet.ServletResponse#setContentLength} method),
136      * to allow the servlet container to use a persistent connection 
137      * to return its response to the client, improving performance.
138      * The content length is automatically set if the entire response fits
139      * inside the response buffer.
140      *
141      * <p>When using HTTP 1.1 chunked encoding (which means that the response
142      * has a Transfer-Encoding header), do not set the Content-Length header.
143      *
144      * <p>The GET method should be safe, that is, without
145      * any side effects for which users are held responsible.
146      * For example, most form queries have no side effects.
147      * If a client request is intended to change stored data,
148      * the request should use some other HTTP method.
149      *
150      * <p>The GET method should also be idempotent, meaning
151      * that it can be safely repeated. Sometimes making a
152      * method safe also makes it idempotent. For example, 
153      * repeating queries is both safe and idempotent, but
154      * buying a product online or modifying data is neither
155      * safe nor idempotent. 
156      *
157      * <p>If the request is incorrectly formatted, <code>doGet</code>
158      * returns an HTTP "Bad Request" message.
159      * 
160      *
161      * @param req  an {@link HttpServletRequest} object that
162      *      contains the request the client has made
163      *      of the servlet
164      *
165      * @param resp  an {@link HttpServletResponse} object that
166      *      contains the response the servlet sends
167      *      to the client
168      * 
169      * @exception IOException  if an input or output error is 
170      *        detected when the servlet handles
171      *        the GET request
172      *
173      * @exception ServletException  if the request for the GET
174      *          could not be handled
175      *
176      * 
177      * @see javax.servlet.ServletResponse#setContentType
178      *
179      */
180 
181     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
182   throws ServletException, IOException
183     {
184   String protocol = req.getProtocol();
185   String msg = lStrings.getString("http.method_get_not_supported");
186   if (protocol.endsWith("1.1")) {
187       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
188   } else {
189       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
190   }
191     }
192 
193 
194 
195 
196 
197     /**
198      *
199      * Returns the time the <code>HttpServletRequest</code>
200      * object was last modified,
201      * in milliseconds since midnight January 1, 1970 GMT.
202      * If the time is unknown, this method returns a negative
203      * number (the default).
204      *
205      * <p>Servlets that support HTTP GET requests and can quickly determine
206      * their last modification time should override this method.
207      * This makes browser and proxy caches work more effectively,
208      * reducing the load on server and network resources.
209      *
210      *
211      * @param req  the <code>HttpServletRequest</code> 
212      *      object that is sent to the servlet
213      *
214      * @return    a <code>long</code> integer specifying
215      *      the time the <code>HttpServletRequest</code>
216      *      object was last modified, in milliseconds
217      *      since midnight, January 1, 1970 GMT, or
218      *      -1 if the time is not known
219      *
220      */
221 
222     protected long getLastModified(HttpServletRequest req) {
223   return -1;
224     }
225 
226 
227 
228 
229     /**
230      * 
231      *
232      * <p>Receives an HTTP HEAD request from the protected
233      * <code>service</code> method and handles the
234      * request.
235      * The client sends a HEAD request when it wants
236      * to see only the headers of a response, such as
237      * Content-Type or Content-Length. The HTTP HEAD
238      * method counts the output bytes in the response
239      * to set the Content-Length header accurately.
240      *
241      * <p>If you override this method, you can avoid computing
242      * the response body and just set the response headers
243      * directly to improve performance. Make sure that the
244      * <code>doHead</code> method you write is both safe
245      * and idempotent (that is, protects itself from being
246      * called multiple times for one HTTP HEAD request).
247      *
248      * <p>If the HTTP HEAD request is incorrectly formatted,
249      * <code>doHead</code> returns an HTTP "Bad Request"
250      * message.
251      *
252      *
253      * @param req  the request object that is passed
254      *      to the servlet
255      *      
256      * @param resp  the response object that the servlet
257      *      uses to return the headers to the clien
258      *
259      * @exception IOException    if an input or output error occurs
260      *
261      * @exception ServletException  if the request for the HEAD
262      *          could not be handled
263      */
264 
265     protected void doHead(HttpServletRequest req, HttpServletResponse resp)
266   throws ServletException, IOException
267     {
268   NoBodyResponse response = new NoBodyResponse(resp);
269   
270   doGet(req, response);
271   response.setContentLength();
272     }
273     
274 
275 
276 
277 
278     /**
279      *
280      * Called by the server (via the <code>service</code> method)
281      * to allow a servlet to handle a POST request.
282      *
283      * The HTTP POST method allows the client to send
284      * data of unlimited length to the Web server a single time
285      * and is useful when posting information such as
286      * credit card numbers.
287      *
288      * <p>When overriding this method, read the request data,
289      * write the response headers, get the response's writer or output
290      * stream object, and finally, write the response data. It's best 
291      * to include content type and encoding. When using a
292      * <code>PrintWriter</code> object to return the response, set the 
293      * content type before accessing the <code>PrintWriter</code> object. 
294      *
295      * <p>The servlet container must write the headers before committing the
296      * response, because in HTTP the headers must be sent before the 
297      * response body.
298      *
299      * <p>Where possible, set the Content-Length header (with the
300      * {@link javax.servlet.ServletResponse#setContentLength} method),
301      * to allow the servlet container to use a persistent connection 
302      * to return its response to the client, improving performance.
303      * The content length is automatically set if the entire response fits
304      * inside the response buffer.  
305      *
306      * <p>When using HTTP 1.1 chunked encoding (which means that the response
307      * has a Transfer-Encoding header), do not set the Content-Length header. 
308      *
309      * <p>This method does not need to be either safe or idempotent.
310      * Operations requested through POST can have side effects for
311      * which the user can be held accountable, for example, 
312      * updating stored data or buying items online.
313      *
314      * <p>If the HTTP POST request is incorrectly formatted,
315      * <code>doPost</code> returns an HTTP "Bad Request" message.
316      *
317      *
318      * @param req  an {@link HttpServletRequest} object that
319      *      contains the request the client has made
320      *      of the servlet
321      *
322      * @param resp  an {@link HttpServletResponse} object that
323      *      contains the response the servlet sends
324      *      to the client
325      * 
326      * @exception IOException  if an input or output error is 
327      *        detected when the servlet handles
328      *        the request
329      *
330      * @exception ServletException  if the request for the POST
331      *          could not be handled
332      *
333      *
334      * @see javax.servlet.ServletOutputStream
335      * @see javax.servlet.ServletResponse#setContentType
336      *
337      *
338      */
339 
340     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
341   throws ServletException, IOException
342     {
343   String protocol = req.getProtocol();
344   String msg = lStrings.getString("http.method_post_not_supported");
345   if (protocol.endsWith("1.1")) {
346       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
347   } else {
348       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
349   }
350     }
351 
352 
353 
354 
355     /**
356      * Called by the server (via the <code>service</code> method)
357      * to allow a servlet to handle a PUT request.
358      *
359      * The PUT operation allows a client to 
360      * place a file on the server and is similar to 
361      * sending a file by FTP.
362      *
363      * <p>When overriding this method, leave intact
364      * any content headers sent with the request (including
365      * Content-Length, Content-Type, Content-Transfer-Encoding,
366      * Content-Encoding, Content-Base, Content-Language, Content-Location,
367      * Content-MD5, and Content-Range). If your method cannot
368      * handle a content header, it must issue an error message
369      * (HTTP 501 - Not Implemented) and discard the request.
370      * For more information on HTTP 1.1, see RFC 2616
371      * <a href="http://www.ietf.org/rfc/rfc2616.txt"></a>.
372      *
373      * <p>This method does not need to be either safe or idempotent.
374      * Operations that <code>doPut</code> performs can have side
375      * effects for which the user can be held accountable. When using
376      * this method, it may be useful to save a copy of the
377      * affected URL in temporary storage.
378      *
379      * <p>If the HTTP PUT request is incorrectly formatted,
380      * <code>doPut</code> returns an HTTP "Bad Request" message.
381      *
382      *
383      * @param req  the {@link HttpServletRequest} object that
384      *      contains the request the client made of
385      *      the servlet
386      *
387      * @param resp  the {@link HttpServletResponse} object that
388      *      contains the response the servlet returns
389      *      to the client
390      *
391      * @exception IOException  if an input or output error occurs
392      *        while the servlet is handling the
393      *        PUT request
394      *
395      * @exception ServletException  if the request for the PUT
396      *          cannot be handled
397      *
398      */
399   
400     protected void doPut(HttpServletRequest req, HttpServletResponse resp)
401   throws ServletException, IOException
402     {
403   String protocol = req.getProtocol();
404   String msg = lStrings.getString("http.method_put_not_supported");
405   if (protocol.endsWith("1.1")) {
406       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
407   } else {
408       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
409   }
410     }
411 
412 
413 
414 
415     /**
416      * 
417      * Called by the server (via the <code>service</code> method)
418      * to allow a servlet to handle a DELETE request.
419      *
420      * The DELETE operation allows a client to remove a document
421      * or Web page from the server.
422      * 
423      * <p>This method does not need to be either safe
424      * or idempotent. Operations requested through
425      * DELETE can have side effects for which users
426      * can be held accountable. When using
427      * this method, it may be useful to save a copy of the
428      * affected URL in temporary storage.
429      *
430      * <p>If the HTTP DELETE request is incorrectly formatted,
431      * <code>doDelete</code> returns an HTTP "Bad Request"
432      * message.
433      *
434      *
435      * @param req  the {@link HttpServletRequest} object that
436      *      contains the request the client made of
437      *      the servlet
438      *
439      *
440      * @param resp  the {@link HttpServletResponse} object that
441      *      contains the response the servlet returns
442      *      to the client        
443      *
444      *
445      * @exception IOException  if an input or output error occurs
446      *        while the servlet is handling the
447      *        DELETE request
448      *
449      * @exception ServletException  if the request for the
450      *          DELETE cannot be handled
451      *
452      */
453      
454     protected void doDelete(HttpServletRequest req,
455           HttpServletResponse resp)
456   throws ServletException, IOException
457     {
458   String protocol = req.getProtocol();
459   String msg = lStrings.getString("http.method_delete_not_supported");
460   if (protocol.endsWith("1.1")) {
461       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
462   } else {
463       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
464   }
465     }
466     
467 
468     private static Method[] getAllDeclaredMethods(Class c) {
469 
470         if (c.equals(javax.servlet.http.HttpServlet.class)) {
471             return null;
472         }
473 
474         Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
475         Method[] thisMethods = c.getDeclaredMethods();
476   
477         if ((parentMethods != null) && (parentMethods.length > 0)) {
478             Method[] allMethods =
479                 new Method[parentMethods.length + thisMethods.length];
480       System.arraycopy(parentMethods, 0, allMethods, 0,
481                              parentMethods.length);
482       System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
483                              thisMethods.length);
484 
485       thisMethods = allMethods;
486   }
487 
488   return thisMethods;
489     }
490 
491 
492     /**
493      * Called by the server (via the <code>service</code> method)
494      * to allow a servlet to handle a OPTIONS request.
495      *
496      * The OPTIONS request determines which HTTP methods 
497      * the server supports and
498      * returns an appropriate header. For example, if a servlet
499      * overrides <code>doGet</code>, this method returns the
500      * following header:
501      *
502      * <p><code>Allow: GET, HEAD, TRACE, OPTIONS</code>
503      *
504      * <p>There's no need to override this method unless the
505      * servlet implements new HTTP methods, beyond those 
506      * implemented by HTTP 1.1.
507      *
508      * @param req  the {@link HttpServletRequest} object that
509      *      contains the request the client made of
510      *      the servlet
511      *
512      *
513      * @param resp  the {@link HttpServletResponse} object that
514      *      contains the response the servlet returns
515      *      to the client        
516      *
517      *
518      * @exception IOException  if an input or output error occurs
519      *        while the servlet is handling the
520      *        OPTIONS request
521      *
522      * @exception ServletException  if the request for the
523      *          OPTIONS cannot be handled
524      *
525      */
526          
527     protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
528   throws ServletException, IOException
529     {
530   Method[] methods = getAllDeclaredMethods(this.getClass());
531   
532   boolean ALLOW_GET = false;
533   boolean ALLOW_HEAD = false;
534   boolean ALLOW_POST = false;
535   boolean ALLOW_PUT = false;
536   boolean ALLOW_DELETE = false;
537   boolean ALLOW_TRACE = true;
538   boolean ALLOW_OPTIONS = true;
539   
540   for (int i=0; i<methods.length; i++) {
541       Method m = methods[i];
542       
543       if (m.getName().equals("doGet")) {
544     ALLOW_GET = true;
545     ALLOW_HEAD = true;
546       }
547       if (m.getName().equals("doPost")) 
548     ALLOW_POST = true;
549       if (m.getName().equals("doPut"))
550     ALLOW_PUT = true;
551       if (m.getName().equals("doDelete"))
552     ALLOW_DELETE = true;
553       
554   }
555   
556   String allow = null;
557   if (ALLOW_GET)
558       if (allow==null) allow=METHOD_GET;
559   if (ALLOW_HEAD)
560       if (allow==null) allow=METHOD_HEAD;
561       else allow += ", " + METHOD_HEAD;
562   if (ALLOW_POST)
563       if (allow==null) allow=METHOD_POST;
564       else allow += ", " + METHOD_POST;
565   if (ALLOW_PUT)
566       if (allow==null) allow=METHOD_PUT;
567       else allow += ", " + METHOD_PUT;
568   if (ALLOW_DELETE)
569       if (allow==null) allow=METHOD_DELETE;
570       else allow += ", " + METHOD_DELETE;
571   if (ALLOW_TRACE)
572       if (allow==null) allow=METHOD_TRACE;
573       else allow += ", " + METHOD_TRACE;
574   if (ALLOW_OPTIONS)
575       if (allow==null) allow=METHOD_OPTIONS;
576       else allow += ", " + METHOD_OPTIONS;
577   
578   resp.setHeader("Allow", allow);
579     }
580     
581     
582     
583     
584     /**
585      * Called by the server (via the <code>service</code> method)
586      * to allow a servlet to handle a TRACE request.
587      *
588      * A TRACE returns the headers sent with the TRACE
589      * request to the client, so that they can be used in
590      * debugging. There's no need to override this method. 
591      *
592      *
593      *
594      * @param req  the {@link HttpServletRequest} object that
595      *      contains the request the client made of
596      *      the servlet
597      *
598      *
599      * @param resp  the {@link HttpServletResponse} object that
600      *      contains the response the servlet returns
601      *      to the client        
602      *
603      *
604      * @exception IOException  if an input or output error occurs
605      *        while the servlet is handling the
606      *        TRACE request
607      *
608      * @exception ServletException  if the request for the
609      *          TRACE cannot be handled
610      *
611      */
612 
613     protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 
614   throws ServletException, IOException
615     {
616   
617   int responseLength;
618   
619   String CRLF = "\r\n";
620   String responseString = "TRACE "+ req.getRequestURI()+
621       " " + req.getProtocol();
622   
623   Enumeration reqHeaderEnum = req.getHeaderNames();
624   
625   while( reqHeaderEnum.hasMoreElements() ) {
626       String headerName = (String)reqHeaderEnum.nextElement();
627       responseString += CRLF + headerName + ": " +
628     req.getHeader(headerName); 
629   }
630   
631   responseString += CRLF;
632   
633   responseLength = responseString.length();
634   
635   resp.setContentType("message/http");
636   resp.setContentLength(responseLength);
637   ServletOutputStream out = resp.getOutputStream();
638   out.print(responseString);  
639   out.close();
640   return;
641     }    
642 
643 
644 
645 
646 
647     /**
648      *
649      * Receives standard HTTP requests from the public
650      * <code>service</code> method and dispatches
651      * them to the <code>do</code><i>XXX</i> methods defined in 
652      * this class. This method is an HTTP-specific version of the 
653      * {@link javax.servlet.Servlet#service} method. There's no
654      * need to override this method.
655      *
656      *
657      *
658      * @param req  the {@link HttpServletRequest} object that
659      *      contains the request the client made of
660      *      the servlet
661      *
662      *
663      * @param resp  the {@link HttpServletResponse} object that
664      *      contains the response the servlet returns
665      *      to the client        
666      *
667      *
668      * @exception IOException  if an input or output error occurs
669      *        while the servlet is handling the
670      *        HTTP request
671      *
672      * @exception ServletException  if the HTTP request
673      *          cannot be handled
674      * 
675      * @see         javax.servlet.Servlet#service
676      *
677      */
678 
679     protected void service(HttpServletRequest req, HttpServletResponse resp)
680   throws ServletException, IOException
681     {
682   String method = req.getMethod();
683 
684   if (method.equals(METHOD_GET)) {
685       long lastModified = getLastModified(req);
686       if (lastModified == -1) {
687     // servlet doesn't support if-modified-since, no reason
688     // to go through further expensive logic
689     doGet(req, resp);
690       } else {
691     long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
692     if (ifModifiedSince < (lastModified / 1000 * 1000)) {
693         // If the servlet mod time is later, call doGet()
694                     // Round down to the nearest second for a proper compare
695                     // A ifModifiedSince of -1 will always be less
696         maybeSetLastModified(resp, lastModified);
697         doGet(req, resp);
698     } else {
699         resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
700     }
701       }
702 
703   } else if (method.equals(METHOD_HEAD)) {
704       long lastModified = getLastModified(req);
705       maybeSetLastModified(resp, lastModified);
706       doHead(req, resp);
707 
708   } else if (method.equals(METHOD_POST)) {
709       doPost(req, resp);
710       
711   } else if (method.equals(METHOD_PUT)) {
712       doPut(req, resp);  
713       
714   } else if (method.equals(METHOD_DELETE)) {
715       doDelete(req, resp);
716       
717   } else if (method.equals(METHOD_OPTIONS)) {
718       doOptions(req,resp);
719       
720   } else if (method.equals(METHOD_TRACE)) {
721       doTrace(req,resp);
722       
723   } else {
724       //
725       // Note that this means NO servlet supports whatever
726       // method was requested, anywhere on this server.
727       //
728 
729       String errMsg = lStrings.getString("http.method_not_implemented");
730       Object[] errArgs = new Object[1];
731       errArgs[0] = method;
732       errMsg = MessageFormat.format(errMsg, errArgs);
733       
734       resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
735   }
736     }
737     
738 
739 
740 
741 
742     /*
743      * Sets the Last-Modified entity header field, if it has not
744      * already been set and if the value is meaningful.  Called before
745      * doGet, to ensure that headers are set before response data is
746      * written.  A subclass might have set this header already, so we
747      * check.
748      */
749 
750     private void maybeSetLastModified(HttpServletResponse resp,
751               long lastModified) {
752   if (resp.containsHeader(HEADER_LASTMOD))
753       return;
754   if (lastModified >= 0)
755       resp.setDateHeader(HEADER_LASTMOD, lastModified);
756     }
757    
758    
759    
760     
761     /**
762      *
763      * Dispatches client requests to the protected
764      * <code>service</code> method. There's no need to
765      * override this method.
766      *
767      * 
768      * @param req  the {@link HttpServletRequest} object that
769      *      contains the request the client made of
770      *      the servlet
771      *
772      *
773      * @param res  the {@link HttpServletResponse} object that
774      *      contains the response the servlet returns
775      *      to the client        
776      *
777      *
778      * @exception IOException  if an input or output error occurs
779      *        while the servlet is handling the
780      *        HTTP request
781      *
782      * @exception ServletException  if the HTTP request cannot
783      *          be handled
784      *
785      * 
786      * @see javax.servlet.Servlet#service
787      *
788      */
789 
790     public void service(ServletRequest req, ServletResponse res)
791   throws ServletException, IOException
792     {
793   HttpServletRequest  request;
794   HttpServletResponse  response;
795   
796   try {
797       request = (HttpServletRequest) req;
798       response = (HttpServletResponse) res;
799   } catch (ClassCastException e) {
800       throw new ServletException("non-HTTP request or response");
801   }
802   service(request, response);
803     }
804 }
805 
806 
807 
808 
809 /*
810  * A response that includes no body, for use in (dumb) "HEAD" support.
811  * This just swallows that body, counting the bytes in order to set
812  * the content length appropriately.  All other methods delegate directly
813  * to the HTTP Servlet Response object used to construct this one.
814  */
815 // file private
816 class NoBodyResponse implements HttpServletResponse {
817     private HttpServletResponse    resp;
818     private NoBodyOutputStream    noBody;
819     private PrintWriter      writer;
820     private boolean      didSetContentLength;
821 
822     // file private
823     NoBodyResponse(HttpServletResponse r) {
824   resp = r;
825   noBody = new NoBodyOutputStream();
826     }
827 
828     // file private
829     void setContentLength() {
830   if (!didSetContentLength)
831     resp.setContentLength(noBody.getContentLength());
832     }
833 
834 
835     // SERVLET RESPONSE interface methods
836 
837     public void setContentLength(int len) {
838   resp.setContentLength(len);
839   didSetContentLength = true;
840     }
841 
842     public void setCharacterEncoding(String charset)
843       { resp.setCharacterEncoding(charset); }
844 
845     public void setContentType(String type)
846       { resp.setContentType(type); }
847 
848     public String getContentType()
849       { return resp.getContentType(); }
850 
851     public ServletOutputStream getOutputStream() throws IOException
852       { return noBody; }
853 
854     public String getCharacterEncoding()
855   { return resp.getCharacterEncoding(); }
856 
857     public PrintWriter getWriter() throws UnsupportedEncodingException
858     {
859   if (writer == null) {
860       OutputStreamWriter  w;
861 
862       w = new OutputStreamWriter(noBody, getCharacterEncoding());
863       writer = new PrintWriter(w);
864   }
865   return writer;
866     }
867 
868     public void setBufferSize(int size) throws IllegalStateException
869       { resp.setBufferSize(size); }
870 
871     public int getBufferSize()
872       { return resp.getBufferSize(); }
873 
874     public void reset() throws IllegalStateException
875       { resp.reset(); }
876       
877       public void resetBuffer() throws IllegalStateException
878       { resp.resetBuffer(); }
879 
880     public boolean isCommitted()
881       { return resp.isCommitted(); }
882 
883     public void flushBuffer() throws IOException
884       { resp.flushBuffer(); }
885 
886     public void setLocale(Locale loc)
887       { resp.setLocale(loc); }
888 
889     public Locale getLocale()
890       { return resp.getLocale(); }
891 
892 
893     // HTTP SERVLET RESPONSE interface methods
894 
895     public void addCookie(Cookie cookie)
896       { resp.addCookie(cookie); }
897 
898     public boolean containsHeader(String name)
899       { return resp.containsHeader(name); }
900 
901     /** @deprecated */
902     public void setStatus(int sc, String sm)
903       { resp.setStatus(sc, sm); }
904 
905     public void setStatus(int sc)
906       { resp.setStatus(sc); }
907 
908     public void setHeader(String name, String value)
909       { resp.setHeader(name, value); }
910 
911     public void setIntHeader(String name, int value)
912       { resp.setIntHeader(name, value); }
913 
914     public void setDateHeader(String name, long date)
915       { resp.setDateHeader(name, date); }
916 
917     public void sendError(int sc, String msg) throws IOException
918       { resp.sendError(sc, msg); }
919 
920     public void sendError(int sc) throws IOException
921       { resp.sendError(sc); }
922 
923     public void sendRedirect(String location) throws IOException
924       { resp.sendRedirect(location); }
925     
926     public String encodeURL(String url) 
927       { return resp.encodeURL(url); }
928 
929     public String encodeRedirectURL(String url)
930       { return resp.encodeRedirectURL(url); }
931       
932     public void addHeader(String name, String value)
933       { resp.addHeader(name, value); }
934       
935     public void addDateHeader(String name, long value)
936       { resp.addDateHeader(name, value); }
937       
938     public void addIntHeader(String name, int value)
939       { resp.addIntHeader(name, value); }
940       
941       
942       
943 
944     /**
945      * @deprecated  As of Version 2.1, replaced by
946      *       {@link HttpServletResponse#encodeURL}.
947      *
948      */
949      
950      
951     public String encodeUrl(String url) 
952       { return this.encodeURL(url); }
953       
954       
955       
956       
957       
958       
959       
960 
961     /**
962      * @deprecated  As of Version 2.1, replaced by
963      *      {@link HttpServletResponse#encodeRedirectURL}.
964      *
965      */
966      
967      
968     public String encodeRedirectUrl(String url)
969       { return this.encodeRedirectURL(url); }
970 
971 }
972 
973 
974 
975 
976 
977 
978 
979 /*
980  * Servlet output stream that gobbles up all its data.
981  */
982  
983 // file private
984 class NoBodyOutputStream extends ServletOutputStream {
985 
986     private static final String LSTRING_FILE =
987   "javax.servlet.http.LocalStrings";
988     private static ResourceBundle lStrings =
989   ResourceBundle.getBundle(LSTRING_FILE);
990 
991     private int    contentLength = 0;
992 
993     // file private
994     NoBodyOutputStream() {}
995 
996     // file private
997     int getContentLength() {
998   return contentLength;
999     }
1000
1001    public void write(int b) {
1002  contentLength++;
1003    }
1004
1005    public void write(byte buf[], int offset, int len)
1006  throws IOException
1007    {
1008  if (len >= 0) {
1009      contentLength += len;
1010  } else {
1011      // XXX
1012      // isn't this really an IllegalArgumentException?
1013      
1014      String msg = lStrings.getString("err.io.negativelength");
1015      throw new IOException("negative length");
1016  }
1017    }
1018}