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