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