View Javadoc

1   /*
2   * Copyright 2004 The Apache Software Foundation
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *     http://www.apache.org/licenses/LICENSE-2.0
9   *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16  package javax.servlet.http;
17  
18  import java.io.IOException;
19  import java.io.PrintWriter;
20  import java.io.OutputStreamWriter;
21  import java.io.UnsupportedEncodingException;
22  import java.lang.reflect.Method;
23  import java.text.MessageFormat;
24  import java.util.Enumeration;
25  import java.util.Locale;
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   *
37   * Provides an abstract class to be subclassed to create
38   * an HTTP servlet suitable for a Web site. A subclass of
39   * <code>HttpServlet</code> must override at least 
40   * one method, usually one of these:
41   *
42   * <ul>
43   * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
44   * <li> <code>doPost</code>, for HTTP POST requests
45   * <li> <code>doPut</code>, for HTTP PUT requests
46   * <li> <code>doDelete</code>, for HTTP DELETE requests
47   * <li> <code>init</code> and <code>destroy</code>, 
48   * to manage resources that are held for the life of the servlet
49   * <li> <code>getServletInfo</code>, which the servlet uses to
50   * provide information about itself 
51   * </ul>
52   *
53   * <p>There's almost no reason to override the <code>service</code>
54   * method. <code>service</code> handles standard HTTP
55   * requests by dispatching them to the handler methods
56   * for each HTTP request type (the <code>do</code><i>XXX</i>
57   * methods listed above).
58   *
59   * <p>Likewise, there's almost no reason to override the 
60   * <code>doOptions</code> and <code>doTrace</code> methods.
61   * 
62   * <p>Servlets typically run on multithreaded servers,
63   * so be aware that a servlet must handle concurrent
64   * requests and be careful to synchronize access to shared resources.
65   * Shared resources include in-memory data such as
66   * instance or class variables and external objects
67   * such as files, database connections, and network 
68   * connections.
69   * See the
70   * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
71   * Java Tutorial on Multithreaded Programming</a> for more
72   * information on handling multiple threads in a Java program.
73   *
74   * @author	Various
75   * @version	$Version$
76   *
77   */
78  
79  
80  
81  public abstract class HttpServlet extends GenericServlet
82      implements java.io.Serializable
83  {
84      private static final String METHOD_DELETE = "DELETE";
85      private static final String METHOD_HEAD = "HEAD";
86      private static final String METHOD_GET = "GET";
87      private static final String METHOD_OPTIONS = "OPTIONS";
88      private static final String METHOD_POST = "POST";
89      private static final String METHOD_PUT = "PUT";
90      private static final String METHOD_TRACE = "TRACE";
91  
92      private static final String HEADER_IFMODSINCE = "If-Modified-Since";
93      private static final String HEADER_LASTMOD = "Last-Modified";
94      
95      private static final String LSTRING_FILE =
96  	"javax.servlet.http.LocalStrings";
97      private static ResourceBundle lStrings =
98  	ResourceBundle.getBundle(LSTRING_FILE);
99     
100    
101    
102     
103     /**
104      * Does nothing, because this is an abstract class.
105      * 
106      */
107 
108     public HttpServlet() { }
109     
110     
111 
112     /**
113      *
114      * Called by the server (via the <code>service</code> method) to
115      * allow a servlet to handle a GET request. 
116      *
117      * <p>Overriding this method to support a GET request also
118      * automatically supports an HTTP HEAD request. A HEAD
119      * request is a GET request that returns no body in the
120      * response, only the request header fields.
121      *
122      * <p>When overriding this method, read the request data,
123      * write the response headers, get the response's writer or 
124      * output stream object, and finally, write the response data.
125      * It's best to include content type and encoding. When using
126      * a <code>PrintWriter</code> object to return the response,
127      * set the content type before accessing the
128      * <code>PrintWriter</code> object.
129      *
130      * <p>The servlet container must write the headers before
131      * committing the response, because in HTTP the headers must be sent
132      * before the response body.
133      *
134      * <p>Where possible, set the Content-Length header (with the
135      * {@link javax.servlet.ServletResponse#setContentLength} method),
136      * to allow the servlet container to use a persistent connection 
137      * to return its response to the client, improving performance.
138      * The content length is automatically set if the entire response fits
139      * inside the response buffer.
140      *
141      * <p>When using HTTP 1.1 chunked encoding (which means that the response
142      * has a Transfer-Encoding header), do not set the Content-Length header.
143      *
144      * <p>The GET method should be safe, that is, without
145      * any side effects for which users are held responsible.
146      * For example, most form queries have no side effects.
147      * If a client request is intended to change stored data,
148      * the request should use some other HTTP method.
149      *
150      * <p>The GET method should also be idempotent, meaning
151      * that it can be safely repeated. Sometimes making a
152      * method safe also makes it idempotent. For example, 
153      * repeating queries is both safe and idempotent, but
154      * buying a product online or modifying data is neither
155      * safe nor idempotent. 
156      *
157      * <p>If the request is incorrectly formatted, <code>doGet</code>
158      * returns an HTTP "Bad Request" message.
159      * 
160      *
161      * @param req	an {@link HttpServletRequest} object that
162      *			contains the request the client has made
163      *			of the servlet
164      *
165      * @param resp	an {@link HttpServletResponse} object that
166      *			contains the response the servlet sends
167      *			to the client
168      * 
169      * @exception IOException	if an input or output error is 
170      *				detected when the servlet handles
171      *				the GET request
172      *
173      * @exception ServletException	if the request for the GET
174      *					could not be handled
175      *
176      * 
177      * @see javax.servlet.ServletResponse#setContentType
178      *
179      */
180 
181     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
182 	throws ServletException, IOException
183     {
184 	String protocol = req.getProtocol();
185 	String msg = lStrings.getString("http.method_get_not_supported");
186 	if (protocol.endsWith("1.1")) {
187 	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
188 	} else {
189 	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
190 	}
191     }
192 
193 
194 
195 
196 
197     /**
198      *
199      * Returns the time the <code>HttpServletRequest</code>
200      * object was last modified,
201      * in milliseconds since midnight January 1, 1970 GMT.
202      * If the time is unknown, this method returns a negative
203      * number (the default).
204      *
205      * <p>Servlets that support HTTP GET requests and can quickly determine
206      * their last modification time should override this method.
207      * This makes browser and proxy caches work more effectively,
208      * reducing the load on server and network resources.
209      *
210      *
211      * @param req	the <code>HttpServletRequest</code> 
212      *			object that is sent to the servlet
213      *
214      * @return		a <code>long</code> integer specifying
215      *			the time the <code>HttpServletRequest</code>
216      *			object was last modified, in milliseconds
217      *			since midnight, January 1, 1970 GMT, or
218      *			-1 if the time is not known
219      *
220      */
221 
222     protected long getLastModified(HttpServletRequest req) {
223 	return -1;
224     }
225 
226 
227 
228 
229     /**
230      * 
231      *
232      * <p>Receives an HTTP HEAD request from the protected
233      * <code>service</code> method and handles the
234      * request.
235      * The client sends a HEAD request when it wants
236      * to see only the headers of a response, such as
237      * Content-Type or Content-Length. The HTTP HEAD
238      * method counts the output bytes in the response
239      * to set the Content-Length header accurately.
240      *
241      * <p>If you override this method, you can avoid computing
242      * the response body and just set the response headers
243      * directly to improve performance. Make sure that the
244      * <code>doHead</code> method you write is both safe
245      * and idempotent (that is, protects itself from being
246      * called multiple times for one HTTP HEAD request).
247      *
248      * <p>If the HTTP HEAD request is incorrectly formatted,
249      * <code>doHead</code> returns an HTTP "Bad Request"
250      * message.
251      *
252      *
253      * @param req	the request object that is passed
254      *			to the servlet
255      *			
256      * @param resp	the response object that the servlet
257      *			uses to return the headers to the clien
258      *
259      * @exception IOException		if an input or output error occurs
260      *
261      * @exception ServletException	if the request for the HEAD
262      *					could not be handled
263      */
264 
265     protected void doHead(HttpServletRequest req, HttpServletResponse resp)
266 	throws ServletException, IOException
267     {
268 	NoBodyResponse response = new NoBodyResponse(resp);
269 	
270 	doGet(req, response);
271 	response.setContentLength();
272     }
273     
274 
275 
276 
277 
278     /**
279      *
280      * Called by the server (via the <code>service</code> method)
281      * to allow a servlet to handle a POST request.
282      *
283      * The HTTP POST method allows the client to send
284      * data of unlimited length to the Web server a single time
285      * and is useful when posting information such as
286      * credit card numbers.
287      *
288      * <p>When overriding this method, read the request data,
289      * write the response headers, get the response's writer or output
290      * stream object, and finally, write the response data. It's best 
291      * to include content type and encoding. When using a
292      * <code>PrintWriter</code> object to return the response, set the 
293      * content type before accessing the <code>PrintWriter</code> object. 
294      *
295      * <p>The servlet container must write the headers before committing the
296      * response, because in HTTP the headers must be sent before the 
297      * response body.
298      *
299      * <p>Where possible, set the Content-Length header (with the
300      * {@link javax.servlet.ServletResponse#setContentLength} method),
301      * to allow the servlet container to use a persistent connection 
302      * to return its response to the client, improving performance.
303      * The content length is automatically set if the entire response fits
304      * inside the response buffer.  
305      *
306      * <p>When using HTTP 1.1 chunked encoding (which means that the response
307      * has a Transfer-Encoding header), do not set the Content-Length header. 
308      *
309      * <p>This method does not need to be either safe or idempotent.
310      * Operations requested through POST can have side effects for
311      * which the user can be held accountable, for example, 
312      * updating stored data or buying items online.
313      *
314      * <p>If the HTTP POST request is incorrectly formatted,
315      * <code>doPost</code> returns an HTTP "Bad Request" message.
316      *
317      *
318      * @param req	an {@link HttpServletRequest} object that
319      *			contains the request the client has made
320      *			of the servlet
321      *
322      * @param resp	an {@link HttpServletResponse} object that
323      *			contains the response the servlet sends
324      *			to the client
325      * 
326      * @exception IOException	if an input or output error is 
327      *				detected when the servlet handles
328      *				the request
329      *
330      * @exception ServletException	if the request for the POST
331      *					could not be handled
332      *
333      *
334      * @see javax.servlet.ServletOutputStream
335      * @see javax.servlet.ServletResponse#setContentType
336      *
337      *
338      */
339 
340     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
341 	throws ServletException, IOException
342     {
343 	String protocol = req.getProtocol();
344 	String msg = lStrings.getString("http.method_post_not_supported");
345 	if (protocol.endsWith("1.1")) {
346 	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
347 	} else {
348 	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
349 	}
350     }
351 
352 
353 
354 
355     /**
356      * Called by the server (via the <code>service</code> method)
357      * to allow a servlet to handle a PUT request.
358      *
359      * The PUT operation allows a client to 
360      * place a file on the server and is similar to 
361      * sending a file by FTP.
362      *
363      * <p>When overriding this method, leave intact
364      * any content headers sent with the request (including
365      * Content-Length, Content-Type, Content-Transfer-Encoding,
366      * Content-Encoding, Content-Base, Content-Language, Content-Location,
367      * Content-MD5, and Content-Range). If your method cannot
368      * handle a content header, it must issue an error message
369      * (HTTP 501 - Not Implemented) and discard the request.
370      * For more information on HTTP 1.1, see RFC 2616
371      * <a href="http://www.ietf.org/rfc/rfc2616.txt"></a>.
372      *
373      * <p>This method does not need to be either safe or idempotent.
374      * Operations that <code>doPut</code> performs can have side
375      * effects for which the user can be held accountable. When using
376      * this method, it may be useful to save a copy of the
377      * affected URL in temporary storage.
378      *
379      * <p>If the HTTP PUT request is incorrectly formatted,
380      * <code>doPut</code> returns an HTTP "Bad Request" message.
381      *
382      *
383      * @param req	the {@link HttpServletRequest} object that
384      *			contains the request the client made of
385      *			the servlet
386      *
387      * @param resp	the {@link HttpServletResponse} object that
388      *			contains the response the servlet returns
389      *			to the client
390      *
391      * @exception IOException	if an input or output error occurs
392      *				while the servlet is handling the
393      *				PUT request
394      *
395      * @exception ServletException	if the request for the PUT
396      *					cannot be handled
397      *
398      */
399   
400     protected void doPut(HttpServletRequest req, HttpServletResponse resp)
401 	throws ServletException, IOException
402     {
403 	String protocol = req.getProtocol();
404 	String msg = lStrings.getString("http.method_put_not_supported");
405 	if (protocol.endsWith("1.1")) {
406 	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
407 	} else {
408 	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
409 	}
410     }
411 
412 
413 
414 
415     /**
416      * 
417      * Called by the server (via the <code>service</code> method)
418      * to allow a servlet to handle a DELETE request.
419      *
420      * The DELETE operation allows a client to remove a document
421      * or Web page from the server.
422      * 
423      * <p>This method does not need to be either safe
424      * or idempotent. Operations requested through
425      * DELETE can have side effects for which users
426      * can be held accountable. When using
427      * this method, it may be useful to save a copy of the
428      * affected URL in temporary storage.
429      *
430      * <p>If the HTTP DELETE request is incorrectly formatted,
431      * <code>doDelete</code> returns an HTTP "Bad Request"
432      * message.
433      *
434      *
435      * @param req	the {@link HttpServletRequest} object that
436      *			contains the request the client made of
437      *			the servlet
438      *
439      *
440      * @param resp	the {@link HttpServletResponse} object that
441      *			contains the response the servlet returns
442      *			to the client				
443      *
444      *
445      * @exception IOException	if an input or output error occurs
446      *				while the servlet is handling the
447      *				DELETE request
448      *
449      * @exception ServletException	if the request for the
450      *					DELETE cannot be handled
451      *
452      */
453      
454     protected void doDelete(HttpServletRequest req,
455 			    HttpServletResponse resp)
456 	throws ServletException, IOException
457     {
458 	String protocol = req.getProtocol();
459 	String msg = lStrings.getString("http.method_delete_not_supported");
460 	if (protocol.endsWith("1.1")) {
461 	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
462 	} else {
463 	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
464 	}
465     }
466     
467 
468     private static Method[] getAllDeclaredMethods(Class c) {
469 
470         if (c.equals(javax.servlet.http.HttpServlet.class)) {
471             return null;
472         }
473 
474         Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
475         Method[] thisMethods = c.getDeclaredMethods();
476 	
477         if ((parentMethods != null) && (parentMethods.length > 0)) {
478             Method[] allMethods =
479                 new Method[parentMethods.length + thisMethods.length];
480 	    System.arraycopy(parentMethods, 0, allMethods, 0,
481                              parentMethods.length);
482 	    System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
483                              thisMethods.length);
484 
485 	    thisMethods = allMethods;
486 	}
487 
488 	return thisMethods;
489     }
490 
491 
492     /**
493      * Called by the server (via the <code>service</code> method)
494      * to allow a servlet to handle a OPTIONS request.
495      *
496      * The OPTIONS request determines which HTTP methods 
497      * the server supports and
498      * returns an appropriate header. For example, if a servlet
499      * overrides <code>doGet</code>, this method returns the
500      * following header:
501      *
502      * <p><code>Allow: GET, HEAD, TRACE, OPTIONS</code>
503      *
504      * <p>There's no need to override this method unless the
505      * servlet implements new HTTP methods, beyond those 
506      * implemented by HTTP 1.1.
507      *
508      * @param req	the {@link HttpServletRequest} object that
509      *			contains the request the client made of
510      *			the servlet
511      *
512      *
513      * @param resp	the {@link HttpServletResponse} object that
514      *			contains the response the servlet returns
515      *			to the client				
516      *
517      *
518      * @exception IOException	if an input or output error occurs
519      *				while the servlet is handling the
520      *				OPTIONS request
521      *
522      * @exception ServletException	if the request for the
523      *					OPTIONS cannot be handled
524      *
525      */
526          
527     protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
528 	throws ServletException, IOException
529     {
530 	Method[] methods = getAllDeclaredMethods(this.getClass());
531 	
532 	boolean ALLOW_GET = false;
533 	boolean ALLOW_HEAD = false;
534 	boolean ALLOW_POST = false;
535 	boolean ALLOW_PUT = false;
536 	boolean ALLOW_DELETE = false;
537 	boolean ALLOW_TRACE = true;
538 	boolean ALLOW_OPTIONS = true;
539 	
540 	for (int i=0; i<methods.length; i++) {
541 	    Method m = methods[i];
542 	    
543 	    if (m.getName().equals("doGet")) {
544 		ALLOW_GET = true;
545 		ALLOW_HEAD = true;
546 	    }
547 	    if (m.getName().equals("doPost")) 
548 		ALLOW_POST = true;
549 	    if (m.getName().equals("doPut"))
550 		ALLOW_PUT = true;
551 	    if (m.getName().equals("doDelete"))
552 		ALLOW_DELETE = true;
553 	    
554 	}
555 	
556 	String allow = null;
557 	if (ALLOW_GET)
558 	    if (allow==null) allow=METHOD_GET;
559 	if (ALLOW_HEAD)
560 	    if (allow==null) allow=METHOD_HEAD;
561 	    else allow += ", " + METHOD_HEAD;
562 	if (ALLOW_POST)
563 	    if (allow==null) allow=METHOD_POST;
564 	    else allow += ", " + METHOD_POST;
565 	if (ALLOW_PUT)
566 	    if (allow==null) allow=METHOD_PUT;
567 	    else allow += ", " + METHOD_PUT;
568 	if (ALLOW_DELETE)
569 	    if (allow==null) allow=METHOD_DELETE;
570 	    else allow += ", " + METHOD_DELETE;
571 	if (ALLOW_TRACE)
572 	    if (allow==null) allow=METHOD_TRACE;
573 	    else allow += ", " + METHOD_TRACE;
574 	if (ALLOW_OPTIONS)
575 	    if (allow==null) allow=METHOD_OPTIONS;
576 	    else allow += ", " + METHOD_OPTIONS;
577 	
578 	resp.setHeader("Allow", allow);
579     }
580     
581     
582     
583     
584     /**
585      * Called by the server (via the <code>service</code> method)
586      * to allow a servlet to handle a TRACE request.
587      *
588      * A TRACE returns the headers sent with the TRACE
589      * request to the client, so that they can be used in
590      * debugging. There's no need to override this method. 
591      *
592      *
593      *
594      * @param req	the {@link HttpServletRequest} object that
595      *			contains the request the client made of
596      *			the servlet
597      *
598      *
599      * @param resp	the {@link HttpServletResponse} object that
600      *			contains the response the servlet returns
601      *			to the client				
602      *
603      *
604      * @exception IOException	if an input or output error occurs
605      *				while the servlet is handling the
606      *				TRACE request
607      *
608      * @exception ServletException	if the request for the
609      *					TRACE cannot be handled
610      *
611      */
612 
613     protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 
614 	throws ServletException, IOException
615     {
616 	
617 	int responseLength;
618 	
619 	String CRLF = "\r\n";
620 	String responseString = "TRACE "+ req.getRequestURI()+
621 	    " " + req.getProtocol();
622 	
623 	Enumeration reqHeaderEnum = req.getHeaderNames();
624 	
625 	while( reqHeaderEnum.hasMoreElements() ) {
626 	    String headerName = (String)reqHeaderEnum.nextElement();
627 	    responseString += CRLF + headerName + ": " +
628 		req.getHeader(headerName); 
629 	}
630 	
631 	responseString += CRLF;
632 	
633 	responseLength = responseString.length();
634 	
635 	resp.setContentType("message/http");
636 	resp.setContentLength(responseLength);
637 	ServletOutputStream out = resp.getOutputStream();
638 	out.print(responseString);	
639 	out.close();
640 	return;
641     }		
642 
643 
644 
645 
646 
647     /**
648      *
649      * Receives standard HTTP requests from the public
650      * <code>service</code> method and dispatches
651      * them to the <code>do</code><i>XXX</i> methods defined in 
652      * this class. This method is an HTTP-specific version of the 
653      * {@link javax.servlet.Servlet#service} method. There's no
654      * need to override this method.
655      *
656      *
657      *
658      * @param req	the {@link HttpServletRequest} object that
659      *			contains the request the client made of
660      *			the servlet
661      *
662      *
663      * @param resp	the {@link HttpServletResponse} object that
664      *			contains the response the servlet returns
665      *			to the client				
666      *
667      *
668      * @exception IOException	if an input or output error occurs
669      *				while the servlet is handling the
670      *				HTTP request
671      *
672      * @exception ServletException	if the HTTP request
673      *					cannot be handled
674      * 
675      * @see 				javax.servlet.Servlet#service
676      *
677      */
678 
679     protected void service(HttpServletRequest req, HttpServletResponse resp)
680 	throws ServletException, IOException
681     {
682 	String method = req.getMethod();
683 
684 	if (method.equals(METHOD_GET)) {
685 	    long lastModified = getLastModified(req);
686 	    if (lastModified == -1) {
687 		// servlet doesn't support if-modified-since, no reason
688 		// to go through further expensive logic
689 		doGet(req, resp);
690 	    } else {
691 		long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
692 		if (ifModifiedSince < (lastModified / 1000 * 1000)) {
693 		    // If the servlet mod time is later, call doGet()
694                     // Round down to the nearest second for a proper compare
695                     // A ifModifiedSince of -1 will always be less
696 		    maybeSetLastModified(resp, lastModified);
697 		    doGet(req, resp);
698 		} else {
699 		    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
700 		}
701 	    }
702 
703 	} else if (method.equals(METHOD_HEAD)) {
704 	    long lastModified = getLastModified(req);
705 	    maybeSetLastModified(resp, lastModified);
706 	    doHead(req, resp);
707 
708 	} else if (method.equals(METHOD_POST)) {
709 	    doPost(req, resp);
710 	    
711 	} else if (method.equals(METHOD_PUT)) {
712 	    doPut(req, resp);	
713 	    
714 	} else if (method.equals(METHOD_DELETE)) {
715 	    doDelete(req, resp);
716 	    
717 	} else if (method.equals(METHOD_OPTIONS)) {
718 	    doOptions(req,resp);
719 	    
720 	} else if (method.equals(METHOD_TRACE)) {
721 	    doTrace(req,resp);
722 	    
723 	} else {
724 	    //
725 	    // Note that this means NO servlet supports whatever
726 	    // method was requested, anywhere on this server.
727 	    //
728 
729 	    String errMsg = lStrings.getString("http.method_not_implemented");
730 	    Object[] errArgs = new Object[1];
731 	    errArgs[0] = method;
732 	    errMsg = MessageFormat.format(errMsg, errArgs);
733 	    
734 	    resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
735 	}
736     }
737     
738 
739 
740 
741 
742     /*
743      * Sets the Last-Modified entity header field, if it has not
744      * already been set and if the value is meaningful.  Called before
745      * doGet, to ensure that headers are set before response data is
746      * written.  A subclass might have set this header already, so we
747      * check.
748      */
749 
750     private void maybeSetLastModified(HttpServletResponse resp,
751 				      long lastModified) {
752 	if (resp.containsHeader(HEADER_LASTMOD))
753 	    return;
754 	if (lastModified >= 0)
755 	    resp.setDateHeader(HEADER_LASTMOD, lastModified);
756     }
757    
758    
759    
760     
761     /**
762      *
763      * Dispatches client requests to the protected
764      * <code>service</code> method. There's no need to
765      * override this method.
766      *
767      * 
768      * @param req	the {@link HttpServletRequest} object that
769      *			contains the request the client made of
770      *			the servlet
771      *
772      *
773      * @param res	the {@link HttpServletResponse} object that
774      *			contains the response the servlet returns
775      *			to the client				
776      *
777      *
778      * @exception IOException	if an input or output error occurs
779      *				while the servlet is handling the
780      *				HTTP request
781      *
782      * @exception ServletException	if the HTTP request cannot
783      *					be handled
784      *
785      * 
786      * @see javax.servlet.Servlet#service
787      *
788      */
789 
790     public void service(ServletRequest req, ServletResponse res)
791 	throws ServletException, IOException
792     {
793 	HttpServletRequest	request;
794 	HttpServletResponse	response;
795 	
796 	try {
797 	    request = (HttpServletRequest) req;
798 	    response = (HttpServletResponse) res;
799 	} catch (ClassCastException e) {
800 	    throw new ServletException("non-HTTP request or response");
801 	}
802 	service(request, response);
803     }
804 }
805 
806 
807 
808 
809 /*
810  * A response that includes no body, for use in (dumb) "HEAD" support.
811  * This just swallows that body, counting the bytes in order to set
812  * the content length appropriately.  All other methods delegate directly
813  * to the HTTP Servlet Response object used to construct this one.
814  */
815 // file private
816 class NoBodyResponse implements HttpServletResponse {
817     private HttpServletResponse		resp;
818     private NoBodyOutputStream		noBody;
819     private PrintWriter			writer;
820     private boolean			didSetContentLength;
821 
822     // file private
823     NoBodyResponse(HttpServletResponse r) {
824 	resp = r;
825 	noBody = new NoBodyOutputStream();
826     }
827 
828     // file private
829     void setContentLength() {
830 	if (!didSetContentLength)
831 	  resp.setContentLength(noBody.getContentLength());
832     }
833 
834 
835     // SERVLET RESPONSE interface methods
836 
837     public void setContentLength(int len) {
838 	resp.setContentLength(len);
839 	didSetContentLength = true;
840     }
841 
842     public void setCharacterEncoding(String charset)
843       { resp.setCharacterEncoding(charset); }
844 
845     public void setContentType(String type)
846       { resp.setContentType(type); }
847 
848     public String getContentType()
849       { return resp.getContentType(); }
850 
851     public ServletOutputStream getOutputStream() throws IOException
852       { return noBody; }
853 
854     public String getCharacterEncoding()
855 	{ return resp.getCharacterEncoding(); }
856 
857     public PrintWriter getWriter() throws UnsupportedEncodingException
858     {
859 	if (writer == null) {
860 	    OutputStreamWriter	w;
861 
862 	    w = new OutputStreamWriter(noBody, getCharacterEncoding());
863 	    writer = new PrintWriter(w);
864 	}
865 	return writer;
866     }
867 
868     public void setBufferSize(int size) throws IllegalStateException
869       { resp.setBufferSize(size); }
870 
871     public int getBufferSize()
872       { return resp.getBufferSize(); }
873 
874     public void reset() throws IllegalStateException
875       { resp.reset(); }
876       
877       public void resetBuffer() throws IllegalStateException
878       { resp.resetBuffer(); }
879 
880     public boolean isCommitted()
881       { return resp.isCommitted(); }
882 
883     public void flushBuffer() throws IOException
884       { resp.flushBuffer(); }
885 
886     public void setLocale(Locale loc)
887       { resp.setLocale(loc); }
888 
889     public Locale getLocale()
890       { return resp.getLocale(); }
891 
892 
893     // HTTP SERVLET RESPONSE interface methods
894 
895     public void addCookie(Cookie cookie)
896       { resp.addCookie(cookie); }
897 
898     public boolean containsHeader(String name)
899       { return resp.containsHeader(name); }
900 
901     /** @deprecated */
902     public void setStatus(int sc, String sm)
903       { resp.setStatus(sc, sm); }
904 
905     public void setStatus(int sc)
906       { resp.setStatus(sc); }
907 
908     public void setHeader(String name, String value)
909       { resp.setHeader(name, value); }
910 
911     public void setIntHeader(String name, int value)
912       { resp.setIntHeader(name, value); }
913 
914     public void setDateHeader(String name, long date)
915       { resp.setDateHeader(name, date); }
916 
917     public void sendError(int sc, String msg) throws IOException
918       { resp.sendError(sc, msg); }
919 
920     public void sendError(int sc) throws IOException
921       { resp.sendError(sc); }
922 
923     public void sendRedirect(String location) throws IOException
924       { resp.sendRedirect(location); }
925     
926     public String encodeURL(String url) 
927       { return resp.encodeURL(url); }
928 
929     public String encodeRedirectURL(String url)
930       { return resp.encodeRedirectURL(url); }
931       
932     public void addHeader(String name, String value)
933       { resp.addHeader(name, value); }
934       
935     public void addDateHeader(String name, long value)
936       { resp.addDateHeader(name, value); }
937       
938     public void addIntHeader(String name, int value)
939       { resp.addIntHeader(name, value); }
940       
941       
942       
943 
944     /**
945      * @deprecated	As of Version 2.1, replaced by
946      * 			{@link HttpServletResponse#encodeURL}.
947      *
948      */
949      
950      
951     public String encodeUrl(String url) 
952       { return this.encodeURL(url); }
953       
954       
955       
956       
957       
958       
959       
960 
961     /**
962      * @deprecated	As of Version 2.1, replaced by
963      *			{@link HttpServletResponse#encodeRedirectURL}.
964      *
965      */
966      
967      
968     public String encodeRedirectUrl(String url)
969       { return this.encodeRedirectURL(url); }
970 
971 }
972 
973 
974 
975 
976 
977 
978 
979 /*
980  * Servlet output stream that gobbles up all its data.
981  */
982  
983 // file private
984 class NoBodyOutputStream extends ServletOutputStream {
985 
986     private static final String LSTRING_FILE =
987 	"javax.servlet.http.LocalStrings";
988     private static ResourceBundle lStrings =
989 	ResourceBundle.getBundle(LSTRING_FILE);
990 
991     private int		contentLength = 0;
992 
993     // file private
994     NoBodyOutputStream() {}
995 
996     // file private
997     int getContentLength() {
998 	return contentLength;
999     }
1000 
1001     public void write(int b) {
1002 	contentLength++;
1003     }
1004 
1005     public void write(byte buf[], int offset, int len)
1006 	throws IOException
1007     {
1008 	if (len >= 0) {
1009 	    contentLength += len;
1010 	} else {
1011 	    // XXX
1012 	    // isn't this really an IllegalArgumentException?
1013 	    
1014 	    String msg = lStrings.getString("err.io.negativelength");
1015 	    throw new IOException("negative length");
1016 	}
1017     }
1018 }