001    /*
002    * Copyright 2004 The Apache Software Foundation
003    *
004    * Licensed under the Apache License, Version 2.0 (the "License");
005    * you may not use this file except in compliance with the License.
006    * You may obtain a copy of the License at
007    *
008    *     http://www.apache.org/licenses/LICENSE-2.0
009    *
010    * Unless required by applicable law or agreed to in writing, software
011    * distributed under the License is distributed on an "AS IS" BASIS,
012    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013    * See the License for the specific language governing permissions and
014    * limitations under the License.
015    */
016    package javax.servlet.http;
017    
018    import java.io.IOException;
019    import java.io.PrintWriter;
020    import java.io.OutputStreamWriter;
021    import java.io.UnsupportedEncodingException;
022    import java.lang.reflect.Method;
023    import java.text.MessageFormat;
024    import java.util.Enumeration;
025    import java.util.Locale;
026    import java.util.ResourceBundle;
027    
028    import javax.servlet.GenericServlet;
029    import javax.servlet.ServletException;
030    import javax.servlet.ServletOutputStream;
031    import javax.servlet.ServletRequest;
032    import javax.servlet.ServletResponse;
033    
034    
035    /**
036     *
037     * Provides an abstract class to be subclassed to create
038     * an HTTP servlet suitable for a Web site. A subclass of
039     * <code>HttpServlet</code> must override at least 
040     * one method, usually one of these:
041     *
042     * <ul>
043     * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
044     * <li> <code>doPost</code>, for HTTP POST requests
045     * <li> <code>doPut</code>, for HTTP PUT requests
046     * <li> <code>doDelete</code>, for HTTP DELETE requests
047     * <li> <code>init</code> and <code>destroy</code>, 
048     * to manage resources that are held for the life of the servlet
049     * <li> <code>getServletInfo</code>, which the servlet uses to
050     * provide information about itself 
051     * </ul>
052     *
053     * <p>There's almost no reason to override the <code>service</code>
054     * method. <code>service</code> handles standard HTTP
055     * requests by dispatching them to the handler methods
056     * for each HTTP request type (the <code>do</code><i>XXX</i>
057     * methods listed above).
058     *
059     * <p>Likewise, there's almost no reason to override the 
060     * <code>doOptions</code> and <code>doTrace</code> methods.
061     * 
062     * <p>Servlets typically run on multithreaded servers,
063     * so be aware that a servlet must handle concurrent
064     * requests and be careful to synchronize access to shared resources.
065     * Shared resources include in-memory data such as
066     * instance or class variables and external objects
067     * such as files, database connections, and network 
068     * connections.
069     * See the
070     * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
071     * Java Tutorial on Multithreaded Programming</a> for more
072     * information on handling multiple threads in a Java program.
073     *
074     * @author      Various
075     * @version     $Version$
076     *
077     */
078    
079    
080    
081    public abstract class HttpServlet extends GenericServlet
082        implements java.io.Serializable
083    {
084        private static final String METHOD_DELETE = "DELETE";
085        private static final String METHOD_HEAD = "HEAD";
086        private static final String METHOD_GET = "GET";
087        private static final String METHOD_OPTIONS = "OPTIONS";
088        private static final String METHOD_POST = "POST";
089        private static final String METHOD_PUT = "PUT";
090        private static final String METHOD_TRACE = "TRACE";
091    
092        private static final String HEADER_IFMODSINCE = "If-Modified-Since";
093        private static final String HEADER_LASTMOD = "Last-Modified";
094        
095        private static final String LSTRING_FILE =
096            "javax.servlet.http.LocalStrings";
097        private static ResourceBundle lStrings =
098            ResourceBundle.getBundle(LSTRING_FILE);
099       
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    }