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