1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package javax.servlet.http;
17
18 import java.io.IOException;
19 import java.io.PrintWriter;
20 import java.io.OutputStreamWriter;
21 import java.io.UnsupportedEncodingException;
22 import java.lang.reflect.Method;
23 import java.text.MessageFormat;
24 import java.util.Enumeration;
25 import java.util.Locale;
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 *
37 * Provides an abstract class to be subclassed to create
38 * an HTTP servlet suitable for a Web site. A subclass of
39 * <code>HttpServlet</code> must override at least
40 * one method, usually one of these:
41 *
42 * <ul>
43 * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
44 * <li> <code>doPost</code>, for HTTP POST requests
45 * <li> <code>doPut</code>, for HTTP PUT requests
46 * <li> <code>doDelete</code>, for HTTP DELETE requests
47 * <li> <code>init</code> and <code>destroy</code>,
48 * to manage resources that are held for the life of the servlet
49 * <li> <code>getServletInfo</code>, which the servlet uses to
50 * provide information about itself
51 * </ul>
52 *
53 * <p>There's almost no reason to override the <code>service</code>
54 * method. <code>service</code> handles standard HTTP
55 * requests by dispatching them to the handler methods
56 * for each HTTP request type (the <code>do</code><i>XXX</i>
57 * methods listed above).
58 *
59 * <p>Likewise, there's almost no reason to override the
60 * <code>doOptions</code> and <code>doTrace</code> methods.
61 *
62 * <p>Servlets typically run on multithreaded servers,
63 * so be aware that a servlet must handle concurrent
64 * requests and be careful to synchronize access to shared resources.
65 * Shared resources include in-memory data such as
66 * instance or class variables and external objects
67 * such as files, database connections, and network
68 * connections.
69 * See the
70 * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
71 * Java Tutorial on Multithreaded Programming</a> for more
72 * information on handling multiple threads in a Java program.
73 *
74 * @author Various
75 * @version $Version$
76 *
77 */
78
79
80
81 public abstract class HttpServlet extends GenericServlet
82 implements java.io.Serializable
83 {
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
102
103 /**
104 * Does nothing, because this is an abstract class.
105 *
106 */
107
108 public HttpServlet() { }
109
110
111
112 /**
113 *
114 * Called by the server (via the <code>service</code> method) to
115 * allow a servlet to handle a GET request.
116 *
117 * <p>Overriding this method to support a GET request also
118 * automatically supports an HTTP HEAD request. A HEAD
119 * request is a GET request that returns no body in the
120 * response, only the request header fields.
121 *
122 * <p>When overriding this method, read the request data,
123 * write the response headers, get the response's writer or
124 * output stream object, and finally, write the response data.
125 * It's best to include content type and encoding. When using
126 * a <code>PrintWriter</code> object to return the response,
127 * set the content type before accessing the
128 * <code>PrintWriter</code> object.
129 *
130 * <p>The servlet container must write the headers before
131 * committing the response, because in HTTP the headers must be sent
132 * before the response body.
133 *
134 * <p>Where possible, set the Content-Length header (with the
135 * {@link javax.servlet.ServletResponse#setContentLength} method),
136 * to allow the servlet container to use a persistent connection
137 * to return its response to the client, improving performance.
138 * The content length is automatically set if the entire response fits
139 * inside the response buffer.
140 *
141 * <p>When using HTTP 1.1 chunked encoding (which means that the response
142 * has a Transfer-Encoding header), do not set the Content-Length header.
143 *
144 * <p>The GET method should be safe, that is, without
145 * any side effects for which users are held responsible.
146 * For example, most form queries have no side effects.
147 * If a client request is intended to change stored data,
148 * the request should use some other HTTP method.
149 *
150 * <p>The GET method should also be idempotent, meaning
151 * that it can be safely repeated. Sometimes making a
152 * method safe also makes it idempotent. For example,
153 * repeating queries is both safe and idempotent, but
154 * buying a product online or modifying data is neither
155 * safe nor idempotent.
156 *
157 * <p>If the request is incorrectly formatted, <code>doGet</code>
158 * returns an HTTP "Bad Request" message.
159 *
160 *
161 * @param req an {@link HttpServletRequest} object that
162 * contains the request the client has made
163 * of the servlet
164 *
165 * @param resp an {@link HttpServletResponse} object that
166 * contains the response the servlet sends
167 * to the client
168 *
169 * @exception IOException if an input or output error is
170 * detected when the servlet handles
171 * the GET request
172 *
173 * @exception ServletException if the request for the GET
174 * could not be handled
175 *
176 *
177 * @see javax.servlet.ServletResponse#setContentType
178 *
179 */
180
181 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
182 throws ServletException, IOException
183 {
184 String protocol = req.getProtocol();
185 String msg = lStrings.getString("http.method_get_not_supported");
186 if (protocol.endsWith("1.1")) {
187 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
188 } else {
189 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
190 }
191 }
192
193
194
195
196
197 /**
198 *
199 * Returns the time the <code>HttpServletRequest</code>
200 * object was last modified,
201 * in milliseconds since midnight January 1, 1970 GMT.
202 * If the time is unknown, this method returns a negative
203 * number (the default).
204 *
205 * <p>Servlets that support HTTP GET requests and can quickly determine
206 * their last modification time should override this method.
207 * This makes browser and proxy caches work more effectively,
208 * reducing the load on server and network resources.
209 *
210 *
211 * @param req the <code>HttpServletRequest</code>
212 * object that is sent to the servlet
213 *
214 * @return a <code>long</code> integer specifying
215 * the time the <code>HttpServletRequest</code>
216 * object was last modified, in milliseconds
217 * since midnight, January 1, 1970 GMT, or
218 * -1 if the time is not known
219 *
220 */
221
222 protected long getLastModified(HttpServletRequest req) {
223 return -1;
224 }
225
226
227
228
229 /**
230 *
231 *
232 * <p>Receives an HTTP HEAD request from the protected
233 * <code>service</code> method and handles the
234 * request.
235 * The client sends a HEAD request when it wants
236 * to see only the headers of a response, such as
237 * Content-Type or Content-Length. The HTTP HEAD
238 * method counts the output bytes in the response
239 * to set the Content-Length header accurately.
240 *
241 * <p>If you override this method, you can avoid computing
242 * the response body and just set the response headers
243 * directly to improve performance. Make sure that the
244 * <code>doHead</code> method you write is both safe
245 * and idempotent (that is, protects itself from being
246 * called multiple times for one HTTP HEAD request).
247 *
248 * <p>If the HTTP HEAD request is incorrectly formatted,
249 * <code>doHead</code> returns an HTTP "Bad Request"
250 * message.
251 *
252 *
253 * @param req the request object that is passed
254 * to the servlet
255 *
256 * @param resp the response object that the servlet
257 * uses to return the headers to the clien
258 *
259 * @exception IOException if an input or output error occurs
260 *
261 * @exception ServletException if the request for the HEAD
262 * could not be handled
263 */
264
265 protected void doHead(HttpServletRequest req, HttpServletResponse resp)
266 throws ServletException, IOException
267 {
268 NoBodyResponse response = new NoBodyResponse(resp);
269
270 doGet(req, response);
271 response.setContentLength();
272 }
273
274
275
276
277
278 /**
279 *
280 * Called by the server (via the <code>service</code> method)
281 * to allow a servlet to handle a POST request.
282 *
283 * The HTTP POST method allows the client to send
284 * data of unlimited length to the Web server a single time
285 * and is useful when posting information such as
286 * credit card numbers.
287 *
288 * <p>When overriding this method, read the request data,
289 * write the response headers, get the response's writer or output
290 * stream object, and finally, write the response data. It's best
291 * to include content type and encoding. When using a
292 * <code>PrintWriter</code> object to return the response, set the
293 * content type before accessing the <code>PrintWriter</code> object.
294 *
295 * <p>The servlet container must write the headers before committing the
296 * response, because in HTTP the headers must be sent before the
297 * response body.
298 *
299 * <p>Where possible, set the Content-Length header (with the
300 * {@link javax.servlet.ServletResponse#setContentLength} method),
301 * to allow the servlet container to use a persistent connection
302 * to return its response to the client, improving performance.
303 * The content length is automatically set if the entire response fits
304 * inside the response buffer.
305 *
306 * <p>When using HTTP 1.1 chunked encoding (which means that the response
307 * has a Transfer-Encoding header), do not set the Content-Length header.
308 *
309 * <p>This method does not need to be either safe or idempotent.
310 * Operations requested through POST can have side effects for
311 * which the user can be held accountable, for example,
312 * updating stored data or buying items online.
313 *
314 * <p>If the HTTP POST request is incorrectly formatted,
315 * <code>doPost</code> returns an HTTP "Bad Request" message.
316 *
317 *
318 * @param req an {@link HttpServletRequest} object that
319 * contains the request the client has made
320 * of the servlet
321 *
322 * @param resp an {@link HttpServletResponse} object that
323 * contains the response the servlet sends
324 * to the client
325 *
326 * @exception IOException if an input or output error is
327 * detected when the servlet handles
328 * the request
329 *
330 * @exception ServletException if the request for the POST
331 * could not be handled
332 *
333 *
334 * @see javax.servlet.ServletOutputStream
335 * @see javax.servlet.ServletResponse#setContentType
336 *
337 *
338 */
339
340 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
341 throws ServletException, IOException
342 {
343 String protocol = req.getProtocol();
344 String msg = lStrings.getString("http.method_post_not_supported");
345 if (protocol.endsWith("1.1")) {
346 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
347 } else {
348 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
349 }
350 }
351
352
353
354
355 /**
356 * Called by the server (via the <code>service</code> method)
357 * to allow a servlet to handle a PUT request.
358 *
359 * The PUT operation allows a client to
360 * place a file on the server and is similar to
361 * sending a file by FTP.
362 *
363 * <p>When overriding this method, leave intact
364 * any content headers sent with the request (including
365 * Content-Length, Content-Type, Content-Transfer-Encoding,
366 * Content-Encoding, Content-Base, Content-Language, Content-Location,
367 * Content-MD5, and Content-Range). If your method cannot
368 * handle a content header, it must issue an error message
369 * (HTTP 501 - Not Implemented) and discard the request.
370 * For more information on HTTP 1.1, see RFC 2616
371 * <a href="http://www.ietf.org/rfc/rfc2616.txt"></a>.
372 *
373 * <p>This method does not need to be either safe or idempotent.
374 * Operations that <code>doPut</code> performs can have side
375 * effects for which the user can be held accountable. When using
376 * this method, it may be useful to save a copy of the
377 * affected URL in temporary storage.
378 *
379 * <p>If the HTTP PUT request is incorrectly formatted,
380 * <code>doPut</code> returns an HTTP "Bad Request" message.
381 *
382 *
383 * @param req the {@link HttpServletRequest} object that
384 * contains the request the client made of
385 * the servlet
386 *
387 * @param resp the {@link HttpServletResponse} object that
388 * contains the response the servlet returns
389 * to the client
390 *
391 * @exception IOException if an input or output error occurs
392 * while the servlet is handling the
393 * PUT request
394 *
395 * @exception ServletException if the request for the PUT
396 * cannot be handled
397 *
398 */
399
400 protected void doPut(HttpServletRequest req, HttpServletResponse resp)
401 throws ServletException, IOException
402 {
403 String protocol = req.getProtocol();
404 String msg = lStrings.getString("http.method_put_not_supported");
405 if (protocol.endsWith("1.1")) {
406 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
407 } else {
408 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
409 }
410 }
411
412
413
414
415 /**
416 *
417 * Called by the server (via the <code>service</code> method)
418 * to allow a servlet to handle a DELETE request.
419 *
420 * The DELETE operation allows a client to remove a document
421 * or Web page from the server.
422 *
423 * <p>This method does not need to be either safe
424 * or idempotent. Operations requested through
425 * DELETE can have side effects for which users
426 * can be held accountable. When using
427 * this method, it may be useful to save a copy of the
428 * affected URL in temporary storage.
429 *
430 * <p>If the HTTP DELETE request is incorrectly formatted,
431 * <code>doDelete</code> returns an HTTP "Bad Request"
432 * message.
433 *
434 *
435 * @param req the {@link HttpServletRequest} object that
436 * contains the request the client made of
437 * the servlet
438 *
439 *
440 * @param resp the {@link HttpServletResponse} object that
441 * contains the response the servlet returns
442 * to the client
443 *
444 *
445 * @exception IOException if an input or output error occurs
446 * while the servlet is handling the
447 * DELETE request
448 *
449 * @exception ServletException if the request for the
450 * DELETE cannot be handled
451 *
452 */
453
454 protected void doDelete(HttpServletRequest req,
455 HttpServletResponse resp)
456 throws ServletException, IOException
457 {
458 String protocol = req.getProtocol();
459 String msg = lStrings.getString("http.method_delete_not_supported");
460 if (protocol.endsWith("1.1")) {
461 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
462 } else {
463 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
464 }
465 }
466
467
468 private static Method[] getAllDeclaredMethods(Class c) {
469
470 if (c.equals(javax.servlet.http.HttpServlet.class)) {
471 return null;
472 }
473
474 Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
475 Method[] thisMethods = c.getDeclaredMethods();
476
477 if ((parentMethods != null) && (parentMethods.length > 0)) {
478 Method[] allMethods =
479 new Method[parentMethods.length + thisMethods.length];
480 System.arraycopy(parentMethods, 0, allMethods, 0,
481 parentMethods.length);
482 System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
483 thisMethods.length);
484
485 thisMethods = allMethods;
486 }
487
488 return thisMethods;
489 }
490
491
492 /**
493 * Called by the server (via the <code>service</code> method)
494 * to allow a servlet to handle a OPTIONS request.
495 *
496 * The OPTIONS request determines which HTTP methods
497 * the server supports and
498 * returns an appropriate header. For example, if a servlet
499 * overrides <code>doGet</code>, this method returns the
500 * following header:
501 *
502 * <p><code>Allow: GET, HEAD, TRACE, OPTIONS</code>
503 *
504 * <p>There's no need to override this method unless the
505 * servlet implements new HTTP methods, beyond those
506 * implemented by HTTP 1.1.
507 *
508 * @param req the {@link HttpServletRequest} object that
509 * contains the request the client made of
510 * the servlet
511 *
512 *
513 * @param resp the {@link HttpServletResponse} object that
514 * contains the response the servlet returns
515 * to the client
516 *
517 *
518 * @exception IOException if an input or output error occurs
519 * while the servlet is handling the
520 * OPTIONS request
521 *
522 * @exception ServletException if the request for the
523 * OPTIONS cannot be handled
524 *
525 */
526
527 protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
528 throws ServletException, IOException
529 {
530 Method[] methods = getAllDeclaredMethods(this.getClass());
531
532 boolean ALLOW_GET = false;
533 boolean ALLOW_HEAD = false;
534 boolean ALLOW_POST = false;
535 boolean ALLOW_PUT = false;
536 boolean ALLOW_DELETE = false;
537 boolean ALLOW_TRACE = true;
538 boolean ALLOW_OPTIONS = true;
539
540 for (int i=0; i<methods.length; i++) {
541 Method m = methods[i];
542
543 if (m.getName().equals("doGet")) {
544 ALLOW_GET = true;
545 ALLOW_HEAD = true;
546 }
547 if (m.getName().equals("doPost"))
548 ALLOW_POST = true;
549 if (m.getName().equals("doPut"))
550 ALLOW_PUT = true;
551 if (m.getName().equals("doDelete"))
552 ALLOW_DELETE = true;
553
554 }
555
556 String allow = null;
557 if (ALLOW_GET)
558 if (allow==null) allow=METHOD_GET;
559 if (ALLOW_HEAD)
560 if (allow==null) allow=METHOD_HEAD;
561 else allow += ", " + METHOD_HEAD;
562 if (ALLOW_POST)
563 if (allow==null) allow=METHOD_POST;
564 else allow += ", " + METHOD_POST;
565 if (ALLOW_PUT)
566 if (allow==null) allow=METHOD_PUT;
567 else allow += ", " + METHOD_PUT;
568 if (ALLOW_DELETE)
569 if (allow==null) allow=METHOD_DELETE;
570 else allow += ", " + METHOD_DELETE;
571 if (ALLOW_TRACE)
572 if (allow==null) allow=METHOD_TRACE;
573 else allow += ", " + METHOD_TRACE;
574 if (ALLOW_OPTIONS)
575 if (allow==null) allow=METHOD_OPTIONS;
576 else allow += ", " + METHOD_OPTIONS;
577
578 resp.setHeader("Allow", allow);
579 }
580
581
582
583
584 /**
585 * Called by the server (via the <code>service</code> method)
586 * to allow a servlet to handle a TRACE request.
587 *
588 * A TRACE returns the headers sent with the TRACE
589 * request to the client, so that they can be used in
590 * debugging. There's no need to override this method.
591 *
592 *
593 *
594 * @param req the {@link HttpServletRequest} object that
595 * contains the request the client made of
596 * the servlet
597 *
598 *
599 * @param resp the {@link HttpServletResponse} object that
600 * contains the response the servlet returns
601 * to the client
602 *
603 *
604 * @exception IOException if an input or output error occurs
605 * while the servlet is handling the
606 * TRACE request
607 *
608 * @exception ServletException if the request for the
609 * TRACE cannot be handled
610 *
611 */
612
613 protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
614 throws ServletException, IOException
615 {
616
617 int responseLength;
618
619 String CRLF = "\r\n";
620 String responseString = "TRACE "+ req.getRequestURI()+
621 " " + req.getProtocol();
622
623 Enumeration reqHeaderEnum = req.getHeaderNames();
624
625 while( reqHeaderEnum.hasMoreElements() ) {
626 String headerName = (String)reqHeaderEnum.nextElement();
627 responseString += CRLF + headerName + ": " +
628 req.getHeader(headerName);
629 }
630
631 responseString += CRLF;
632
633 responseLength = responseString.length();
634
635 resp.setContentType("message/http");
636 resp.setContentLength(responseLength);
637 ServletOutputStream out = resp.getOutputStream();
638 out.print(responseString);
639 out.close();
640 return;
641 }
642
643
644
645
646
647 /**
648 *
649 * Receives standard HTTP requests from the public
650 * <code>service</code> method and dispatches
651 * them to the <code>do</code><i>XXX</i> methods defined in
652 * this class. This method is an HTTP-specific version of the
653 * {@link javax.servlet.Servlet#service} method. There's no
654 * need to override this method.
655 *
656 *
657 *
658 * @param req the {@link HttpServletRequest} object that
659 * contains the request the client made of
660 * the servlet
661 *
662 *
663 * @param resp the {@link HttpServletResponse} object that
664 * contains the response the servlet returns
665 * to the client
666 *
667 *
668 * @exception IOException if an input or output error occurs
669 * while the servlet is handling the
670 * HTTP request
671 *
672 * @exception ServletException if the HTTP request
673 * cannot be handled
674 *
675 * @see javax.servlet.Servlet#service
676 *
677 */
678
679 protected void service(HttpServletRequest req, HttpServletResponse resp)
680 throws ServletException, IOException
681 {
682 String method = req.getMethod();
683
684 if (method.equals(METHOD_GET)) {
685 long lastModified = getLastModified(req);
686 if (lastModified == -1) {
687
688
689 doGet(req, resp);
690 } else {
691 long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
692 if (ifModifiedSince < (lastModified / 1000 * 1000)) {
693
694
695
696 maybeSetLastModified(resp, lastModified);
697 doGet(req, resp);
698 } else {
699 resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
700 }
701 }
702
703 } else if (method.equals(METHOD_HEAD)) {
704 long lastModified = getLastModified(req);
705 maybeSetLastModified(resp, lastModified);
706 doHead(req, resp);
707
708 } else if (method.equals(METHOD_POST)) {
709 doPost(req, resp);
710
711 } else if (method.equals(METHOD_PUT)) {
712 doPut(req, resp);
713
714 } else if (method.equals(METHOD_DELETE)) {
715 doDelete(req, resp);
716
717 } else if (method.equals(METHOD_OPTIONS)) {
718 doOptions(req,resp);
719
720 } else if (method.equals(METHOD_TRACE)) {
721 doTrace(req,resp);
722
723 } else {
724
725
726
727
728
729 String errMsg = lStrings.getString("http.method_not_implemented");
730 Object[] errArgs = new Object[1];
731 errArgs[0] = method;
732 errMsg = MessageFormat.format(errMsg, errArgs);
733
734 resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
735 }
736 }
737
738
739
740
741
742
743
744
745
746
747
748
749
750 private void maybeSetLastModified(HttpServletResponse resp,
751 long lastModified) {
752 if (resp.containsHeader(HEADER_LASTMOD))
753 return;
754 if (lastModified >= 0)
755 resp.setDateHeader(HEADER_LASTMOD, lastModified);
756 }
757
758
759
760
761 /**
762 *
763 * Dispatches client requests to the protected
764 * <code>service</code> method. There's no need to
765 * override this method.
766 *
767 *
768 * @param req the {@link HttpServletRequest} object that
769 * contains the request the client made of
770 * the servlet
771 *
772 *
773 * @param res the {@link HttpServletResponse} object that
774 * contains the response the servlet returns
775 * to the client
776 *
777 *
778 * @exception IOException if an input or output error occurs
779 * while the servlet is handling the
780 * HTTP request
781 *
782 * @exception ServletException if the HTTP request cannot
783 * be handled
784 *
785 *
786 * @see javax.servlet.Servlet#service
787 *
788 */
789
790 public void service(ServletRequest req, ServletResponse res)
791 throws ServletException, IOException
792 {
793 HttpServletRequest request;
794 HttpServletResponse response;
795
796 try {
797 request = (HttpServletRequest) req;
798 response = (HttpServletResponse) res;
799 } catch (ClassCastException e) {
800 throw new ServletException("non-HTTP request or response");
801 }
802 service(request, response);
803 }
804 }
805
806
807
808
809
810
811
812
813
814
815
816 class NoBodyResponse implements HttpServletResponse {
817 private HttpServletResponse resp;
818 private NoBodyOutputStream noBody;
819 private PrintWriter writer;
820 private boolean didSetContentLength;
821
822
823 NoBodyResponse(HttpServletResponse r) {
824 resp = r;
825 noBody = new NoBodyOutputStream();
826 }
827
828
829 void setContentLength() {
830 if (!didSetContentLength)
831 resp.setContentLength(noBody.getContentLength());
832 }
833
834
835
836
837 public void setContentLength(int len) {
838 resp.setContentLength(len);
839 didSetContentLength = true;
840 }
841
842 public void setCharacterEncoding(String charset)
843 { resp.setCharacterEncoding(charset); }
844
845 public void setContentType(String type)
846 { resp.setContentType(type); }
847
848 public String getContentType()
849 { return resp.getContentType(); }
850
851 public ServletOutputStream getOutputStream() throws IOException
852 { return noBody; }
853
854 public String getCharacterEncoding()
855 { return resp.getCharacterEncoding(); }
856
857 public PrintWriter getWriter() throws UnsupportedEncodingException
858 {
859 if (writer == null) {
860 OutputStreamWriter w;
861
862 w = new OutputStreamWriter(noBody, getCharacterEncoding());
863 writer = new PrintWriter(w);
864 }
865 return writer;
866 }
867
868 public void setBufferSize(int size) throws IllegalStateException
869 { resp.setBufferSize(size); }
870
871 public int getBufferSize()
872 { return resp.getBufferSize(); }
873
874 public void reset() throws IllegalStateException
875 { resp.reset(); }
876
877 public void resetBuffer() throws IllegalStateException
878 { resp.resetBuffer(); }
879
880 public boolean isCommitted()
881 { return resp.isCommitted(); }
882
883 public void flushBuffer() throws IOException
884 { resp.flushBuffer(); }
885
886 public void setLocale(Locale loc)
887 { resp.setLocale(loc); }
888
889 public Locale getLocale()
890 { return resp.getLocale(); }
891
892
893
894
895 public void addCookie(Cookie cookie)
896 { resp.addCookie(cookie); }
897
898 public boolean containsHeader(String name)
899 { return resp.containsHeader(name); }
900
901 /** @deprecated */
902 public void setStatus(int sc, String sm)
903 { resp.setStatus(sc, sm); }
904
905 public void setStatus(int sc)
906 { resp.setStatus(sc); }
907
908 public void setHeader(String name, String value)
909 { resp.setHeader(name, value); }
910
911 public void setIntHeader(String name, int value)
912 { resp.setIntHeader(name, value); }
913
914 public void setDateHeader(String name, long date)
915 { resp.setDateHeader(name, date); }
916
917 public void sendError(int sc, String msg) throws IOException
918 { resp.sendError(sc, msg); }
919
920 public void sendError(int sc) throws IOException
921 { resp.sendError(sc); }
922
923 public void sendRedirect(String location) throws IOException
924 { resp.sendRedirect(location); }
925
926 public String encodeURL(String url)
927 { return resp.encodeURL(url); }
928
929 public String encodeRedirectURL(String url)
930 { return resp.encodeRedirectURL(url); }
931
932 public void addHeader(String name, String value)
933 { resp.addHeader(name, value); }
934
935 public void addDateHeader(String name, long value)
936 { resp.addDateHeader(name, value); }
937
938 public void addIntHeader(String name, int value)
939 { resp.addIntHeader(name, value); }
940
941
942
943
944 /**
945 * @deprecated As of Version 2.1, replaced by
946 * {@link HttpServletResponse#encodeURL}.
947 *
948 */
949
950
951 public String encodeUrl(String url)
952 { return this.encodeURL(url); }
953
954
955
956
957
958
959
960
961 /**
962 * @deprecated As of Version 2.1, replaced by
963 * {@link HttpServletResponse#encodeRedirectURL}.
964 *
965 */
966
967
968 public String encodeRedirectUrl(String url)
969 { return this.encodeRedirectURL(url); }
970
971 }
972
973
974
975
976
977
978
979
980
981
982
983
984 class NoBodyOutputStream extends ServletOutputStream {
985
986 private static final String LSTRING_FILE =
987 "javax.servlet.http.LocalStrings";
988 private static ResourceBundle lStrings =
989 ResourceBundle.getBundle(LSTRING_FILE);
990
991 private int contentLength = 0;
992
993
994 NoBodyOutputStream() {}
995
996
997 int getContentLength() {
998 return contentLength;
999 }
1000
1001 public void write(int b) {
1002 contentLength++;
1003 }
1004
1005 public void write(byte buf[], int offset, int len)
1006 throws IOException
1007 {
1008 if (len >= 0) {
1009 contentLength += len;
1010 } else {
1011
1012
1013
1014 String msg = lStrings.getString("err.io.negativelength");
1015 throw new IOException("negative length");
1016 }
1017 }
1018 }