HTTP and Servlets

 < Free Open Study > 



The javax.servlet package provides generic interfaces and classes to service client requests in a protocol-independent manner. This means that all compatible requests can be made using the members of this package, but we are limited to generic servlet methods to process our request. Any protocol-specific functionality has to be incorporated into the application by the developer.

We can extend the javax.servlet package API to create protocol-specific servlet classes that can not only process requests, but also include any protocol specific logic required. The javax.servlet.http package is just such an extension. It adds support for HTTP specific functions including the HTTP GET or POST methods.

The javax.servlet.http package should be viewed in relation to the standard Servlet API. For example, the javax.servlet.http.HttpServlet class extends from javax.servlet.GenericServlet, adding a number of specific methods to process different types of HTTP requests.

Here's a diagram of the classes and interfaces in the javax.servlet.http package:

click to expand

Of course, many classes and interfaces in the javax.http.HttpServlet package continue to make use of classes and interfaces from the javax.servlet package; for example the streaming and exception classes.

The HttpServlet Class

Many of the servlets that we will develop will extend from HttpServlet, rather than GenericServlet, because most communication over the Web is carried over HTTP, which HttpServlet is designed to handle. When we extend from HttpServlet we gain HTTP functionality. For example, HttpServlet makes use of HTTP versions of the Request and Response objects. HttpServlet overrides the service() method of GenericServlet and forwards requests to methods designed to process different types of HTTP requests.

Of course, if we use HttpServlet, then client requests must be sent using HTTP if they are to be understood. If the clients our application is expected to handle use a protocol other than HTTP we will need to use a servlet extended from GenericServlet.

Lifecycle Methods

HttpServlet inherits two important lifecycle methods from the GenericServlet class: init() and destroy() - we covered their use in Chapter 2. We can override one of two init() methods:

    public void init(ServletConfig config) throws ServletException    public void init() throws ServletException 

If you override the first of these you must first call super.init(config) to ensure that the reference to the ServletConfig object passed in by the servlet container is stored in the servlet instance for later use. If the second init() method is overridden there is no need to call super.init(config); it will be called by the init(config) method once the ServletConfig object reference is stored.

start sidebar

We should normally only override one version of the init() method, because we only need to initialize the servlet in one place. The second method is provided as a convenient alternative choice, but it does not make sense for our servlets to override both and spread the initialization logic.

end sidebar

Service Methods

The HttpServlet class defines two service() methods to process requests. The first of these overrides the service() method inherited from GenericServlet:

    void service(ServletRequest req, ServletResponse res) 

As HTTP servlet developers we should never have reason to override this method. This method simply casts the ServletRequest and ServletResponse objects into their corresponding HTTP objects (HttpServletRequest and HttpServletResponse) and forwards the request to the second service() method:

 protected void service(HttpServletRequest req, HttpServletResponse resp 

This method should also not be overridden, as it is the responsibility of this method to determine the type of the HTTP request and forward it to the appropriate method to be processed.

There are few reasons why a developer would want to override this service() method. One reason might occur if the developer is working with a custom extended version of the HTTP protocol - but before doing this you should consider alternate ways of achieving your objective, because one of the biggest benefits of HTTP is its interoperability.

Handling HTTP Requests

We saw earlier that the most common HTTP requests are GET and POST methods. We must implement methods to handle these different types of requests. The servlet container will recognize the type of HTTP request that has been made, and will pass the request to the correct servlet method. Accordingly, we do not override the service() methods as we did for servlets that extend GenericServlet, but rather we override the appropriate request method(s):

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)      throws ServletException, IOException    protected void doPost(HttpServletRequest req, HttpServletResponse resp)      throws ServletException, IOException    protected void doHead(HttpServletRequest req, HttpServletResponse resp)      throws ServletException, IOException    protected void doPut(HttpServletRequest req, HttpServletResponse resp)      throws ServletException, IOException 

Not all clients or servers implement the set of HTTP (1.0 or 1.1) specifications fully. It is up to the developer to chose the appropriate way to handle the request and the appropriate method to be used in a web application. Whenever possible, this choice should be consistent with the normal use of the request type (for example, POST for posting data).

