home *** CD-ROM | disk | FTP | other *** search
/ Java Developer's Companion / Java Developer's Companion.iso / binaries / Windows / jsdk / src / javax / servlet / http / HttpServlet.java next >
Encoding:
Java Source  |  1997-07-18  |  15.4 KB  |  432 lines

  1. /*
  2.  * @(#)HttpServlet.java    1.15 97/05/22
  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 javax.servlet.GenericServlet;
  26. import javax.servlet.ServletException;
  27. import javax.servlet.ServletOutputStream;
  28. import javax.servlet.ServletRequest;
  29. import javax.servlet.ServletResponse;
  30.  
  31.  
  32. /**
  33.  * The HttpServlet class is an abstract class that simplifies writing
  34.  * HTTP 1.0 servlets.  It extends the GenericServlet base class and
  35.  * provides a protocol handling framework.  Because it is abstract,
  36.  * servlet writers must subclass it and override at least one method.
  37.  * The methods normally overridden are: <UL>
  38.  *
  39.  *    <LI> <em>doGet</em>, if HTTP GET requests are supported.
  40.  *    Where practical, the <em>getLastModified</em> method should
  41.  *    also be overridden, to facilitate caching the HTTP response
  42.  *    data. 
  43.  *
  44.  *    <LI> <em>doPost</em>, if HTTP POST requests are supported.
  45.  *
  46.  *    <LI> The lifecycle methods <em>init</em> and <em>destroy</em>,
  47.  *    if the servlet writer needs to manage costly resources that are
  48.  *    held for the lifetime of the servlet.  Servlets that do not
  49.  *    manage such resources do not need to specialize these methods.
  50.  *    
  51.  *    <LI> <em>getServletInfo</em>, to provide descriptive
  52.  *    information through a service's administrative interfaces.
  53.  * 
  54.  *    </UL>
  55.  * 
  56.  * <P> By subclassing HttpServlet and implementing the doGet method, a
  57.  * servlet automatically supports the HTTP 1.0 protocol's GET, HEAD and
  58.  * conditional GET operations.  Adding support for the getLastModified
  59.  * method improves performance by enabling smarter conditional GET
  60.  * support through caches.
  61.  *
  62.  * <P> To support HTTP 1.1 methods such as OPTIONS, PUT, DELETE, and
  63.  * TRACE, or other extensions, override the service method and handle
  64.  * those additional HTTP methods directly.  Calling super.service from
  65.  * within the overridden service method provides the default handling
  66.  * on the other methods (such as GET).
  67.  *
  68.  * <P> Note that servlets typically run inside multi-threaded servers;
  69.  * servlets must be written to handle multiple service requests
  70.  * simultaneously.  It is the servlet writer's responsibility to
  71.  * synchronize access to any shared resources.  Such resources include
  72.  * in-memory data such as instance or class variables of the servlet,
  73.  * as well as external components such as files, database and network
  74.  * connections.  Information on multithreaded programming in Java can
  75.  * be found in the <a
  76.  * href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
  77.  * Java Tutorial on Multithreaded Programming</a>.
  78.  *
  79.  * @version     1.15, 05/22/97
  80.  * @author    David Brownell
  81.  * @author David Connelly */
  82. public abstract
  83. class HttpServlet extends GenericServlet {
  84.  
  85.     /**
  86.      * The default constructor does nothing.
  87.      */
  88.     protected HttpServlet () { }
  89.  
  90.  
  91.     /**
  92.      * Performs the HTTP GET operation.  The default implementation
  93.      * reports an HTTP BAD_REQUEST error.  When overriding this method,
  94.      * servlet writers should set the headers for the requested entity
  95.      * (including content type, length, and encoding) then write that
  96.      * entity's data using the servlet output stream from the response.
  97.      * The response headers must be written before the response data
  98.      * because the headers can be flushed at any time after the data
  99.      * starts to be written.  Setting content length allows the servlet
  100.      * to take advantage of HTTP "connection keep alive".  If content
  101.      * length can not be set in advance, the performance penalties
  102.      * associated with not using keep alives will sometimes be avoided
  103.      * if the response entity fits in an internal buffer.
  104.      *
  105.      * <P> By supporting GET, the HEAD operation is automatically
  106.      * supported.  (HEAD is a GET that returns no body in the response;
  107.      * it just returns the request HEADer fields.)  Entity data written
  108.      * for a HEAD request is ignored.  Servlet writers can, as a simple
  109.      * performance optimization, omit writing response data for HEAD
  110.      * methods.
  111.      *
  112.      * <P> Note that the GET operation is expected to be <em>safe</em>,
  113.      * without any side effects for which users might be held
  114.      * responsible.  For example, most form queries have no side
  115.      * effects.  Requests intended to change stored data should use
  116.      * some other HTTP method.  (There have been cases of significant
  117.      * security breaches reported because web-based applications used
  118.      * GET inappropriately.)
  119.      *
  120.      * <P> The GET operation is also expected to be
  121.      * <em>idempotent</em>, meaning that it can safely be repeated.
  122.      * This is not quite the same as being safe, but in some common
  123.      * examples the requirements have the same result.  For example,
  124.      * repeating queries is both safe and idempotent (unless payment is
  125.      * required!), but buying something or modifying data is neither
  126.      * safe nor idempotent.
  127.      *
  128.      * @param req encapsulates the request to the servlet
  129.      * @param resp encapsulates the response from the servlet
  130.      * @exception ServletException if the request could not be handled
  131.      * @exception IOException if detected when handling the request */
  132.     protected void doGet (HttpServletRequest req, HttpServletResponse resp)
  133.     throws ServletException, IOException
  134.     {
  135.     resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
  136.         "GET is not supported by this URL");
  137.     }
  138.  
  139.  
  140.     /**
  141.      * Returns the time the requested entity was last modified.  The
  142.      * default implementation returns a negative number, indicating
  143.      * that the modification time is unknown and hence should not be
  144.      * used for conditional GET operations or for other cache control
  145.      * operations.
  146.      *
  147.      * <P> Implementations supporting the GET request should override
  148.      * this method to provide an accurate object modification time.
  149.      * This makes browser and proxy caches work more effectively,
  150.      * reducing the load on server and network resources.
  151.      *
  152.      * @param req encapsulates the request to the servlet
  153.      * @return the time the requested entity was last modified, in
  154.      *    milliseconds since the epoch.  Negative numbers indicate
  155.      *    this time is unknown.
  156.      */
  157.     protected long getLastModified (HttpServletRequest req)
  158.     {
  159.     return -1;
  160.     }
  161.  
  162.  
  163.     /*
  164.      * Implements the HTTP 1.0 HEAD method.  By default, this is done
  165.      * in terms of the unconditional GET method, using a response body
  166.      * which only counts its output bytes (to set Content-Length
  167.      * correctly).  Subclassers could avoid computing the response
  168.      * body, and just set the response headers directly, for improved
  169.      * performance.
  170.      *
  171.      * <P> As with GET, this method should be both "safe" and
  172.      * "idempotent".
  173.      *
  174.      * @param req encapsulates the request to the servlet
  175.      * @param resp encapsulates the response from the servlet
  176.      * @exception ServletException if the request could not be handled
  177.      * @exception IOException if detected when handling the request */
  178.     private void doHead (HttpServletRequest req, HttpServletResponse resp)
  179.     throws ServletException, IOException
  180.     {
  181.     NoBodyResponse response = new NoBodyResponse(resp);
  182.  
  183.     doGet (req, response);
  184.     response.setContentLength ();
  185.     }
  186.  
  187.  
  188.     /**
  189.      *
  190.      * Performs the HTTP POST operation.  The default implementation
  191.      * reports an HTTP BAD_REQUEST error.  Subclassers should read any
  192.      * data from the request (for example, form parameters), set entity
  193.      * headers in the response, and then write any response data using
  194.      * the servlet output stream.  The headers that are set should
  195.      * include content type, length, and encoding.  Setting content
  196.      * length allows the servlet to take advantage of HTTP "connection
  197.      * keep alive".  If content length can not be set in advance, the
  198.      * performance penalties associated with not using keep alives will
  199.      * sometimes be avoided if the response entity fits in an internal
  200.      * buffer.  The servlet implementor must write the headers before
  201.      * the response data because the headers can be flushed at any time
  202.      * after the data starts to be written
  203.      *
  204.      * <P> This method does not need to be either "safe" or
  205.      * "idempotent".  Operations requested through POST could be ones
  206.      * for which users need to be held accountable.  Specific examples
  207.      * including updating stored data or buying things online.
  208.      *
  209.      * @param req encapsulates the request to the servlet
  210.      * @param resp encapsulates the response from the servlet
  211.      * @exception ServletException if the request could not be handled
  212.      * @exception IOException if detected when handling the request */
  213.     protected void doPost (HttpServletRequest req, HttpServletResponse resp)
  214.     throws ServletException, IOException
  215.     {
  216.     resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
  217.         "POST is not supported by this URL");
  218.     }
  219.  
  220.  
  221.     /**
  222.      * This is an HTTP-specific version of the Servlet.service method,
  223.      * which accepts HTTP specific parameters.  This method is rarely
  224.      * overridden.  Standard HTTP 1.0 requests are supported by
  225.      * dispatching to Java methods specialized to implement them.
  226.      *
  227.      * @param req encapsulates the request to the servlet
  228.      * @param resp encapsulates the response from the servlet
  229.      * @exception ServletException if the request could not be handled
  230.      * @exception IOException if detected when handling the request */
  231.     protected void service (HttpServletRequest req, HttpServletResponse resp)
  232.     throws ServletException, IOException
  233.     {
  234.     String            method = req.getMethod ();
  235.  
  236.     if (method.equals ("GET")) {
  237.         long        ifModifiedSince;
  238.         long        lastModified;
  239.         long        now;
  240.  
  241.         //
  242.         // HTTP 1.0 conditional GET just uses If-Modified-Since fields
  243.         // in the header.  HTTP 1.1 has more conditional GET options.
  244.         //
  245.         // We call getLastModified() only once; it won't be cheap.
  246.         //
  247.         ifModifiedSince = req.getDateHeader ("If-Modified-Since");
  248.         lastModified = getLastModified (req);
  249.         maybeSetLastModified (resp, lastModified);
  250.  
  251.         if (ifModifiedSince == -1)
  252.         doGet (req, resp);
  253.         else {
  254.         now = System.currentTimeMillis ();
  255.  
  256.         //
  257.         // Times in the future are invalid ... but we can't treat
  258.         // them as "hard errors", so for now we accept extra load.
  259.         //
  260.         if (now < ifModifiedSince || ifModifiedSince < lastModified)
  261.             doGet (req, resp);
  262.         else
  263.             resp.sendError (HttpServletResponse.SC_NOT_MODIFIED);
  264.         }
  265.  
  266.     } else if (method.equals ("HEAD")) {
  267.         long        lastModified;
  268.  
  269.         lastModified = getLastModified (req);
  270.         maybeSetLastModified (resp, lastModified);
  271.         doHead (req, resp);
  272.  
  273.     } else if (method.equals ("POST")) {
  274.         if (req.getContentLength () == -1)
  275.         resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
  276.             "POST bodies must specify content length");
  277.         else
  278.         doPost (req, resp);
  279.     
  280.     } else {
  281.         //
  282.         // Note that this means NO servlet supports whatever
  283.         // method was requested, anywhere on this server.
  284.         //
  285.         resp.sendError (HttpServletResponse.SC_NOT_IMPLEMENTED,
  286.         "Method '" + method + "' is not defined in RFC 1945");
  287.     }
  288.     }
  289.  
  290.  
  291.     /**
  292.      * Sets the Last-Modified entity header field, if it has not
  293.      * already been set and if the value is meaningful.  Called before
  294.      * doGet, to ensure that headers are set before response data is
  295.      * written.  A subclass might have set this header already, so we
  296.      * check.
  297.      */
  298.     private void maybeSetLastModified (
  299.     HttpServletResponse    resp,
  300.     long            lastModified
  301.     ) {
  302.     if (resp.containsHeader ("Last-Modified"))
  303.         return;
  304.     if (lastModified >= 0)
  305.         resp.setDateHeader ("Last-Modified", lastModified);
  306.     }
  307.  
  308.     /**
  309.      * Implements the high level Servlet.service method by delegating
  310.      * to the HTTP-specific service method.  This method is not
  311.      * normally overriden.
  312.      * 
  313.      * @param req the servlet request
  314.      * @param res the servlet response
  315.      * @exception ServletException if a servlet exception has occurred
  316.      * @exception IOException if an I/O exception has occurred
  317.      */
  318.     public void service(ServletRequest req, ServletResponse res)
  319.     throws ServletException, IOException
  320.     {
  321.     HttpServletRequest    request;
  322.     HttpServletResponse    response;
  323.  
  324.     try {
  325.         request = (HttpServletRequest) req;
  326.         response = (HttpServletResponse) res;
  327.     } catch (ClassCastException e) {
  328.         throw new ServletException ("non-HTTP request or response");
  329.     }
  330.     service (request, response);
  331.     }
  332. }
  333.  
  334.  
  335. /*
  336.  * A response that includes no body, for use in (dumb) "HEAD" support.
  337.  * This just swallows that body, counting the bytes in order to set
  338.  * the content length appropriately.  All other methods delegate directly
  339.  * to the HTTP Servlet Response object used to construct this one.
  340.  */
  341. // file private
  342. class NoBodyResponse implements HttpServletResponse {
  343.     private HttpServletResponse        resp;
  344.     private NoBodyOutputStream        noBody;
  345.     private boolean            didSetContentLength;
  346.  
  347.     // file private
  348.     NoBodyResponse (HttpServletResponse r) {
  349.     resp = r;
  350.     noBody = new NoBodyOutputStream ();
  351.     }
  352.  
  353.     // file private
  354.     void setContentLength () {
  355.     if (!didSetContentLength)
  356.         resp.setContentLength (noBody.getContentLength ());
  357.     }
  358.  
  359.  
  360.     // SERVLET RESPONSE interface methods
  361.  
  362.     public void setContentLength (int len) {
  363.     resp.setContentLength (len);
  364.     didSetContentLength = true;
  365.     }
  366.  
  367.     public void setContentType (String type)
  368.     { resp.setContentType (type); }
  369.  
  370.     public ServletOutputStream getOutputStream () throws IOException
  371.     { return noBody; }
  372.  
  373.  
  374.     // HTTP SERVLET RESPONSE interface methods
  375.  
  376.     public boolean containsHeader (String name)
  377.     { return resp.containsHeader (name); }
  378.  
  379.     public void setStatus (int sc, String sm)
  380.     { resp.setStatus (sc, sm); }
  381.  
  382.     public void setStatus (int sc)
  383.     { resp.setStatus (sc); }
  384.  
  385.     public void setHeader (String name, String value)
  386.     { resp.setHeader (name, value); }
  387.  
  388.     public void setIntHeader (String name, int value)
  389.     { resp.setIntHeader (name, value); }
  390.  
  391.     public void setDateHeader (String name, long date)
  392.     { resp.setDateHeader (name, date); }
  393.  
  394.     public void sendError (int sc, String msg) throws IOException
  395.     { resp.sendError (sc, msg); }
  396.  
  397.     public void sendError (int sc) throws IOException
  398.     { resp.sendError (sc); }
  399.  
  400.     public void sendRedirect (String location) throws IOException
  401.     { resp.sendRedirect (location); }
  402. }
  403.  
  404.  
  405. /*
  406.  * Servlet output stream that gobbles up all its data.
  407.  */
  408. // file private
  409. class NoBodyOutputStream extends ServletOutputStream {
  410.     private int        contentLength = 0;
  411.  
  412.     // file private
  413.     NoBodyOutputStream () {}
  414.  
  415.     // file private
  416.     int getContentLength () {
  417.     return contentLength;
  418.     }
  419.  
  420.     public void write (int b) {
  421.     contentLength++;
  422.     }
  423.  
  424.     public void write (byte buf [], int offset, int len)
  425.     throws IOException {
  426.     if (len >= 0)
  427.         contentLength += len;
  428.     else
  429.         throw new IOException ("negative length");
  430.     }
  431. }
  432.