home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-07-18 | 15.4 KB | 432 lines |
- /*
- * @(#)HttpServlet.java 1.15 97/05/22
- *
- * Copyright (c) 1996-1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- * CopyrightVersion 1.0
- */
-
- package javax.servlet.http;
-
- import java.io.IOException;
- import javax.servlet.GenericServlet;
- import javax.servlet.ServletException;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
-
-
- /**
- * The HttpServlet class is an abstract class that simplifies writing
- * HTTP 1.0 servlets. It extends the GenericServlet base class and
- * provides a protocol handling framework. Because it is abstract,
- * servlet writers must subclass it and override at least one method.
- * The methods normally overridden are: <UL>
- *
- * <LI> <em>doGet</em>, if HTTP GET requests are supported.
- * Where practical, the <em>getLastModified</em> method should
- * also be overridden, to facilitate caching the HTTP response
- * data.
- *
- * <LI> <em>doPost</em>, if HTTP POST requests are supported.
- *
- * <LI> The lifecycle methods <em>init</em> and <em>destroy</em>,
- * if the servlet writer needs to manage costly resources that are
- * held for the lifetime of the servlet. Servlets that do not
- * manage such resources do not need to specialize these methods.
- *
- * <LI> <em>getServletInfo</em>, to provide descriptive
- * information through a service's administrative interfaces.
- *
- * </UL>
- *
- * <P> By subclassing HttpServlet and implementing the doGet method, a
- * servlet automatically supports the HTTP 1.0 protocol's GET, HEAD and
- * conditional GET operations. Adding support for the getLastModified
- * method improves performance by enabling smarter conditional GET
- * support through caches.
- *
- * <P> To support HTTP 1.1 methods such as OPTIONS, PUT, DELETE, and
- * TRACE, or other extensions, override the service method and handle
- * those additional HTTP methods directly. Calling super.service from
- * within the overridden service method provides the default handling
- * on the other methods (such as GET).
- *
- * <P> Note that servlets typically run inside multi-threaded servers;
- * servlets must be written to handle multiple service requests
- * simultaneously. It is the servlet writer's responsibility to
- * synchronize access to any shared resources. Such resources include
- * in-memory data such as instance or class variables of the servlet,
- * as well as external components such as files, database and network
- * connections. Information on multithreaded programming in Java can
- * be found in the <a
- * href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
- * Java Tutorial on Multithreaded Programming</a>.
- *
- * @version 1.15, 05/22/97
- * @author David Brownell
- * @author David Connelly */
- public abstract
- class HttpServlet extends GenericServlet {
-
- /**
- * The default constructor does nothing.
- */
- protected HttpServlet () { }
-
-
- /**
- * Performs the HTTP GET operation. The default implementation
- * reports an HTTP BAD_REQUEST error. When overriding this method,
- * servlet writers should set the headers for the requested entity
- * (including content type, length, and encoding) then write that
- * entity's data using the servlet output stream from the response.
- * The response headers must be written before the response data
- * because the headers can be flushed at any time after the data
- * starts to be written. Setting content length allows the servlet
- * to take advantage of HTTP "connection keep alive". If content
- * length can not be set in advance, the performance penalties
- * associated with not using keep alives will sometimes be avoided
- * if the response entity fits in an internal buffer.
- *
- * <P> By supporting GET, the HEAD operation is automatically
- * supported. (HEAD is a GET that returns no body in the response;
- * it just returns the request HEADer fields.) Entity data written
- * for a HEAD request is ignored. Servlet writers can, as a simple
- * performance optimization, omit writing response data for HEAD
- * methods.
- *
- * <P> Note that the GET operation is expected to be <em>safe</em>,
- * without any side effects for which users might be held
- * responsible. For example, most form queries have no side
- * effects. Requests intended to change stored data should use
- * some other HTTP method. (There have been cases of significant
- * security breaches reported because web-based applications used
- * GET inappropriately.)
- *
- * <P> The GET operation is also expected to be
- * <em>idempotent</em>, meaning that it can safely be repeated.
- * This is not quite the same as being safe, but in some common
- * examples the requirements have the same result. For example,
- * repeating queries is both safe and idempotent (unless payment is
- * required!), but buying something or modifying data is neither
- * safe nor idempotent.
- *
- * @param req encapsulates the request to the servlet
- * @param resp encapsulates the response from the servlet
- * @exception ServletException if the request could not be handled
- * @exception IOException if detected when handling the request */
- protected void doGet (HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
- {
- resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
- "GET is not supported by this URL");
- }
-
-
- /**
- * Returns the time the requested entity was last modified. The
- * default implementation returns a negative number, indicating
- * that the modification time is unknown and hence should not be
- * used for conditional GET operations or for other cache control
- * operations.
- *
- * <P> Implementations supporting the GET request should override
- * this method to provide an accurate object modification time.
- * This makes browser and proxy caches work more effectively,
- * reducing the load on server and network resources.
- *
- * @param req encapsulates the request to the servlet
- * @return the time the requested entity was last modified, in
- * milliseconds since the epoch. Negative numbers indicate
- * this time is unknown.
- */
- protected long getLastModified (HttpServletRequest req)
- {
- return -1;
- }
-
-
- /*
- * Implements the HTTP 1.0 HEAD method. By default, this is done
- * in terms of the unconditional GET method, using a response body
- * which only counts its output bytes (to set Content-Length
- * correctly). Subclassers could avoid computing the response
- * body, and just set the response headers directly, for improved
- * performance.
- *
- * <P> As with GET, this method should be both "safe" and
- * "idempotent".
- *
- * @param req encapsulates the request to the servlet
- * @param resp encapsulates the response from the servlet
- * @exception ServletException if the request could not be handled
- * @exception IOException if detected when handling the request */
- private void doHead (HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
- {
- NoBodyResponse response = new NoBodyResponse(resp);
-
- doGet (req, response);
- response.setContentLength ();
- }
-
-
- /**
- *
- * Performs the HTTP POST operation. The default implementation
- * reports an HTTP BAD_REQUEST error. Subclassers should read any
- * data from the request (for example, form parameters), set entity
- * headers in the response, and then write any response data using
- * the servlet output stream. The headers that are set should
- * include content type, length, and encoding. Setting content
- * length allows the servlet to take advantage of HTTP "connection
- * keep alive". If content length can not be set in advance, the
- * performance penalties associated with not using keep alives will
- * sometimes be avoided if the response entity fits in an internal
- * buffer. The servlet implementor must write the headers before
- * the response data because the headers can be flushed at any time
- * after the data starts to be written
- *
- * <P> This method does not need to be either "safe" or
- * "idempotent". Operations requested through POST could be ones
- * for which users need to be held accountable. Specific examples
- * including updating stored data or buying things online.
- *
- * @param req encapsulates the request to the servlet
- * @param resp encapsulates the response from the servlet
- * @exception ServletException if the request could not be handled
- * @exception IOException if detected when handling the request */
- protected void doPost (HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
- {
- resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
- "POST is not supported by this URL");
- }
-
-
- /**
- * This is an HTTP-specific version of the Servlet.service method,
- * which accepts HTTP specific parameters. This method is rarely
- * overridden. Standard HTTP 1.0 requests are supported by
- * dispatching to Java methods specialized to implement them.
- *
- * @param req encapsulates the request to the servlet
- * @param resp encapsulates the response from the servlet
- * @exception ServletException if the request could not be handled
- * @exception IOException if detected when handling the request */
- protected void service (HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
- {
- String method = req.getMethod ();
-
- if (method.equals ("GET")) {
- long ifModifiedSince;
- long lastModified;
- long now;
-
- //
- // HTTP 1.0 conditional GET just uses If-Modified-Since fields
- // in the header. HTTP 1.1 has more conditional GET options.
- //
- // We call getLastModified() only once; it won't be cheap.
- //
- ifModifiedSince = req.getDateHeader ("If-Modified-Since");
- lastModified = getLastModified (req);
- maybeSetLastModified (resp, lastModified);
-
- if (ifModifiedSince == -1)
- doGet (req, resp);
- else {
- now = System.currentTimeMillis ();
-
- //
- // Times in the future are invalid ... but we can't treat
- // them as "hard errors", so for now we accept extra load.
- //
- if (now < ifModifiedSince || ifModifiedSince < lastModified)
- doGet (req, resp);
- else
- resp.sendError (HttpServletResponse.SC_NOT_MODIFIED);
- }
-
- } else if (method.equals ("HEAD")) {
- long lastModified;
-
- lastModified = getLastModified (req);
- maybeSetLastModified (resp, lastModified);
- doHead (req, resp);
-
- } else if (method.equals ("POST")) {
- if (req.getContentLength () == -1)
- resp.sendError (HttpServletResponse.SC_BAD_REQUEST,
- "POST bodies must specify content length");
- else
- doPost (req, resp);
-
- } else {
- //
- // Note that this means NO servlet supports whatever
- // method was requested, anywhere on this server.
- //
- resp.sendError (HttpServletResponse.SC_NOT_IMPLEMENTED,
- "Method '" + method + "' is not defined in RFC 1945");
- }
- }
-
-
- /**
- * Sets the Last-Modified entity header field, if it has not
- * already been set and if the value is meaningful. Called before
- * doGet, to ensure that headers are set before response data is
- * written. A subclass might have set this header already, so we
- * check.
- */
- private void maybeSetLastModified (
- HttpServletResponse resp,
- long lastModified
- ) {
- if (resp.containsHeader ("Last-Modified"))
- return;
- if (lastModified >= 0)
- resp.setDateHeader ("Last-Modified", lastModified);
- }
-
- /**
- * Implements the high level Servlet.service method by delegating
- * to the HTTP-specific service method. This method is not
- * normally overriden.
- *
- * @param req the servlet request
- * @param res the servlet response
- * @exception ServletException if a servlet exception has occurred
- * @exception IOException if an I/O exception has occurred
- */
- public void service(ServletRequest req, ServletResponse res)
- throws ServletException, IOException
- {
- HttpServletRequest request;
- HttpServletResponse response;
-
- try {
- request = (HttpServletRequest) req;
- response = (HttpServletResponse) res;
- } catch (ClassCastException e) {
- throw new ServletException ("non-HTTP request or response");
- }
- service (request, response);
- }
- }
-
-
- /*
- * A response that includes no body, for use in (dumb) "HEAD" support.
- * This just swallows that body, counting the bytes in order to set
- * the content length appropriately. All other methods delegate directly
- * to the HTTP Servlet Response object used to construct this one.
- */
- // file private
- class NoBodyResponse implements HttpServletResponse {
- private HttpServletResponse resp;
- private NoBodyOutputStream noBody;
- private boolean didSetContentLength;
-
- // file private
- NoBodyResponse (HttpServletResponse r) {
- resp = r;
- noBody = new NoBodyOutputStream ();
- }
-
- // file private
- void setContentLength () {
- if (!didSetContentLength)
- resp.setContentLength (noBody.getContentLength ());
- }
-
-
- // SERVLET RESPONSE interface methods
-
- public void setContentLength (int len) {
- resp.setContentLength (len);
- didSetContentLength = true;
- }
-
- public void setContentType (String type)
- { resp.setContentType (type); }
-
- public ServletOutputStream getOutputStream () throws IOException
- { return noBody; }
-
-
- // HTTP SERVLET RESPONSE interface methods
-
- public boolean containsHeader (String name)
- { return resp.containsHeader (name); }
-
- public void setStatus (int sc, String sm)
- { resp.setStatus (sc, sm); }
-
- public void setStatus (int sc)
- { resp.setStatus (sc); }
-
- public void setHeader (String name, String value)
- { resp.setHeader (name, value); }
-
- public void setIntHeader (String name, int value)
- { resp.setIntHeader (name, value); }
-
- public void setDateHeader (String name, long date)
- { resp.setDateHeader (name, date); }
-
- public void sendError (int sc, String msg) throws IOException
- { resp.sendError (sc, msg); }
-
- public void sendError (int sc) throws IOException
- { resp.sendError (sc); }
-
- public void sendRedirect (String location) throws IOException
- { resp.sendRedirect (location); }
- }
-
-
- /*
- * Servlet output stream that gobbles up all its data.
- */
- // file private
- class NoBodyOutputStream extends ServletOutputStream {
- private int contentLength = 0;
-
- // file private
- NoBodyOutputStream () {}
-
- // file private
- int getContentLength () {
- return contentLength;
- }
-
- public void write (int b) {
- contentLength++;
- }
-
- public void write (byte buf [], int offset, int len)
- throws IOException {
- if (len >= 0)
- contentLength += len;
- else
- throw new IOException ("negative length");
- }
- }
-