The programmer should not normally override the doHead() method because the HttpServlet implementation correctly returns the HEAD request information. The HEAD request returns the header information, but not the body of the GET request.

We must take care only to use the methods new to HTTP 1.1 when clients are known to support the latest version, such as custom Java applications or applets acting as clients. These methods are:

    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)      throws ServletException, IOException    protected void doTrace(HttpServletRequest req, HttpServletResponse resp)      throws ServletException, IOException 

Clients use OPTIONS requests to determine the types of HTTP requests that the server will handle. We will rarely need to override this method, unless our application needs to 'hide' a supported request type from a client, or we implement methods additional to HTTP 1.1 (such as a later version). We may want to hide methods from client scans to prevent hacking where hidden methods perform sensitive or administrator tasks.

TRACE requests are normally used for debugging. They are designed to allow a request from a client to be sent to a server, and the server then returns the request (as received by it) in the body of the response. This is useful to identify the specific contents of the request that are being received by the server, to determine whether the client is sending the correct request, and/or to determine if the request data is being altered in any way mid-route.

The default implementation of the doTrace() method should not normally be overridden because the default implementation is the same for all servlets. The default implementation will return the header information received by the server back to the client. For applications with custom clients, requests made to the servlet can be examined (to determine if the request is being correctly made) if the request method is modified to an HTTP TRACE request and directed at the servlet.

The getLastModified() method, below, allows servlets that can easily determine the last update time of their GET request data to do so, and then include this in the doHead() and doGet() responses:

    protected long getLastModified(HttpServletRequest req)      throws ServletException, IOException 

This has the effect of improving caching of output, and thereby reducing the load on the server and network.

HTTP Requests and Responses

The HttpServletRequest and HttpServletResponse interfaces extend the ServletRequest and ServletResponse interfaces respectively, in order to add methods that are specific to HTTP. We saw in Chapter 2 that the Servlet API provides two generic wrappers for ServletRequest and ServletResponse: ServletRequestWrapper and ServletResponseWrapper. These wrappers are extended further to provide convenience wrappers for the HTTP interfaces: HttpServletRequestWrapper and HttpServletResponseWrapper.

The HttpServletRequest Interface

We can use the methods defined in the HttpServletRequest interface to learn a great deal about a request.

Header Information

Objects implementing the HttpServletRequest interface contain the header information for the HTTP request. The interface defines methods that are designed to extract the information about the request.

The getMethod() method returns the name of the HTTP request method used to make the request, for example GET or POST:

    public String getMethod() 

The getHeaderNames() method returns a java.util.Enumeration of the names of all of the headers supplied with the request:

    public Enumeration getHeaderNames() 

We can use the getHeader(String) method to return the value of the header assuming that is exists:

    public String getHeader(String name) 

The argument to this method could be any header name, for instance one of the elements of the Enumeration returned by the previous method. For example, calling the method with the user-agent parameter would return information about the client software generating the request (such as Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)).

We can also use the getHeaders() method, which returns an Enumeration of Strings that contains all the values of the header specified by the supplied name. We use the getHeaders() method where we expect more than one header value of the same name to be included in the header of the request.

    public Enumeration getHeaders(String name) 

However, we might not always want the value of a header to be stored in a String. If we know that the value of a header is representing a date, or an integer, we can use the getDateHeader() and getIntHeader() methods instead. The getDateHeader() method returns the value of the header specified by the supplied name as a long value that represents a Date object (which is specified by the number of milliseconds since January 1, 1970 GMT):

    public long getDateHeader(String name) 

If we know a header is in an int value we can use the getIntHeader() method to retrieve it from the request header:

    public int getIntHeader(String name) 

Putting it all together, we could use the following code snippet to find and print all the headers and corresponding values of the request:

    Enumeration e = request.getHeaderNames();    while(e.hasMoreElements()) {      String headerName = (String)e.nextElement();      String headerValue = request.getHeader(headerName);      table.appendRow("Header: <code>" + headerName + "</code>", headerValue);    } 

The following is an example of the output produced from the code above, where the client supplied the headers shown below:

Header

Value

accept

image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*

referer

http://localhost:8080/httpServlet/index.html

accept-language

en-ie

accept-encoding

gzip, deflate

user-agent

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)

host

localhost:8080

connection

Keep-Alive

