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