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