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