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