Only the host header is really essential as many web servers house multiple web sites on one IP address, so specifying the requested web host is important.

Path Information

We can extract information about the path used in the request and the query string (for example http://localhost:8080/httpServlet/servlet/firewall.OurHttpServlet?name=Jayne&children=Luther). The getQueryString() method returns the query string of the request, or null if there was no query string associated with the request URL: For the URL given above the method would return "name=Jayne&children=Luther".

    public String getQueryString() 

The getContextPath() method returns the URL context path of the request. This is the first part of the URI, starting with "/" and not ending in a "/" character. For servlets in the root or default context this returns "". In the URL example above this will return "/httpServlet".

    public String getContextPath() 

The getServletPath() method will return the part of the URL that is used to call the URL (in other words our servlet or another file/resource). In the example URL above this would equate to "/servlet/firewall.OurHttpServlet".

    public String getServletPath() 

The getPathInfo() method will return any additional path information sent by the client in the request URL:

    public String getPathInfo() 

This is any additional path information between the servlet path and the query string. In the example above this would return null, as there is no such additional information. We might use additional information to identify a client (for example session tracking) or to include a key or ID.

The getPathTranslated() method is similar to the previous getPathInfo() method in that it refers to the same additional path information, but in this method it translates this into a real path:

    public String getPathTranslated() 

The getRequestURI() method specifies the full URI for the request. In the example it would return "/httpServlet/servlet/firewall.OurHttpServlet".

    public String getRequestURI() 

The getRequestURL() method constructs the URL that the client used to make the request and returns it. This includes the full URL except for the query parameters and would return "http://localhost/httpServlet/servlet/firewall.OurHttpServlet" for the example above:

    public StringBuffer getRequestURL() 

Let's now look at some code that calls these methods on the request object and outputs the result:

    //Request Path Elements    out.println("<br><b>Request Context Path:</b> " + request.getContextPath());    out.println("<br><b>Request Servlet Path:</b> " + request.getServletPath());    out.println("<br><b>Request Path Info:</b> " + request.getPathInfo());    out.println("<br><b>Request Path Translated:</b> " +                 request.getPathTranslated());    out.println("<br><b>Request Request URI:</b> " + request.getRequestURI());    out.println("<br><b>Request Request URL:</b> " + request.getRequestURL());    out.println("<br><b>Query String:</b> " + request.getQueryString()); 

The result of this block of code is shown below. These are the various permutations we would get with our example URL.

Request URI: /httpServlet/servlet/firewall.OurHttpServlet

Request Context Path: /httpServlet

Request Servlet Path: /servlet/firewall.OurHttpServlet

Request Path Info: null

Request Path Translated: null

Request Request URI: /httpServlet/servlet/firewall.OurHttpServlet

Request Request URL: http://localhost/httpServlet/servlet/firewall.OurHttpServlet

Query String: name=Jayne&children=Luther&children=Mary

Authentication Information

A number of methods exist to help improve security and authentication by providing the servlet with the means to identify the user (if possible), which enables the servlet to determine what the user has access to or what actions they can perform. Authentication schemes like Basic or Digest Authentication can be used to secure the servlet.

The getAuthType() method will return the String name of the scheme being used:

    public String getAuthType() 

The getRemoteUser() method will determine the login name of the client making the request if the user is already authenticated to the servlet. If the user has not already been authenticated to the servlet, this method will return null:

    public String getRemoteUser() 

The getUserPrincipal() method is very similar to the previous method except that it returns a Principal object containing the name of the authenticated user (or null if they are not authenticated):

    public java.security.Principal getUserPrincipal() 

The two previous methods effectively perform similar actions, but the second returns a Principal object. The Principal object is used to represent the concept of a user entity, which could be an individual, a corporation, or a login ID. The getUserPrincipal() method may be used when applications use the java.security packages to manage access and security for the application.

The following method can be used to find out if the user who has been authenticated to the server has been designated with the specified role when using the web application:

    public boolean isUserInRole(String role) 

We can use this method to grant or deny access to a user, based on their role.

The HttpServletResponse Interface

The HttpServletResponse interface extends from the ServletResponse interface and is used to send the servlet's HTTP-based response back to the client. It includes additional HTTP-specific methods for setting data in the response, such as HTTP headers, sessions and cookies, and status codes.

Headers and MIME Types

The HttpServletResponse interface inherits two methods from the ServletResponse class related to setting the headers of a response.

The setContentLength() method sets the header indicating the length of the response. Setting this value too low will normally stop the server sending the excess data after the length specified, and most clients will stop reading the response after the specified length. Conversely, setting the size too high may leave the client hanging, waiting for more data once the response has been completed, until it times out. Therefore it is often better to let the server set this header (if it can buffer the full response before sending) or perhaps leave it unset, unless the content can be easily determined in advance.

The second method inherited from the ServletResponse class is the setContentType() method. This is used to set the MIME (Multipurpose Internet Mail Extensions, RFC 2045 and 2046) type of the response. MIME types are used in many protocols other than HTTP to indicate the type of output or file following:

    response.setContentType("text/html"); 

Here we set the content type to "text/html". For servlets sending back HTML-based web pages this is the type we always use, and is the most common type that servlets will return to the client. We change this if we are sending different data back to the client. Appendix B gives more information on MIME and common MIME types.

The most common way to set headers of a HTTP response is to use the setHeader() method to reset an existing header or the addHeader() method to add a new header to the response:

    public void setHeader(String name, String value)    public void addHeader(String name, String value) 

A number of other convenience header methods exist, to allow for the inclusion of data not in String format into headers. To set a date header we could use one of the above methods, with the date value in String format. However to set the date header directly we can use the setDateHeader() method to set or reset the specified header field. Using the addDateHeader() method we can add a header field with date information:

    public void setDateHeader(String name, long date)    public void addDateHeader(String name, long date) 

The addIntHeader() and setIntHeader() methods allows the addition/setting of int values in headers in a similar way:

    public void addIntHeader(String name, int value)    public void setIntHeader(String name, int value) 

We can check if a header has already been set using the containsHeader() method:

    boolean containsHeader(String name) 

This will return true if the specified header has already been set in the response object. Otherwise it will return false.

Redirecting Requests

To redirect a request to another resource on the server (or anywhere else), the sendRedirect() method may be used with the relative or absolute address as appropriate. If the server is (or may be) using URL rewriting to maintain sessions, you must call the encodeRedirectURL() method (on the Response object as well) with the URL that the client is being redirected to, so that the server can add the session information to the URL:

    void sendRedirect(String location) 

To use the sendRedirect() method, the response must still be buffered on the server (or not started at all), and not committed. We can check if the response has been committed yet with the isCommitted() method, inherited from ServletResponse. If we try to redirect the request after the response has been committed an IllegalStateException is thrown. Also, using this method effectively commits the response, so we should not write any further to the response.

Using the sendRedirect() method is different to using a RequestDispatcher object to forward (or include a response). This method is to effectively redirect the entire request to another location for processing. Using a RequestDispatcher object we can either include the content of the resource that the RequestDispatcher object represents, or forward the request to this resource. If we forward the request using the RequestDispatcher object, we may have already sent some data back to the client, while the resource being forwarded to will append to the output already sent (if any). You should refer to Chapter 2 for more on the RequestDispatcher class and examples of its use.

Status Codes and Errors

The HttpServletResponse class currently has forty static int fields declared, corresponding to HTTP status codes that can be returned in a response to a client. The most commonly seen status code in browsers on the Internet is the 404 Not Found error reported when a page or resource has been removed.

We can set the status code to a request using the setStatus() method. This is much better than just returning an error to the client and it can be much more informational, because we can specify that a resource is temporarily unavailable (503) or it is forbidden (403).

    public void setStatus(int sc) 

When an error occurs we can use either of the sendError() methods (taking a status code, or code and message):

    public void sendError(int sc)    public void sendError(int sc, String msg) 

These set the status code as with the setStatus() method, but also clear the buffer and commit the response, meaning that the servlet cannot send any further output to the client in response to this request. Most servers, depending on configuration, will present a default error page (specific to this error code or all error codes) with information for the client:



 < Free Open Study > 



Professional Java Servlets 2.3
Professional Java Servlets 2.3
ISBN: 186100561X
EAN: 2147483647
Year: 2006
Pages: 130

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net