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