1 /**
2 *
3 * Copyright 2003-2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * 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
18
19
20
21
22
23
24 package javax.servlet.http;
25
26 import java.io.IOException;
27 import java.io.OutputStreamWriter;
28 import java.io.PrintWriter;
29 import java.io.UnsupportedEncodingException;
30 import java.lang.reflect.Method;
31 import java.text.MessageFormat;
32 import java.util.Enumeration;
33 import java.util.Locale;
34 import java.util.ResourceBundle;
35 import javax.servlet.GenericServlet;
36 import javax.servlet.ServletException;
37 import javax.servlet.ServletOutputStream;
38 import javax.servlet.ServletRequest;
39 import javax.servlet.ServletResponse;
40
41
42 /**
43 * Provides an abstract class to be subclassed to create
44 * an HTTP servlet suitable for a Web site. A subclass of
45 * <code>HttpServlet</code> must override at least
46 * one method, usually one of these:
47 *
48 * <ul>
49 * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
50 * <li> <code>doPost</code>, for HTTP POST requests
51 * <li> <code>doPut</code>, for HTTP PUT requests
52 * <li> <code>doDelete</code>, for HTTP DELETE requests
53 * <li> <code>init</code> and <code>destroy</code>,
54 * to manage resources that are held for the life of the servlet
55 * <li> <code>getServletInfo</code>, which the servlet uses to
56 * provide information about itself
57 * </ul>
58 *
59 * <p>There's almost no reason to override the <code>service</code>
60 * method. <code>service</code> handles standard HTTP
61 * requests by dispatching them to the handler methods
62 * for each HTTP request type (the <code>do</code><i>XXX</i>
63 * methods listed above).
64 *
65 * <p>Likewise, there's almost no reason to override the
66 * <code>doOptions</code> and <code>doTrace</code> methods.
67 *
68 * <p>Servlets typically run on multithreaded servers,
69 * so be aware that a servlet must handle concurrent
70 * requests and be careful to synchronize access to shared resources.
71 * Shared resources include in-memory data such as
72 * instance or class variables and external objects
73 * such as files, database connections, and network
74 * connections.
75 * See the
76 * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
77 * Java Tutorial on Multithreaded Programming</a> for more
78 * information on handling multiple threads in a Java program.
79 *
80 * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
81 */
82 public abstract class HttpServlet extends GenericServlet
83 implements java.io.Serializable {
84 private static final String METHOD_DELETE = "DELETE";
85 private static final String METHOD_HEAD = "HEAD";
86 private static final String METHOD_GET = "GET";
87 private static final String METHOD_OPTIONS = "OPTIONS";
88 private static final String METHOD_POST = "POST";
89 private static final String METHOD_PUT = "PUT";
90 private static final String METHOD_TRACE = "TRACE";
91
92 private static final String HEADER_IFMODSINCE = "If-Modified-Since";
93 private static final String HEADER_LASTMOD = "Last-Modified";
94
95 private static final String LSTRING_FILE =
96 "javax.servlet.http.LocalStrings";
97 private static ResourceBundle lStrings =
98 ResourceBundle.getBundle(LSTRING_FILE);
99
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
594
595 doGet(req, resp);
596 } else {
597 long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
598 if (ifModifiedSince < (lastModified / 1000 * 1000)) {
599
600
601
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
632
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
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
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
899
900
901 String msg = lStrings.getString("err.io.negativelength");
902 throw new IOException("negative length");
903 }
904 }
905 }