home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / VCAFE.3.0A / Main.bin / HttpServlet.java < prev    next >
Text File  |  1998-04-21  |  27KB  |  714 lines

  1. /*
  2.  * @(#)HttpServlet.java    1.32 97/11/21
  3.  * 
  4.  * Copyright (c) 1996-1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.0
  20.  */
  21.  
  22. package javax.servlet.http;
  23.  
  24. import java.io.IOException;
  25. import java.io.PrintWriter;
  26. import java.io.OutputStreamWriter;
  27. import java.io.UnsupportedEncodingException;
  28. import java.lang.reflect.Method;
  29. import java.util.Enumeration;
  30.  
  31. import javax.servlet.GenericServlet;
  32. import javax.servlet.ServletException;
  33. import javax.servlet.ServletOutputStream;
  34. import javax.servlet.ServletRequest;
  35. import javax.servlet.ServletResponse;
  36.  
  37.  
  38. /**
  39.  * An abstract class that simplifies writing HTTP servlets.  It extends
  40.  * the <code>GenericServlet</code> base class and provides an framework
  41.  * for handling the HTTP protocol.  Because it is an abstract class,
  42.  * servlet writers must subclass it and override at least one method.
  43.  * The methods normally overridden are:
  44.  * 
  45.  * <ul>
  46.  *      <li> <code>doGet</code>, if HTTP GET requests are supported.
  47.  *    Overriding the <code>doGet</code> method automatically also
  48.  *    provides support for the HEAD and conditional GET operations.
  49.  *    Where practical, the <code>getLastModified</code> method should
  50.  *    also be overridden, to facilitate caching the HTTP response
  51.  *    data.  This improves performance by enabling smarter
  52.  *    conditional GET support.
  53.  *
  54.  *    <li> <code>doPost</code>, if HTTP POST requests are supported.
  55.  *      <li> <code>doPut</code>, if HTTP PUT requests are supported.
  56.  *      <li> <code>doDelete</code>, if HTTP DELETE requests are supported.
  57.  *
  58.  *    <li> The lifecycle methods <code>init</code> and
  59.  *    <code>destroy</code>, if the servlet writer needs to manage
  60.  *    resources that are held for the lifetime of the servlet.
  61.  *    Servlets that do not manage resources do not need to specialize
  62.  *    these methods.
  63.  *    
  64.  *    <li> <code>getServletInfo</code>, to provide descriptive
  65.  *    information through a service's administrative interfaces.
  66.  *      </ul>
  67.  * 
  68.  * <P>Notice that the <code>service</code> method is not typically
  69.  * overridden.  The <code>service</code> method, as provided, supports
  70.  * standard HTTP requests by dispatching them to appropriate methods,
  71.  * such as the methods listed above that have the prefix "do".  In
  72.  * addition, the service method also supports the HTTP 1.1 protocol's
  73.  * TRACE and OPTIONS methods by dispatching to the <code>doTrace</code>
  74.  * and <code>doOptions</code> methods.  The <code>doTrace</code> and
  75.  * <code>doOptions</code> methods are not typically overridden.
  76.  *
  77.  * <P>Servlets typically run inside multi-threaded servers; servlets
  78.  * must be written to handle multiple service requests simultaneously.
  79.  * It is the servlet writer's responsibility to synchronize access to
  80.  * any shared resources.  Such resources include in-memory data such as
  81.  * instance or class variables of the servlet, as well as external
  82.  * components such as files, database and network connections.
  83.  * Information on multithreaded programming in Java can be found in the
  84.  * <a
  85.  * href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
  86.  * Java Tutorial on Multithreaded Programming</a>.
  87.  *
  88.  * @version 1.32, 11/21/97
  89.  */
  90.  
  91. public abstract class HttpServlet extends GenericServlet 
  92.     implements java.io.Serializable {
  93.  
  94.     /**
  95.      * The default constructor does nothing.
  96.      */
  97.     public HttpServlet () { }
  98.  
  99.  
  100.     /**
  101.      * Performs the HTTP GET operation; the default implementation
  102.      * reports an HTTP BAD_REQUEST error.  Overriding this method to
  103.      * support the GET operation also automatically supports the HEAD
  104.      * operation.  (HEAD is a GET that returns no body in the response;
  105.      * it just returns the request HEADer fields.)
  106.      *
  107.      * <p>Servlet writers who override this method should read any data
  108.      * from the request, set entity headers in the response, access the
  109.      * writer or output stream, and, finally, write any response data.
  110.      * The headers that are set should include content type, and
  111.      * encoding.  If a writer is to be used to write response data, the
  112.      * content type must be set before the writer is accessed.  In
  113.      * general, the servlet implementor must write the headers before
  114.      * the response data because the headers can be flushed at any time
  115.      * after the data starts to be written.
  116.      * 
  117.      * <p>Setting content length allows the servlet to take advantage
  118.      * of HTTP "connection keep alive".  If content length can not be
  119.      * set in advance, the performance penalties associated with not
  120.      * using keep alives will sometimes be avoided if the response
  121.      * entity fits in an internal buffer.
  122.      *
  123.      * <p>Entity data written for a HEAD request is ignored.  Servlet
  124.      * writers can, as a simple performance optimization, omit writing
  125.      * response data for HEAD methods.  If no response data is to be
  126.      * written, then the content length field must be set explicitly.
  127.      *
  128.      * <P>The GET operation is expected to be safe: without any side
  129.      * effects for which users might be held responsible.  For example,
  130.      * most form queries have no side effects.  Requests intended to
  131.      * change stored data should use some other HTTP method.  (There
  132.      * have been cases of significant security breaches reported
  133.      * because web-based applications used GET inappropriately.)
  134.      *
  135.      * <P> The GET operation is also expected to be idempotent: it can
  136.      * safely be repeated.  This is not quite the same as being safe,
  137.      * but in some common examples the requirements have the same
  138.      * result.  For example, repeating queries is both safe and
  139.      * idempotent (unless payment is required!), but buying something
  140.      * or modifying data is neither safe nor idempotent.
  141.      *
  142.      * @param req HttpServletRequest that encapsulates the request to
  143.      * the servlet 
  144.      * @param resp HttpServletResponse that encapsulates the response
  145.      * from the servlet
  146.      * 
  147.      * @exception IOException if detected when handling the request
  148.      * @exception ServletException if the request could not be handled
  149.      * 
  150.      * @see javax.servlet.ServletResponse#setContentType
  151.      */
  152.     protected void doGet (HttpServletRequest req, HttpServletResponse resp)
  153.       throws ServletException, IOException
  154.       {
  155.       resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
  156.               "GET is not supported by this URL");
  157.       }
  158.  
  159.  
  160.     /**
  161.      * Gets the time the requested entity was last modified; the
  162.      * default implementation returns a negative number, indicating
  163.      * that the modification time is unknown and hence should not be
  164.      * used for conditional GET operations or for other cache control
  165.      * operations as this implementation will always return the contents. 
  166.      *
  167.      * <P> Implementations supporting the GET request should override
  168.      * this method to provide an accurate object modification time.
  169.      * This makes browser and proxy caches work more effectively,
  170.      * reducing the load on server and network resources.
  171.      *
  172.      * @param req HttpServletRequest that encapsulates the request to
  173.      * the servlet 
  174.      * @return the time the requested entity was last modified, as
  175.      * the difference, measured in milliseconds, between that
  176.      * time and midnight, January 1, 1970 UTC.  Negative numbers
  177.      * indicate this time is unknown.
  178.      */
  179.     protected long getLastModified (HttpServletRequest req)
  180.       {
  181.       return -1;
  182.       }
  183.  
  184.  
  185.     /*
  186.      * Implements the HTTP HEAD method.  By default, this is done
  187.      * in terms of the unconditional GET method, using a response body
  188.      * which only counts its output bytes (to set Content-Length
  189.      * correctly).  Subclassers could avoid computing the response
  190.      * body, and just set the response headers directly, for improved
  191.      * performance.
  192.      *
  193.      * <P> As with GET, this method should be both "safe" and
  194.      * "idempotent".
  195.      *
  196.      * @param req HttpServletRequest that encapsulates the request to
  197.      * the servlet 
  198.      * @param resp HttpServletResponse that encapsulates the response
  199.      * from the servlet
  200.      * @exception IOException if detected when handling the request
  201.      * @exception ServletException if the request could not be handled
  202.      */
  203.     private void doHead (HttpServletRequest req, HttpServletResponse resp)
  204.       throws ServletException, IOException
  205.       {
  206.       NoBodyResponse response = new NoBodyResponse(resp);
  207.  
  208.       doGet (req, response);
  209.       response.setContentLength ();
  210.       }
  211.  
  212.  
  213.     /**
  214.      *
  215.      * Performs the HTTP POST operation; the default implementation
  216.      * reports an HTTP BAD_REQUEST error.  Servlet writers who override
  217.      * this method should read any data from the request (for example,
  218.      * form parameters), set entity headers in the response, access the
  219.      * writer or output stream and, finally, write any response data
  220.      * using the servlet output stream.  The headers that are set
  221.      * should include content type, and encoding.  If a writer is to be
  222.      * used to write response data, the content type must be set before
  223.      * the writer is accessed.  In general, the servlet implementor
  224.      * must write the headers before the response data because the
  225.      * headers can be flushed at any time after the data starts to be
  226.      * written.
  227.      *
  228.      * <p>If HTTP/1.1 chunked encoding is used (that is, if the
  229.      * transfer-encoding header is present), then the content-length
  230.      * header should not be set.  For HTTP/1.1 communications that do
  231.      * not use chunked encoding and HTTP 1.0 communications, setting
  232.      * content length allows the servlet to take advantage of HTTP
  233.      * "connection keep alive".  For just such communications, if
  234.      * content length can not be set, the performance penalties
  235.      * associated with not using keep alives will sometimes be avoided
  236.      * if the response entity fits in an internal buffer.
  237.      *
  238.      * <P> This method does not need to be either "safe" or
  239.      * "idempotent".  Operations requested through POST can have side
  240.      * effects for which the user can be held accountable.  Specific
  241.      * examples including updating stored data or buying things online.
  242.      *
  243.      * @param req HttpServletRequest that encapsulates the request to
  244.      * the servlet 
  245.      * @param resp HttpServletResponse that encapsulates the response
  246.      * from the servlet
  247.      * 
  248.      * @exception IOException if detected when handling the request
  249.      * @exception ServletException if the request could not be handled
  250.      *
  251.      * @see javax.servlet.ServletResponse#setContentType
  252.      */
  253.     protected void doPost (HttpServletRequest req, HttpServletResponse resp)
  254.       throws ServletException, IOException
  255.       {
  256.       resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
  257.               "POST is not supported by this URL");
  258.       }
  259.  
  260.     /**
  261.      * Performs the HTTP PUT operation; the default implementation
  262.      * reports an HTTP BAD_REQUEST error.  The PUT operation is
  263.      * analogous to sending a file via FTP.
  264.      *
  265.      * <p>Servlet writers who override this method must respect any
  266.      * Content-* headers sent with the request. (These headers include
  267.      * content-length, content-type, content-transfer-encoding,
  268.      * content-encoding, content-base, content-language,
  269.      * content-location, content-MD5, and content-range.) If the
  270.      * subclass cannot honor a content header, then it must issue an
  271.      * error response (501) and discard the request.  For more
  272.      * information, see the <a
  273.      * href="http://info.internet.isi.edu:80/in-notes/rfc/files/rfc2068.txt">
  274.      * HTTP 1.1 RFC</a>.
  275.      *
  276.      * <P> This method does not need to be either "safe" or
  277.      * "idempotent".  Operations requested through PUT can have side
  278.      * effects for which the user can be held accountable.  Although
  279.      * not required, servlet writers who override this method may wish
  280.      * to save a copy of the affected URI in temporary storage.
  281.      * 
  282.      * @param req HttpServletRequest that encapsulates the request to
  283.      * the servlet 
  284.      * @param resp HttpServletResponse that encapsulates the response
  285.      * from the servlet 
  286.      * @exception IOException if detected when handling the request
  287.      * @exception ServletException if the request could not be handled
  288.      */
  289.     protected void doPut (HttpServletRequest req, HttpServletResponse resp)
  290.       throws ServletException, IOException
  291.       {
  292.       resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
  293.               "PUT is not supported by this URL");
  294.       }
  295.  
  296.     /**
  297.      * Performs the HTTP DELETE operation; the default implementation
  298.      * reports an HTTP BAD_REQUEST error. The DELETE operation allows a
  299.      * client to request a URI to be removed from the server.
  300.      *
  301.      * <P> This method does not need to be either "safe" or
  302.      * "idempotent".  Operations requested through DELETE can have
  303.      * side-effects for which users may be held accountable. Although
  304.      * not required, servlet writers who subclass this method may wish
  305.      * to save a copy of the affected URI in temporary storage.
  306.      *
  307.      * @param req HttpServletRequest that encapsulates the request to
  308.      * the servlet 
  309.      * @param resp HttpServletResponse that encapsulates the response
  310.      * from the servlet 
  311.      * @exception IOException if detected when handling the request
  312.      * @exception ServletException if the request could not be handled
  313.      */
  314.     protected void doDelete (HttpServletRequest req,
  315.                  HttpServletResponse resp)
  316.       throws ServletException, IOException
  317.       {
  318.       resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
  319.               "DELETE is not supported by this URL");
  320.       }
  321.  
  322.  
  323.     private Method [] getAllDeclaredMethods (Class c) {
  324.     if (c.getName().equals("javax.servlet.http.HttpServlet"))
  325.       return null;
  326.     
  327.     int j=0;
  328.     Method [] parentMethods = getAllDeclaredMethods(c.getSuperclass());
  329.     Method [] thisMethods = c.getDeclaredMethods();
  330.  
  331.     if (parentMethods!=null) {
  332.         Method [] allMethods = new Method [parentMethods.length + thisMethods.length];
  333.         for (int i=0; i<parentMethods.length; i++) {
  334.         allMethods[i]=parentMethods[i];
  335.         j=i;
  336.         }
  337.         j++;
  338.         for (int i=j; i<thisMethods.length+j; i++) {
  339.         allMethods[i] = thisMethods[i-j];
  340.         }
  341.         return allMethods;
  342.     }
  343.     return thisMethods;
  344.     }
  345.  
  346.     /**
  347.      * Performs the HTTP OPTIONS operation; the default implementation
  348.      * of this method automatically determines what HTTP Options are
  349.      * supported.  For example, if a servlet writer subclasses
  350.      * HttpServlet and overrides the <code>doGet</code> method, then
  351.      * this method will return the following header: <p>Allow:
  352.      * GET,HEAD,TRACE,OPTIONS
  353.      * 
  354.      * <p>This method does not need to be overridden unless the servlet
  355.      * implements new methods, beyond those supported by the HTTP/1.1
  356.      * protocol.
  357.      *
  358.      * @param req HttpServletRequest that encapsulates the request to
  359.      * the servlet 
  360.      * @param resp HttpServletResponse that encapsulates the response
  361.      * from the servlet 
  362.      * @exception IOException if detected when handling the request
  363.      * @exception ServletException if the request could not be handled
  364.      */
  365.     protected void doOptions (HttpServletRequest req, HttpServletResponse resp)
  366.       throws ServletException, IOException
  367.       {
  368.       Method [] methods = getAllDeclaredMethods(this.getClass());
  369.       
  370.       boolean ALLOW_GET = false;
  371.       boolean ALLOW_HEAD = false;
  372.       boolean ALLOW_POST = false;
  373.       boolean ALLOW_PUT = false;
  374.       boolean ALLOW_DELETE = false;
  375.       boolean ALLOW_TRACE = true;
  376.       boolean ALLOW_OPTIONS = true;
  377.       
  378.       for (int i=0; i<methods.length; i++) {
  379.           Method m = methods[i];
  380.           
  381.           if (m.getName().equals("doGet")) {
  382.           ALLOW_GET = true;
  383.           ALLOW_HEAD = true;
  384.           }
  385.           if (m.getName().equals("doPost")) 
  386.         ALLOW_POST = true;
  387.           if (m.getName().equals("doPut"))
  388.         ALLOW_PUT = true;
  389.           if (m.getName().equals("doDelete"))
  390.         ALLOW_DELETE = true;
  391.           
  392.       }
  393.         
  394.       String allow = null;
  395.       if (ALLOW_GET)
  396.         if (allow==null) allow="GET";
  397.       if (ALLOW_HEAD)
  398.         if (allow==null) allow="HEAD";
  399.         else allow += ", " + "HEAD";
  400.       if (ALLOW_POST)
  401.         if (allow==null) allow="POST";
  402.         else allow += ", " + "POST";
  403.       if (ALLOW_PUT)
  404.         if (allow==null) allow="PUT";
  405.         else allow += ", " + "PUT";
  406.       if (ALLOW_DELETE)
  407.         if (allow==null) allow="DELETE";
  408.         else allow += ", " + "DELETE";
  409.       if (ALLOW_TRACE)
  410.         if (allow==null) allow="TRACE";
  411.         else allow += ", " + "TRACE";
  412.       if (ALLOW_OPTIONS)
  413.         if (allow==null) allow="OPTIONS";
  414.         else allow += ", " + "OPTIONS";
  415.  
  416.       resp.setHeader("Allow", allow);
  417.       }
  418.  
  419.     /**
  420.      * Performs the HTTP TRACE operation; the default implementation of
  421.      * this method causes a response with a message containing all of
  422.      * the headers sent in the trace request.  This method is not
  423.      * typically overridden.
  424.      *
  425.      * @param req HttpServletRequest that encapsulates the request to
  426.      * the servlet 
  427.      * @param resp HttpServletResponse that encapsulates the response
  428.      * from the servlet 
  429.      * @exception IOException if detected when handling the request
  430.      * @exception ServletException if the request could not be handled
  431.      */
  432.     protected void doTrace (HttpServletRequest req, HttpServletResponse resp) 
  433.       throws ServletException, IOException {
  434.  
  435.     int responseLength;
  436.     
  437.     String CRLF = "\r\n";
  438.     String responseString = "TRACE "+req.getRequestURI()+" " +req.getProtocol();
  439.     
  440.     Enumeration reqHeaderEnum = req.getHeaderNames();
  441.     
  442.     while( reqHeaderEnum.hasMoreElements() )
  443.       {
  444.           String headerName = (String)reqHeaderEnum.nextElement();
  445.           responseString += CRLF + headerName + ": " + req.getHeader(headerName); 
  446.       }
  447.     
  448.     responseString += CRLF;
  449.     
  450.     responseLength = responseString.length();
  451.     
  452.     resp.setContentType("message/http");
  453.     resp.setContentLength(responseLength);
  454.     ServletOutputStream out = resp.getOutputStream();
  455.     out.print(responseString);    
  456.     out.close();
  457.     return;
  458.     }        
  459.  
  460.  
  461.     /**
  462.      * This is an HTTP-specific version of the
  463.      * <code>Servlet.service</code> method, which accepts HTTP specific
  464.      * parameters.  This method is rarely overridden.  Standard HTTP
  465.      * requests are supported by dispatching to Java methods
  466.      * specialized to implement them.
  467.      *
  468.      * @param req HttpServletRequest that encapsulates the request to
  469.      * the servlet 
  470.      * @param resp HttpServletResponse that encapsulates the response
  471.      * from the servlet 
  472.      * @exception IOException if detected when handling the request
  473.      * @exception ServletException if the request could not be handled
  474.      * 
  475.      * @see javax.servlet.Servlet#service
  476.      */
  477.     protected void service (HttpServletRequest req, HttpServletResponse resp)
  478.       throws ServletException, IOException
  479.       {
  480.       String            method = req.getMethod ();
  481.  
  482.       if (method.equals ("GET")) {
  483.           long        ifModifiedSince;
  484.           long        lastModified;
  485.           long        now;
  486.  
  487.           //
  488.           // HTTP 1.0 conditional GET just uses If-Modified-Since fields
  489.           // in the header.  HTTP 1.1 has more conditional GET options.
  490.           //
  491.           // We call getLastModified() only once; it won't be cheap.
  492.           //
  493.           ifModifiedSince = req.getDateHeader ("If-Modified-Since");
  494.           lastModified = getLastModified (req);
  495.           maybeSetLastModified (resp, lastModified);
  496.  
  497.  
  498.           if (ifModifiedSince == -1 || lastModified == -1)
  499.         doGet (req, resp);
  500.           else {
  501.           now = System.currentTimeMillis ();
  502.  
  503.           //
  504.           // Times in the future are invalid ... but we can't treat
  505.           // them as "hard errors", so for now we accept extra load.
  506.           //
  507.           if (now < ifModifiedSince || ifModifiedSince < lastModified)
  508.             doGet (req, resp);
  509.           else
  510.             resp.sendError (HttpServletResponse.SC_NOT_MODIFIED);
  511.           }
  512.  
  513.       } else if (method.equals ("HEAD")) {
  514.           long        lastModified;
  515.  
  516.           lastModified = getLastModified (req);
  517.           maybeSetLastModified (resp, lastModified);
  518.           doHead (req, resp);
  519.  
  520.       } else if (method.equals ("POST")) {
  521.           doPost (req, resp);
  522.  
  523.       } else if (method.equals ("PUT")) {
  524.           doPut(req, resp);    
  525.  
  526.       } else if (method.equals ("DELETE")) {
  527.           doDelete(req, resp);
  528.  
  529.       } else if (method.equals ("OPTIONS")) {
  530.           doOptions(req,resp);
  531.  
  532.       } else if (method.equals ("TRACE")) {
  533.           doTrace(req,resp);
  534.     
  535.       } else {
  536.           //
  537.           // Note that this means NO servlet supports whatever
  538.           // method was requested, anywhere on this server.
  539.           //
  540.           resp.sendError (HttpServletResponse.SC_NOT_IMPLEMENTED,
  541.                   "Method '" + method + "' is not defined in RFC 2068");
  542.       }
  543.       }
  544.  
  545.  
  546.     /*
  547.      * Sets the Last-Modified entity header field, if it has not
  548.      * already been set and if the value is meaningful.  Called before
  549.      * doGet, to ensure that headers are set before response data is
  550.      * written.  A subclass might have set this header already, so we
  551.      * check.
  552.      */
  553.     private void maybeSetLastModified (
  554.     HttpServletResponse    resp,
  555.     long            lastModified) {
  556.     if (resp.containsHeader ("Last-Modified"))
  557.       return;
  558.     if (lastModified >= 0)
  559.       resp.setDateHeader ("Last-Modified", lastModified);
  560.     }
  561.  
  562.     /**
  563.      * Implements the high level <code>Servlet.service</code> method by
  564.      * delegating to the HTTP-specific service method.  This method is
  565.      * not normally overriden.
  566.      * 
  567.      * @param req ServletRequest that encapsulates the request to the
  568.      * servlet
  569.      * @param res ServletResponse that encapsulates the response from
  570.      * the servlet
  571.      * @exception IOException if an I/O exception has occurred
  572.      * @exception ServletException if a servlet exception has occurred
  573.      * 
  574.      * @see javax.servlet.Servlet#service
  575.      */
  576.     public void service(ServletRequest req, ServletResponse res)
  577.       throws ServletException, IOException
  578.       {
  579.       HttpServletRequest    request;
  580.       HttpServletResponse    response;
  581.  
  582.       try {
  583.           request = (HttpServletRequest) req;
  584.           response = (HttpServletResponse) res;
  585.       } catch (ClassCastException e) {
  586.           throw new ServletException ("non-HTTP request or response");
  587.       }
  588.       service (request, response);
  589.       }
  590. }
  591.  
  592.  
  593. /*
  594.  * A response that includes no body, for use in (dumb) "HEAD" support.
  595.  * This just swallows that body, counting the bytes in order to set
  596.  * the content length appropriately.  All other methods delegate directly
  597.  * to the HTTP Servlet Response object used to construct this one.
  598.  */
  599. // file private
  600. class NoBodyResponse implements HttpServletResponse {
  601.     private HttpServletResponse        resp;
  602.     private NoBodyOutputStream        noBody;
  603.     private PrintWriter            writer;
  604.     private boolean            didSetContentLength;
  605.  
  606.     // file private
  607.     NoBodyResponse (HttpServletResponse r) {
  608.     resp = r;
  609.     noBody = new NoBodyOutputStream ();
  610.     }
  611.  
  612.     // file private
  613.     void setContentLength () {
  614.     if (!didSetContentLength)
  615.       resp.setContentLength (noBody.getContentLength ());
  616.     }
  617.  
  618.  
  619.     // SERVLET RESPONSE interface methods
  620.  
  621.     public void setContentLength (int len) {
  622.     resp.setContentLength (len);
  623.     didSetContentLength = true;
  624.     }
  625.  
  626.     public void setContentType (String type)
  627.       { resp.setContentType (type); }
  628.  
  629.     public ServletOutputStream getOutputStream () throws IOException
  630.       { return noBody; }
  631.  
  632.     public String getCharacterEncoding ()
  633.     { return resp.getCharacterEncoding (); }
  634.  
  635.     public PrintWriter getWriter () throws UnsupportedEncodingException
  636.     {
  637.     if (writer == null) {
  638.         OutputStreamWriter    w;
  639.  
  640.         w = new OutputStreamWriter (noBody, getCharacterEncoding ());
  641.         writer = new PrintWriter (w);
  642.     }
  643.     return writer;
  644.     }
  645.  
  646.  
  647.     // HTTP SERVLET RESPONSE interface methods
  648.  
  649.     public void addCookie(Cookie cookie)
  650.       { resp.addCookie(cookie); }
  651.  
  652.     public boolean containsHeader (String name)
  653.       { return resp.containsHeader (name); }
  654.  
  655.     public void setStatus (int sc, String sm)
  656.       { resp.setStatus (sc, sm); }
  657.  
  658.     public void setStatus (int sc)
  659.       { resp.setStatus (sc); }
  660.  
  661.     public void setHeader (String name, String value)
  662.       { resp.setHeader (name, value); }
  663.  
  664.     public void setIntHeader (String name, int value)
  665.       { resp.setIntHeader (name, value); }
  666.  
  667.     public void setDateHeader (String name, long date)
  668.       { resp.setDateHeader (name, date); }
  669.  
  670.     public void sendError (int sc, String msg) throws IOException
  671.       { resp.sendError (sc, msg); }
  672.  
  673.     public void sendError (int sc) throws IOException
  674.       { resp.sendError (sc); }
  675.  
  676.     public void sendRedirect (String location) throws IOException
  677.       { resp.sendRedirect (location); }
  678.  
  679.     public String encodeUrl (String url) 
  680.       { return resp.encodeUrl(url); }
  681.  
  682.     public String encodeRedirectUrl (String url)
  683.       { return resp.encodeRedirectUrl(url); }
  684. }
  685.  
  686.  
  687. /*
  688.  * Servlet output stream that gobbles up all its data.
  689.  */
  690. // file private
  691. class NoBodyOutputStream extends ServletOutputStream {
  692.     private int        contentLength = 0;
  693.  
  694.     // file private
  695.     NoBodyOutputStream () {}
  696.  
  697.     // file private
  698.     int getContentLength () {
  699.     return contentLength;
  700.     }
  701.  
  702.     public void write (int b) {
  703.     contentLength++;
  704.     }
  705.  
  706.     public void write (byte buf [], int offset, int len)
  707.       throws IOException {
  708.       if (len >= 0)
  709.         contentLength += len;
  710.       else
  711.         throw new IOException ("negative length");
  712.     }
  713. }
  714.