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-25 06:01:51 +0200 (Mi, 25. Okt 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 }