View Javadoc

1   /**
2    *
3    * Copyright 2003-2004 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  //
19  // This source code implements specifications defined by the Java
20  // Community Process. In order to remain compliant with the specification
21  // DO NOT add / change / or delete method signatures!
22  //
23  
24  package javax.servlet.http;
25  
26  import java.io.IOException;
27  import java.io.OutputStreamWriter;
28  import java.io.PrintWriter;
29  import java.io.UnsupportedEncodingException;
30  import java.lang.reflect.Method;
31  import java.text.MessageFormat;
32  import java.util.Enumeration;
33  import java.util.Locale;
34  import java.util.ResourceBundle;
35  import javax.servlet.GenericServlet;
36  import javax.servlet.ServletException;
37  import javax.servlet.ServletOutputStream;
38  import javax.servlet.ServletRequest;
39  import javax.servlet.ServletResponse;
40  
41  
42  /**
43   * Provides an abstract class to be subclassed to create
44   * an HTTP servlet suitable for a Web site. A subclass of
45   * <code>HttpServlet</code> must override at least
46   * one method, usually one of these:
47   *
48   * <ul>
49   * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
50   * <li> <code>doPost</code>, for HTTP POST requests
51   * <li> <code>doPut</code>, for HTTP PUT requests
52   * <li> <code>doDelete</code>, for HTTP DELETE requests
53   * <li> <code>init</code> and <code>destroy</code>,
54   * to manage resources that are held for the life of the servlet
55   * <li> <code>getServletInfo</code>, which the servlet uses to
56   * provide information about itself
57   * </ul>
58   *
59   * <p>There's almost no reason to override the <code>service</code>
60   * method. <code>service</code> handles standard HTTP
61   * requests by dispatching them to the handler methods
62   * for each HTTP request type (the <code>do</code><i>XXX</i>
63   * methods listed above).
64   *
65   * <p>Likewise, there's almost no reason to override the
66   * <code>doOptions</code> and <code>doTrace</code> methods.
67   *
68   * <p>Servlets typically run on multithreaded servers,
69   * so be aware that a servlet must handle concurrent
70   * requests and be careful to synchronize access to shared resources.
71   * Shared resources include in-memory data such as
72   * instance or class variables and external objects
73   * such as files, database connections, and network
74   * connections.
75   * See the
76   * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
77   * Java Tutorial on Multithreaded Programming</a> for more
78   * information on handling multiple threads in a Java program.
79   *
80   * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
81   */
82  public abstract class HttpServlet extends GenericServlet
83          implements java.io.Serializable {
84      private static final String METHOD_DELETE = "DELETE";
85      private static final String METHOD_HEAD = "HEAD";
86      private static final String METHOD_GET = "GET";
87      private static final String METHOD_OPTIONS = "OPTIONS";
88      private static final String METHOD_POST = "POST";
89      private static final String METHOD_PUT = "PUT";
90      private static final String METHOD_TRACE = "TRACE";
91  
92      private static final String HEADER_IFMODSINCE = "If-Modified-Since";
93      private static final String HEADER_LASTMOD = "Last-Modified";
94  
95      private static final String LSTRING_FILE =
96              "javax.servlet.http.LocalStrings";
97      private static ResourceBundle lStrings =
98              ResourceBundle.getBundle(LSTRING_FILE);
99  
100     /**
101      * 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 }