你的位置:首页 > Java教程

[Java教程]HttpServlet中的2种请求处理方式


HttpServlet继承于GenericServlet,,专门用于处理Http的请求:

  方法一:  HttpServlet复写了GenericServlet的service(ServletRequest rq,ServletResponse rp)并同时提供了了一个service(HttpServletRequest req,HttpServletRsponse rep),,,在service(ServletRequest rq,ServletResponse rp)方法内部调用了service(HttpServletRequest req,HttpServletRsponse rep),这样在服务器自动执行service(ServletRequest rq,ServletResponse rp)该生命周期方法时,也会同时调用到service(HttpServletRequest req,HttpServletRsponse rep)方法,而我们只需要子类中复写service(HttpServletRequest req,HttpServletRsponse rep)方法,在其中编写处理请求的代码,,[注]:在子类复写service(HttpServletRequest req,HttpServletRsponse rep)方法时,不能再该方法内写super.service(req,rep)调用该方法会输出一个错误信息.

  方法二:  HttpServlet复写了GenericServlet的service(ServletRequest rq,ServletResponse rp)并同时提供了了一个service(HttpServletRequest req,HttpServletRsponse rep),,,在service(ServletRequest rq,ServletResponse rp)方法内部调用了service(HttpServletRequest req,HttpServletRsponse rep),这样在服务器自动执行service(ServletRequest rq,ServletResponse rp)该生命周期方法时,也会同时调用到service(HttpServletRequest req,HttpServletRsponse rep)方法,,同时在service(HttpServletRequest req,HttpServletRsponse rep)方法内,还对请求类型进行了判断,如果根据不同的请求类型,在该方法内有调用了不同的方法对不同的请求类型进行处理,,,如针对get的doGet()方法,针对post的doPost()方法,,,,此时我们可以仅仅只在子类中分别复写针对不同请求类型的处理方法,如doGet()和doPost()等方法,,,这样即可在服务处理请求时根据service(ServletRequest rq,ServletResponse rp)------>service(HttpServletRequest req,HttpServletRsponse rep)的顺序自动找到相应的doGet()或doPost()方法进行对应的请求类型的处理...[注]:在子类中复写doGet()和doPost()等方法时不能在其方法内写super.doGet()或super.doPost()等方法,,,同样的,该调用同样是输出一个错误信息.

                          HttpServlet源代码

 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  * @author Various 74 */ 75 public abstract class HttpServlet extends GenericServlet { 76  77   private static final long serialVersionUID = 1L; 78  79   private static final String METHOD_DELETE = "DELETE"; 80   private static final String METHOD_HEAD = "HEAD"; 81   private static final String METHOD_GET = "GET"; 82   private static final String METHOD_OPTIONS = "OPTIONS"; 83   private static final String METHOD_POST = "POST"; 84   private static final String METHOD_PUT = "PUT"; 85   private static final String METHOD_TRACE = "TRACE"; 86  87   private static final String HEADER_IFMODSINCE = "If-Modified-Since"; 88   private static final String HEADER_LASTMOD = "Last-Modified"; 89  90   private static final String LSTRING_FILE = 91     "javax.servlet.http.LocalStrings"; 92   private static ResourceBundle lStrings = 93     ResourceBundle.getBundle(LSTRING_FILE); 94  95  96   /** 97    * Does nothing, because this is an abstract class. 98   */ 99   public HttpServlet() {100     // NOOP101   }102 103 104   /**105    * Called by the server (via the <code>service</code> method) to106    * allow a servlet to handle a GET request.107    *108    * <p>Overriding this method to support a GET request also109    * automatically supports an HTTP HEAD request. A HEAD110    * request is a GET request that returns no body in the111    * response, only the request header fields.112    *113    * <p>When overriding this method, read the request data,114    * write the response headers, get the response's writer or115    * output stream object, and finally, write the response data.116    * It's best to include content type and encoding. When using117    * a <code>PrintWriter</code> object to return the response,118    * set the content type before accessing the119    * <code>PrintWriter</code> object.120    *121    * <p>The servlet container must write the headers before122    * committing the response, because in HTTP the headers must be sent123    * before the response body.124    *125    * <p>Where possible, set the Content-Length header (with the126    * {@link javax.servlet.ServletResponse#setContentLength} method),127    * to allow the servlet container to use a persistent connection128    * to return its response to the client, improving performance.129    * The content length is automatically set if the entire response fits130    * inside the response buffer.131    *132    * <p>When using HTTP 1.1 chunked encoding (which means that the response133    * has a Transfer-Encoding header), do not set the Content-Length header.134    *135    * <p>The GET method should be safe, that is, without136    * any side effects for which users are held responsible.137    * For example, most form queries have no side effects.138    * If a client request is intended to change stored data,139    * the request should use some other HTTP method.140    *141    * <p>The GET method should also be idempotent, meaning142    * that it can be safely repeated. Sometimes making a143    * method safe also makes it idempotent. For example,144    * repeating queries is both safe and idempotent, but145    * buying a product online or modifying data is neither146    * safe nor idempotent.147    *148    * <p>If the request is incorrectly formatted, <code>doGet</code>149    * returns an HTTP "Bad Request" message.150    *151    * @param req  an {@link HttpServletRequest} object that152    *         contains the request the client has made153    *         of the servlet154    *155    * @param resp an {@link HttpServletResponse} object that156    *         contains the response the servlet sends157    *         to the client158    *159    * @exception IOException  if an input or output error is160    *               detected when the servlet handles161    *               the GET request162    *163    * @exception ServletException if the request for the GET164    *                 could not be handled165    *166    * @see javax.servlet.ServletResponse#setContentType167   */168   protected void doGet(HttpServletRequest req, HttpServletResponse resp)169     throws ServletException, IOException170   {171     String protocol = req.getProtocol();172     String msg = lStrings.getString("http.method_get_not_supported");173     if (protocol.endsWith("1.1")) {174       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);175     } else {176       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);177     }178   }179 180 181   /**182    * Returns the time the <code>HttpServletRequest</code>183    * object was last modified,184    * in milliseconds since midnight January 1, 1970 GMT.185    * If the time is unknown, this method returns a negative186    * number (the default).187    *188    * <p>Servlets that support HTTP GET requests and can quickly determine189    * their last modification time should override this method.190    * This makes browser and proxy caches work more effectively,191    * reducing the load on server and network resources.192    *193    * @param req  the <code>HttpServletRequest</code>194    *         object that is sent to the servlet195    *196    * @return a <code>long</code> integer specifying197    *       the time the <code>HttpServletRequest</code>198    *       object was last modified, in milliseconds199    *       since midnight, January 1, 1970 GMT, or200    *       -1 if the time is not known201   */202   protected long getLastModified(HttpServletRequest req) {203     return -1;204   }205 206 207   /**208    * <p>Receives an HTTP HEAD request from the protected209    * <code>service</code> method and handles the210    * request.211    * The client sends a HEAD request when it wants212    * to see only the headers of a response, such as213    * Content-Type or Content-Length. The HTTP HEAD214    * method counts the output bytes in the response215    * to set the Content-Length header accurately.216    *217    * <p>If you override this method, you can avoid computing218    * the response body and just set the response headers219    * directly to improve performance. Make sure that the220    * <code>doHead</code> method you write is both safe221    * and idempotent (that is, protects itself from being222    * called multiple times for one HTTP HEAD request).223    *224    * <p>If the HTTP HEAD request is incorrectly formatted,225    * <code>doHead</code> returns an HTTP "Bad Request"226    * message.227    *228    * @param req  the request object that is passed to the servlet229    *230    * @param resp the response object that the servlet231    *         uses to return the headers to the client232    *233    * @exception IOException  if an input or output error occurs234    *235    * @exception ServletException if the request for the HEAD236    *                 could not be handled237   */238   protected void doHead(HttpServletRequest req, HttpServletResponse resp)239     throws ServletException, IOException {240 241     NoBodyResponse response = new NoBodyResponse(resp);242 243     doGet(req, response);244     response.setContentLength();245   }246 247 248   /**249    * Called by the server (via the <code>service</code> method)250    * to allow a servlet to handle a POST request.251    *252    * The HTTP POST method allows the client to send253    * data of unlimited length to the Web server a single time254    * and is useful when posting information such as255    * credit card numbers.256    *257    * <p>When overriding this method, read the request data,258    * write the response headers, get the response's writer or output259    * stream object, and finally, write the response data. It's best260    * to include content type and encoding. When using a261    * <code>PrintWriter</code> object to return the response, set the262    * content type before accessing the <code>PrintWriter</code> object.263    *264    * <p>The servlet container must write the headers before committing the265    * response, because in HTTP the headers must be sent before the266    * response body.267    *268    * <p>Where possible, set the Content-Length header (with the269    * {@link javax.servlet.ServletResponse#setContentLength} method),270    * to allow the servlet container to use a persistent connection271    * to return its response to the client, improving performance.272    * The content length is automatically set if the entire response fits273    * inside the response buffer.274    *275    * <p>When using HTTP 1.1 chunked encoding (which means that the response276    * has a Transfer-Encoding header), do not set the Content-Length header.277    *278    * <p>This method does not need to be either safe or idempotent.279    * Operations requested through POST can have side effects for280    * which the user can be held accountable, for example,281    * updating stored data or buying items online.282    *283    * <p>If the HTTP POST request is incorrectly formatted,284    * <code>doPost</code> returns an HTTP "Bad Request" message.285    *286    *287    * @param req  an {@link HttpServletRequest} object that288    *         contains the request the client has made289    *         of the servlet290    *291    * @param resp an {@link HttpServletResponse} object that292    *         contains the response the servlet sends293    *         to the client294    *295    * @exception IOException  if an input or output error is296    *               detected when the servlet handles297    *               the request298    *299    * @exception ServletException if the request for the POST300    *                 could not be handled301    *302    * @see javax.servlet.ServletOutputStream303    * @see javax.servlet.ServletResponse#setContentType304   */305   protected void doPost(HttpServletRequest req, HttpServletResponse resp)306     throws ServletException, IOException {307 308     String protocol = req.getProtocol();309     String msg = lStrings.getString("http.method_post_not_supported");310     if (protocol.endsWith("1.1")) {311       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);312     } else {313       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);314     }315   }316 317 318   /**319    * Called by the server (via the <code>service</code> method)320    * to allow a servlet to handle a PUT request.321    *322    * The PUT operation allows a client to323    * place a file on the server and is similar to324    * sending a file by FTP.325    *326    * <p>When overriding this method, leave intact327    * any content headers sent with the request (including328    * Content-Length, Content-Type, Content-Transfer-Encoding,329    * Content-Encoding, Content-Base, Content-Language, Content-Location,330    * Content-MD5, and Content-Range). If your method cannot331    * handle a content header, it must issue an error message332    * (HTTP 501 - Not Implemented) and discard the request.333    * For more information on HTTP 1.1, see RFC 2616334    * <a href="http://www.ietf.org/rfc/rfc2616.txt"></a>.335    *336    * <p>This method does not need to be either safe or idempotent.337    * Operations that <code>doPut</code> performs can have side338    * effects for which the user can be held accountable. When using339    * this method, it may be useful to save a copy of the340    * affected URL in temporary storage.341    *342    * <p>If the HTTP PUT request is incorrectly formatted,343    * <code>doPut</code> returns an HTTP "Bad Request" message.344    *345    * @param req  the {@link HttpServletRequest} object that346    *         contains the request the client made of347    *         the servlet348    *349    * @param resp the {@link HttpServletResponse} object that350    *         contains the response the servlet returns351    *         to the client352    *353    * @exception IOException  if an input or output error occurs354    *               while the servlet is handling the355    *               PUT request356    *357    * @exception ServletException if the request for the PUT358    *                 cannot be handled359   */360   protected void doPut(HttpServletRequest req, HttpServletResponse resp)361     throws ServletException, IOException {362 363     String protocol = req.getProtocol();364     String msg = lStrings.getString("http.method_put_not_supported");365     if (protocol.endsWith("1.1")) {366       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);367     } else {368       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);369     }370   }371 372 373   /**374    * Called by the server (via the <code>service</code> method)375    * to allow a servlet to handle a DELETE request.376    *377    * The DELETE operation allows a client to remove a document378    * or Web page from the server.379    *380    * <p>This method does not need to be either safe381    * or idempotent. Operations requested through382    * DELETE can have side effects for which users383    * can be held accountable. When using384    * this method, it may be useful to save a copy of the385    * affected URL in temporary storage.386    *387    * <p>If the HTTP DELETE request is incorrectly formatted,388    * <code>doDelete</code> returns an HTTP "Bad Request"389    * message.390    *391    * @param req  the {@link HttpServletRequest} object that392    *         contains the request the client made of393    *         the servlet394    *395    *396    * @param resp the {@link HttpServletResponse} object that397    *         contains the response the servlet returns398    *         to the client399    *400    * @exception IOException  if an input or output error occurs401    *               while the servlet is handling the402    *               DELETE request403    *404    * @exception ServletException if the request for the405    *                 DELETE cannot be handled406   */407   protected void doDelete(HttpServletRequest req,408               HttpServletResponse resp)409     throws ServletException, IOException {410 411     String protocol = req.getProtocol();412     String msg = lStrings.getString("http.method_delete_not_supported");413     if (protocol.endsWith("1.1")) {414       resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);415     } else {416       resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);417     }418   }419 420 421   private static Method[] getAllDeclaredMethods(Class<?> c) {422 423     if (c.equals(javax.servlet.http.HttpServlet.class)) {424       return null;425     }426 427     Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());428     Method[] thisMethods = c.getDeclaredMethods();429 430     if ((parentMethods != null) && (parentMethods.length > 0)) {431       Method[] allMethods =432         new Method[parentMethods.length + thisMethods.length];433       System.arraycopy(parentMethods, 0, allMethods, 0,434                parentMethods.length);435       System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,436                thisMethods.length);437 438       thisMethods = allMethods;439     }440 441     return thisMethods;442   }443 444 445   /**446    * Called by the server (via the <code>service</code> method)447    * to allow a servlet to handle a OPTIONS request.448    *449    * The OPTIONS request determines which HTTP methods450    * the server supports and451    * returns an appropriate header. For example, if a servlet452    * overrides <code>doGet</code>, this method returns the453    * following header:454    *455    * <p><code>Allow: GET, HEAD, TRACE, OPTIONS</code>456    *457    * <p>There's no need to override this method unless the458    * servlet implements new HTTP methods, beyond those459    * implemented by HTTP 1.1.460    *461    * @param req  the {@link HttpServletRequest} object that462    *         contains the request the client made of463    *         the servlet464    *465    * @param resp the {@link HttpServletResponse} object that466    *         contains the response the servlet returns467    *         to the client468    *469    * @exception IOException  if an input or output error occurs470    *               while the servlet is handling the471    *               OPTIONS request472    *473    * @exception ServletException if the request for the474    *                 OPTIONS cannot be handled475   */476   protected void doOptions(HttpServletRequest req,477       HttpServletResponse resp)478     throws ServletException, IOException {479 480     Method[] methods = getAllDeclaredMethods(this.getClass());481 482     boolean ALLOW_GET = false;483     boolean ALLOW_HEAD = false;484     boolean ALLOW_POST = false;485     boolean ALLOW_PUT = false;486     boolean ALLOW_DELETE = false;487     boolean ALLOW_TRACE = true;488     boolean ALLOW_OPTIONS = true;489 490     for (int i=0; i<methods.length; i++) {491       Method m = methods[i];492 493       if (m.getName().equals("doGet")) {494         ALLOW_GET = true;495         ALLOW_HEAD = true;496       }497       if (m.getName().equals("doPost"))498         ALLOW_POST = true;499       if (m.getName().equals("doPut"))500         ALLOW_PUT = true;501       if (m.getName().equals("doDelete"))502         ALLOW_DELETE = true;503     }504 505     String allow = null;506     if (ALLOW_GET)507       allow=METHOD_GET;508     if (ALLOW_HEAD)509       if (allow==null) allow=METHOD_HEAD;510       else allow += ", " + METHOD_HEAD;511     if (ALLOW_POST)512       if (allow==null) allow=METHOD_POST;513       else allow += ", " + METHOD_POST;514     if (ALLOW_PUT)515       if (allow==null) allow=METHOD_PUT;516       else allow += ", " + METHOD_PUT;517     if (ALLOW_DELETE)518       if (allow==null) allow=METHOD_DELETE;519       else allow += ", " + METHOD_DELETE;520     if (ALLOW_TRACE)521       if (allow==null) allow=METHOD_TRACE;522       else allow += ", " + METHOD_TRACE;523     if (ALLOW_OPTIONS)524       if (allow==null) allow=METHOD_OPTIONS;525       else allow += ", " + METHOD_OPTIONS;526 527     resp.setHeader("Allow", allow);528   }529 530 531   /**532    * Called by the server (via the <code>service</code> method)533    * to allow a servlet to handle a TRACE request.534    *535    * A TRACE returns the headers sent with the TRACE536    * request to the client, so that they can be used in537    * debugging. There's no need to override this method.538    *539    * @param req  the {@link HttpServletRequest} object that540    *         contains the request the client made of541    *         the servlet542    *543    * @param resp the {@link HttpServletResponse} object that544    *         contains the response the servlet returns545    *         to the client546    *547    * @exception IOException  if an input or output error occurs548    *               while the servlet is handling the549    *               TRACE request550    *551    * @exception ServletException if the request for the552    *                 TRACE cannot be handled553   */554   protected void doTrace(HttpServletRequest req, HttpServletResponse resp)555     throws ServletException, IOException556   {557 558     int responseLength;559 560     String CRLF = "\r\n";561     StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI())562       .append(" ").append(req.getProtocol());563 564     Enumeration<String> reqHeaderEnum = req.getHeaderNames();565 566     while( reqHeaderEnum.hasMoreElements() ) {567       String headerName = reqHeaderEnum.nextElement();568       buffer.append(CRLF).append(headerName).append(": ")569         .append(req.getHeader(headerName));570     }571 572     buffer.append(CRLF);573 574     responseLength = buffer.length();575 576     resp.setContentType("message/http");577     resp.setContentLength(responseLength);578     ServletOutputStream out = resp.getOutputStream();579     out.print(buffer.toString());580     out.close();581     return;582   }583 584 585   /**586    * Receives standard HTTP requests from the public587    * <code>service</code> method and dispatches588    * them to the <code>do</code><i>Method</i> methods defined in589    * this class. This method is an HTTP-specific version of the590    * {@link javax.servlet.Servlet#service} method. There's no591    * need to override this method.592    *593    * @param req  the {@link HttpServletRequest} object that594    *         contains the request the client made of595    *         the servlet596    *597    * @param resp the {@link HttpServletResponse} object that598    *         contains the response the servlet returns599    *         to the client600    *601    * @exception IOException  if an input or output error occurs602    *               while the servlet is handling the603    *               HTTP request604    *605    * @exception ServletException if the HTTP request606    *                 cannot be handled607    *608    * @see javax.servlet.Servlet#service609   */610   protected void service(HttpServletRequest req, HttpServletResponse resp)611     throws ServletException, IOException {612 613     String method = req.getMethod();614 615     if (method.equals(METHOD_GET)) {616       long lastModified = getLastModified(req);617       if (lastModified == -1) {618         // servlet doesn't support if-modified-since, no reason619         // to go through further expensive logic620         doGet(req, resp);621       } else {622         long ifModifiedSince;623         try {624           ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);625         } catch (IllegalArgumentException iae) {626           // Invalid date header - proceed as if none was set627           ifModifiedSince = -1;628         }629         if (ifModifiedSince < (lastModified / 1000 * 1000)) {630           // If the servlet mod time is later, call doGet()631           // Round down to the nearest second for a proper compare632           // A ifModifiedSince of -1 will always be less633           maybeSetLastModified(resp, lastModified);634           doGet(req, resp);635         } else {636           resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);637         }638       }639 640     } else if (method.equals(METHOD_HEAD)) {641       long lastModified = getLastModified(req);642       maybeSetLastModified(resp, lastModified);643       doHead(req, resp);644 645     } else if (method.equals(METHOD_POST)) {646       doPost(req, resp);647 648     } else if (method.equals(METHOD_PUT)) {649       doPut(req, resp);650 651     } else if (method.equals(METHOD_DELETE)) {652       doDelete(req, resp);653 654     } else if (method.equals(METHOD_OPTIONS)) {655       doOptions(req,resp);656 657     } else if (method.equals(METHOD_TRACE)) {658       doTrace(req,resp);659 660     } else {661       //662       // Note that this means NO servlet supports whatever663       // method was requested, anywhere on this server.664       //665 666       String errMsg = lStrings.getString("http.method_not_implemented");667       Object[] errArgs = new Object[1];668       errArgs[0] = method;669       errMsg = MessageFormat.format(errMsg, errArgs);670 671       resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);672     }673   }674 675 676   /*677    * Sets the Last-Modified entity header field, if it has not678    * already been set and if the value is meaningful. Called before679    * doGet, to ensure that headers are set before response data is680    * written. A subclass might have set this header already, so we681    * check.682   */683   private void maybeSetLastModified(HttpServletResponse resp,684                    long lastModified) {685     if (resp.containsHeader(HEADER_LASTMOD))686       return;687     if (lastModified >= 0)688       resp.setDateHeader(HEADER_LASTMOD, lastModified);689   }690 691 692   /**693    * Dispatches client requests to the protected694    * <code>service</code> method. There's no need to695    * override this method.696    *697    * @param req  the {@link HttpServletRequest} object that698    *         contains the request the client made of699    *         the servlet700    *701    * @param res  the {@link HttpServletResponse} object that702    *         contains the response the servlet returns703    *         to the client704    *705    * @exception IOException  if an input or output error occurs706    *               while the servlet is handling the707    *               HTTP request708    *709    * @exception ServletException if the HTTP request cannot710    *                 be handled711    *712    * @see javax.servlet.Servlet#service713   */714   @Override715   public void service(ServletRequest req, ServletResponse res)716     throws ServletException, IOException {717 718     HttpServletRequest request;719     HttpServletResponse response;720 721     try {722       request = (HttpServletRequest) req;723       response = (HttpServletResponse) res;724     } catch (ClassCastException e) {725       throw new ServletException("non-HTTP request or response");726     }727     service(request, response);728   }729 }730 731 732 /*733  * A response wrapper for use in (dumb) "HEAD" support.734  * This just swallows that body, counting the bytes in order to set735  * the content length appropriately. All other methods delegate to the736  * wrapped HTTP Servlet Response object.737 */738 // file private739 class NoBodyResponse extends HttpServletResponseWrapper {740   private NoBodyOutputStream        noBody;741   private PrintWriter            writer;742   private boolean            didSetContentLength;743 744   // file private745   NoBodyResponse(HttpServletResponse r) {746     super(r);747     noBody = new NoBodyOutputStream();748   }749 750   // file private751   void setContentLength() {752     if (!didSetContentLength) {753       if (writer != null) {754         writer.flush();755       }756       super.setContentLength(noBody.getContentLength());757     }758   }759 760 761   // SERVLET RESPONSE interface methods762 763   @Override764   public void setContentLength(int len) {765     super.setContentLength(len);766     didSetContentLength = true;767   }768 769   @Override770   public void setHeader(String name, String value) {771     super.setHeader(name, value);772     checkHeader(name);773   }774 775   @Override776   public void addHeader(String name, String value) {777     super.addHeader(name, value);778     checkHeader(name);779   }780 781   @Override782   public void setIntHeader(String name, int value) {783     super.setIntHeader(name, value);784     checkHeader(name);785   }786 787   @Override788   public void addIntHeader(String name, int value) {789     super.addIntHeader(name, value);790     checkHeader(name);791   }792 793   private void checkHeader(String name) {794     if ("content-length".equalsIgnoreCase(name)) {795       didSetContentLength = true;796     }797   }798 799   @Override800   public ServletOutputStream getOutputStream() throws IOException {801     return noBody;802   }803 804   @Override805   public PrintWriter getWriter() throws UnsupportedEncodingException {806 807     if (writer == null) {808       OutputStreamWriter w;809 810       w = new OutputStreamWriter(noBody, getCharacterEncoding());811       writer = new PrintWriter(w);812     }813     return writer;814   }815 }816 817 818 /*819  * Servlet output stream that gobbles up all its data.820 */821 822 // file private823 class NoBodyOutputStream extends ServletOutputStream {824 825   private static final String LSTRING_FILE =826     "javax.servlet.http.LocalStrings";827   private static ResourceBundle lStrings =828     ResourceBundle.getBundle(LSTRING_FILE);829 830   private int        contentLength = 0;831 832   // file private833   NoBodyOutputStream() {834     // NOOP835   }836 837   // file private838   int getContentLength() {839     return contentLength;840   }841 842   @Override843   public void write(int b) {844     contentLength++;845   }846 847   @Override848   public void write(byte buf[], int offset, int len) throws IOException {849     if (buf == null) {850       throw new NullPointerException(851           lStrings.getString("err.io.nullArray"));852     }853 854     if (offset < 0 || len < 0 || offset+len > buf.length) {855       String msg = lStrings.getString("err.io.indexOutOfBounds");856       Object[] msgArgs = new Object[3];857       msgArgs[0] = Integer.valueOf(offset);858       msgArgs[1] = Integer.valueOf(len);859       msgArgs[2] = Integer.valueOf(buf.length);860       msg = MessageFormat.format(msg, msgArgs);861       throw new IndexOutOfBoundsException(msg);862     }863 864     contentLength += len;865   }866 }