Quadcap Embeddable Server

com/quadcap/http/server22/HttpResponse.java

Go to the documentation of this file.
00001 package com.quadcap.http.server22; 00002 00003 /* Copyright 1997 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.util.Calendar; 00042 import java.util.Date; 00043 import java.util.Enumeration; 00044 import java.util.Hashtable; 00045 import java.util.Locale; 00046 import java.util.TimeZone; 00047 import java.util.Vector; 00048 00049 import java.text.DateFormat; 00050 import java.text.SimpleDateFormat; 00051 00052 import java.io.ByteArrayOutputStream; 00053 import java.io.IOException; 00054 import java.io.OutputStream; 00055 import java.io.OutputStreamWriter; 00056 import java.io.PrintWriter; 00057 00058 import javax.servlet.ServletOutputStream; 00059 import javax.servlet.http.Cookie; 00060 import javax.servlet.http.HttpServletResponse; 00061 00062 import com.quadcap.net.server.WorkerOutputStream; 00063 00064 import com.quadcap.util.Debug; 00065 00066 /** 00067 * An HTTP servlet response. This interface allows a servlet's 00068 * <code>service</code> method to manipulate HTTP-protocol specified 00069 * header information and return data to its client. It is implemented 00070 * by network service developers for use within servlets. 00071 * 00072 * @author Stan Bailes 00073 */ 00074 public class HttpResponse implements HttpServletResponse { 00075 WebWorker w; 00076 Hashtable headers = new Hashtable(); 00077 String protocol; 00078 int sc = SC_OK; 00079 String sm = "Request Completed"; 00080 boolean changedCode = false; 00081 Locale defaultLocale = Locale.getDefault(); 00082 Locale locale = defaultLocale; 00083 00084 int contentLength = -1; 00085 String contentType = null; 00086 StringBuffer headerBuf = new StringBuffer(); 00087 boolean headerBufValid = true; 00088 boolean anyHeaders = false; 00089 boolean keepAlive = false; 00090 public boolean getWriterCalled = false; 00091 public boolean getOutputStreamCalled = false; 00092 00093 byte[] fixedHeaders = null; 00094 ByteArrayOutputStream fixedH = new ByteArrayOutputStream(); 00095 00096 HttpOutputStream os; 00097 PrintWriter writer = null; 00098 JspWriter jWriter = new JspWriter(8192, true); 00099 boolean jWriterInit = false; 00100 00101 Vector cookies = null; 00102 long calbase = -1; 00103 byte[] curTime = null; 00104 00105 static DateFormat cookieDateFormat; 00106 static TimeZone GMT; 00107 static SimpleDateFormat df; 00108 static SimpleDateFormat df2; 00109 00110 static { 00111 GMT = TimeZone.getTimeZone("GMT"); 00112 cookieDateFormat = new SimpleDateFormat("E, dd-MMM-yy HH:mm:ss 'GMT'"); 00113 cookieDateFormat.setTimeZone(GMT); 00114 df = new SimpleDateFormat("'Date: 'EEE, dd MMM yyyy HH:mm:ss 'GMT\r\n'"); 00115 df.setTimeZone(GMT); 00116 df2 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'"); 00117 df2.setTimeZone(GMT); 00118 } 00119 00120 /** 00121 * Construct a new HttpResponse for the specified worker. 00122 * 00123 * @param w the worker handling this http request 00124 */ 00125 public HttpResponse(WebWorker w) { 00126 this.w = w; 00127 } 00128 00129 public void reset(HttpOutputStream os) { 00130 this.os = os; 00131 this.os.setResponse(this); 00132 headers.clear(); 00133 sc = SC_OK; 00134 jWriterInit = false; 00135 sm = "Request Completed"; 00136 changedCode = false; 00137 locale = defaultLocale; 00138 contentLength = -1; 00139 contentType = null; 00140 headerBuf.setLength(0); 00141 headerBufValid = true; 00142 writer = null; 00143 cookies = null; 00144 anyHeaders = false; 00145 getWriterCalled = false; 00146 getOutputStreamCalled = false; 00147 } 00148 00149 void setProtocol(String p) { 00150 this.protocol = p; 00151 } 00152 00153 void setKeepAlive(boolean v) { 00154 this.keepAlive = v; 00155 } 00156 00157 static final void write(OutputStream out, String s) throws IOException { 00158 for (int i = 0; i < s.length(); i++) { 00159 out.write((byte)s.charAt(i)); 00160 } 00161 } 00162 00163 static final byte[] headerSep = { (byte)':', (byte)' ' }; 00164 static final byte[] CRLF = { (byte)'\r', (byte)'\n' }; 00165 static final byte[] OKRESPONSE = 00166 " 200 Request Completed\r\n".getBytes(); 00167 static final byte[] CONTENT_TYPE = "Content-Type: ".getBytes(); 00168 static final byte[] CONTENT_LENGTH = "Content-Length: ".getBytes(); 00169 static final byte[] CONNECTION_KEEPALIVE = 00170 "Connection: Keep-Alive\r\n".getBytes(); 00171 static final byte[] CONNECTION_CLOSE = 00172 "Connection: Close\r\n".getBytes(); 00173 static final byte[] DEFAULT_CONTENT_TYPE = 00174 "Content-Type: text/plain\r\n".getBytes(); 00175 00176 final void writeHeader(WorkerOutputStream out, String name, String val) 00177 throws IOException 00178 { 00179 //#ifdef DEBUG 00180 if (Trace.level() > 1) { 00181 Debug.println("header: " + name + ": " + val); 00182 } 00183 //#endif 00184 out.write(name); 00185 out.write(headerSep); 00186 out.write(val); // XXX folding? 00187 out.write(CRLF); 00188 } 00189 00190 /** 00191 * Write the result code and the message headers for the response 00192 */ 00193 public void writeHeaders() throws IOException { 00194 WorkerOutputStream out = os.getOutputStream(); 00195 out.write(protocol); 00196 if (changedCode) { 00197 out.write(' '); 00198 out.writeInt(sc); 00199 out.write(' '); 00200 out.write(sm); 00201 out.write(CRLF); 00202 } else { 00203 out.write(OKRESPONSE); 00204 } 00205 00206 if (keepAlive) { 00207 out.write(CONNECTION_KEEPALIVE); 00208 } else { 00209 out.write(CONNECTION_CLOSE); 00210 } 00211 00212 if (contentType != null) { 00213 out.write(CONTENT_TYPE); 00214 out.write(contentType); 00215 out.write(CRLF); 00216 } else { 00217 out.write(DEFAULT_CONTENT_TYPE); 00218 } 00219 00220 if (contentLength >= 0) { 00221 out.write(CONTENT_LENGTH); 00222 out.writeInt(contentLength); 00223 out.write(CRLF); 00224 } 00225 if (fixedHeaders == null) { 00226 if (fixedH != null) { 00227 fixedHeaders = fixedH.toByteArray(); 00228 fixedH = null; 00229 } 00230 out.write(fixedHeaders); 00231 } 00232 00233 if (headerBufValid) { 00234 out.write(headerBuf.toString()); 00235 } else if (anyHeaders) { 00236 Enumeration hdrs = headers.keys(); 00237 while (hdrs.hasMoreElements()) { 00238 String headerName = (String)hdrs.nextElement(); 00239 Object headerVal = headers.get(headerName); 00240 if (headerVal instanceof String) { 00241 writeHeader(out, headerName, headerVal.toString()); 00242 } else { 00243 Vector v = (Vector)headerVal; 00244 for (int i = 0; i < v.size(); i++) { 00245 writeHeader(out, headerName, v.elementAt(i).toString()); 00246 } 00247 } 00248 } 00249 } 00250 00251 if (cookies != null) { 00252 writeCookies(out); 00253 } 00254 writeDateHeader(out); 00255 out.write(CRLF); 00256 } 00257 00258 static byte[] digits = "0123456789".getBytes(); 00259 static byte[] GMTString = " GMT\r\n".getBytes(); 00260 00261 final void writeDateHeader(WorkerOutputStream out) throws IOException { 00262 long now = System.currentTimeMillis(); 00263 long msec = now - calbase; 00264 if (msec >= 60000) { 00265 Calendar c = Calendar.getInstance(GMT); 00266 c.setTime(new Date(now)); 00267 c.set(Calendar.SECOND, 0); 00268 c.set(Calendar.MILLISECOND, 0); 00269 Date d = c.getTime(); 00270 calbase = d.getTime(); 00271 curTime = df.format(d).getBytes(); 00272 msec = now - calbase; 00273 if (msec < 0) msec = 0; 00274 } 00275 int sec = (int)(msec / 1000); 00276 curTime[29] = digits[sec / 10]; 00277 curTime[30] = digits[sec % 10]; 00278 out.write(curTime); 00279 } 00280 00281 void writeAttr(WorkerOutputStream out, String name, String val) 00282 throws IOException 00283 { 00284 if (val != null) { 00285 out.write(';'); 00286 out.write(name); 00287 out.write('='); 00288 out.write(val); 00289 } 00290 } 00291 00292 // from RFC 2068, token special case characters 00293 private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; 00294 00295 /** 00296 * Return true iff the string counts as an HTTP/1.1 "token". 00297 */ 00298 private static boolean isToken (String value) { 00299 final int len = value.length(); 00300 00301 for (int i = 0; i < len; i++) { 00302 char c = value.charAt(i); 00303 if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) 00304 return false; 00305 } 00306 return true; 00307 } 00308 00309 private final void writeTok(WorkerOutputStream out, String val, int v) 00310 throws IOException 00311 { 00312 if (v == 0 || isToken(val)) { 00313 out.write(val); 00314 } else { 00315 out.write('"'); 00316 out.write(val); 00317 out.write('"'); 00318 } 00319 } 00320 00321 void writeCookies(WorkerOutputStream out) throws IOException { 00322 out.write("Set-Cookie: "); 00323 for (int i = 0; i < cookies.size(); i++) { 00324 Cookie cookie = (Cookie)cookies.elementAt(i); 00325 final int version = cookie.getVersion(); 00326 if (i > 0) out.write('\t'); 00327 out.write(cookie.getName()); 00328 String val = cookie.getValue(); 00329 if (val != null) { 00330 out.write('='); 00331 writeTok(out, val, version); 00332 } 00333 00334 writeAttr(out, "Path", cookie.getPath()); 00335 if (version == 0) { 00336 writeAttr(out, "Domain", cookie.getDomain()); 00337 if (cookie.getMaxAge() >= 0) { 00338 Date d = new Date(); 00339 long ms = d.getTime() + cookie.getMaxAge() * 1000; 00340 d.setTime(ms); 00341 writeAttr(out, "Expires", 00342 cookieDateFormat.format(d)); 00343 } 00344 } else { 00345 out.write(";Version=1"); 00346 out.write(";Domain="); 00347 writeTok(out, cookie.getDomain(), version); 00348 if (cookie.getMaxAge() >= 0) { 00349 writeAttr(out, "Max-Age", "" + cookie.getMaxAge()); 00350 } else { 00351 out.write(";Discard"); 00352 } 00353 writeAttr(out, "Comment", cookie.getComment()); 00354 } 00355 if (cookie.getSecure()) out.write(";Ssecure"); 00356 out.write(CRLF); 00357 } 00358 } 00359 00360 final void setFixedHeader(String name, String val) { 00361 try { 00362 write(fixedH, name); 00363 write(fixedH, ": "); 00364 write(fixedH, val); 00365 fixedH.write(CRLF); 00366 } catch (Exception e) {} 00367 } 00368 00369 /** 00370 * ----- SerlvetResponse methods ----- 00371 */ 00372 00373 /** 00374 * Sets the content length for this response. 00375 * 00376 * @param len the content length 00377 */ 00378 public void setContentLength(int len) { 00379 contentLength = len; 00380 } 00381 00382 final void maybeSetContentLength(int len) { 00383 if (contentLength == -1) { 00384 contentLength = len; 00385 } 00386 } 00387 00388 int getContentLength() { return contentLength; } 00389 00390 /** 00391 * Sets the content type for this response. This type may later 00392 * be implicitly modified by addition of properties such as the MIME 00393 * <em>charset=&lt;value&gt;</em> if the service finds it necessary, 00394 * and the appropriate media type property has not been set. 00395 * 00396 * <p>This response property may only be assigned one time. If a 00397 * writer is to be used to write a text response, this method must 00398 * be called before the method <code>getWriter</code>. If an 00399 * output stream will be used to write a response, this method must 00400 * be called before the output stream is used to write response 00401 * data. 00402 * 00403 * @param type the content's MIME type 00404 */ 00405 public void setContentType(String type) { 00406 contentType = type; 00407 } 00408 00409 /** 00410 * Returns an output stream for writing binary response data. 00411 * 00412 * @exception IllegalStateException if getWriter has been 00413 * called on this same request. 00414 * @exception IOException if an I/O exception has occurred 00415 */ 00416 public ServletOutputStream getOutputStream() throws IOException { 00417 if (getWriterCalled) { 00418 throw new IllegalStateException("getWriter() already called"); 00419 } 00420 getOutputStreamCalled = true; 00421 return os; 00422 } 00423 00424 /** 00425 * Returns a print writer for writing formatted text responses. The 00426 * MIME type of the response will be modified, if necessary, to reflect 00427 * the character encoding used, through the <em>charset=...</em> 00428 * property. This means that the content type must be set before 00429 * calling this method. 00430 * 00431 * 00432 * @exception UnsupportedEncodingException if no such encoding can 00433 * be provided 00434 * @exception IllegalStateException if getOutputStream has been 00435 * called on this same request. 00436 * @exception IOException on other errors. 00437 */ 00438 public PrintWriter getWriter() throws IOException { 00439 if (getOutputStreamCalled) { 00440 throw new 00441 IllegalStateException("getOutputStream() already called"); 00442 } 00443 if (writer == null) { 00444 String encoding = getCharacterEncoding(); 00445 OutputStreamWriter ww = null; 00446 OutputStream os = getOutputStream(); 00447 if (encoding != null) { 00448 ww = new OutputStreamWriter(os, encoding); 00449 } else { 00450 ww = new OutputStreamWriter(os); 00451 } 00452 writer = new PrintWriter(ww); 00453 getWriterCalled = true; 00454 } 00455 return writer; 00456 } 00457 00458 public JspWriter getJspWriter(int bufferSize, boolean autoFlush) 00459 throws IOException 00460 { 00461 if (!jWriterInit) { 00462 jWriterInit = true; 00463 jWriter.setHttpOutputStream(os); 00464 jWriter.setBufferSize(bufferSize); 00465 jWriter.setAutoFlush(autoFlush); 00466 } 00467 return jWriter; 00468 } 00469 00470 /** 00471 * Returns the character set encoding used for this MIME body. 00472 * The character encoding is either the one specified in the 00473 * assigned content type, or one which the client understands. 00474 * If no content type has yet been assigned, it is implicitly 00475 * set to <em>text/plain</em> 00476 */ 00477 public String getCharacterEncoding () { 00478 String s = contentType; 00479 if (s == null) return null; 00480 00481 int idx = s.indexOf(';'); 00482 while (idx > 0) { 00483 s = s.substring(idx+1).trim(); 00484 idx = s.indexOf(';'); 00485 String c = s; 00486 if (idx > 0) { 00487 c = s.substring(0, idx).trim(); 00488 } 00489 if (c.startsWith("charset=")) { 00490 return c.substring(8); 00491 } 00492 } 00493 return null; 00494 } 00495 00496 /** 00497 * ----- HttpServletResponse methods ----- 00498 */ 00499 00500 00501 /** 00502 * Adds the specified cookie to the response. It can be called 00503 * multiple times to set more than one cookie. 00504 * 00505 * @param cookie the Cookie to return to the client 00506 */ 00507 public void addCookie(Cookie cookie) { 00508 //#ifdef DEBUG 00509 if (Trace.level() > 7) { 00510 Debug.println("addCookie(" + cookie + ")"); 00511 } 00512 //#endif 00513 if (cookies == null) { 00514 cookies = new Vector(); 00515 } 00516 cookies.addElement(cookie); 00517 } 00518 00519 /** 00520 * Checks whether the response message header has a field with 00521 * the specified name. 00522 * 00523 * @param name the header field name 00524 * @return true if the response message header has a field with 00525 * the specified name; false otherwise 00526 */ 00527 public boolean containsHeader(String name) { 00528 return headers.get(name) != null; 00529 } 00530 00531 /** 00532 * Sets the status code and message for this response. If the 00533 * field had already been set, the new value overwrites the 00534 * previous one. The message is sent as the body of an HTML 00535 * page, which is returned to the user to describe the problem. 00536 * The page is sent with a default HTML header; the message 00537 * is enclosed in simple body tags (&lt;body&gt;&lt;/body&gt;). 00538 * 00539 * @param sc the status code 00540 * @param sm the status message 00541 */ 00542 public void setStatus(int sc, String sm) { 00543 this.changedCode = true; 00544 this.sc = sc; 00545 this.sm = sm; 00546 } 00547 00548 /** 00549 * Sets the status code for this response. This method is used to 00550 * set the return status code when there is no error (for example, 00551 * for the status codes SC_OK or SC_MOVED_TEMPORARILY). If there 00552 * is an error, the <code>sendError</code> method should be used 00553 * instead. 00554 * 00555 * @param sc the status code 00556 * 00557 */ 00558 public void setStatus(int sc) { 00559 this.changedCode = true; 00560 this.sc = sc; 00561 this.sm = ""; 00562 } 00563 00564 /** 00565 * 00566 * Adds a field to the response header with the given name and value. 00567 * If the field had already been set, the new value overwrites the 00568 * previous one. The <code>containsHeader</code> method can be 00569 * used to test for the presence of a header before setting its 00570 * value. 00571 * 00572 * @param name the name of the header field 00573 * @param value the header field's value 00574 * 00575 */ 00576 public void setHeader(String name, String value) { 00577 if (name.charAt(0) == 'C') { 00578 if (name.equals("Content-Type")) { 00579 contentType = value; 00580 return; 00581 } else if (name.equals("Content-Length")) { 00582 contentLength = Integer.parseInt(value); 00583 return; 00584 } 00585 } 00586 if (headerBufValid) { 00587 if (headers.get(name) == null) { 00588 appendHeader(name, value); 00589 } else { 00590 headerBufValid = false; 00591 } 00592 } 00593 anyHeaders = true; 00594 headers.put(name, value); 00595 } 00596 00597 final void appendHeader(String name, String value) { 00598 headerBuf.append(name); 00599 headerBuf.append(": "); 00600 headerBuf.append(value); 00601 headerBuf.append("\r\n"); 00602 } 00603 00604 /** 00605 * Add a new header value -- this method allows multiple headers with 00606 * the same name. 00607 */ 00608 public void addHeader(String name, String value) { 00609 Object obj = headers.get(name); 00610 Vector v = null; 00611 boolean mustInsert = true; 00612 if (obj instanceof String) { 00613 v = new Vector(); 00614 v.addElement(obj.toString()); 00615 } else if (obj == null) { 00616 v = new Vector(); 00617 } else { 00618 v = (Vector)obj; 00619 mustInsert = false; 00620 } 00621 v.addElement(value); 00622 if (mustInsert) { 00623 anyHeaders = true; 00624 headers.put(name, v); 00625 } 00626 appendHeader(name, value); 00627 } 00628 00629 00630 /** 00631 * Adds a field to the response header with the given name and 00632 * integer value. If the field had already been set, the new value 00633 * overwrites the previous one. The <code>containsHeader</code> 00634 * method can be used to test for the presence of a header before 00635 * setting its value. 00636 * 00637 * @param name the name of the header field 00638 * @param value the header field's integer value 00639 * 00640 */ 00641 public void setIntHeader(String name, int value) { 00642 setHeader(name, "" + value); 00643 } 00644 00645 public void addIntHeader(String name, int value) { 00646 addHeader(name, "" + value); 00647 } 00648 00649 /** 00650 * 00651 * Adds a field to the response header with the given name and 00652 * date-valued field. The date is specified in terms of 00653 * milliseconds since the epoch. If the date field had already 00654 * been set, the new value overwrites the previous one. The 00655 * <code>containsHeader</code> method can be used to test for the 00656 * presence of a header before setting its value. 00657 * 00658 * @param name the name of the header field 00659 * @param value the header field's date value 00660 * 00661 */ 00662 public void setDateHeader(String name, long date) { 00663 Date d = new Date(date); 00664 setHeader(name, df2.format(d)); 00665 } 00666 00667 public void addDateHeader(String name, long date) { 00668 Date d = new Date(date); 00669 addHeader(name, df2.format(d)); 00670 } 00671 00672 /** 00673 * Sends an error response to the client using the specified status 00674 * code and descriptive message. If setStatus has previously been 00675 * called, it is reset to the error status code. The message is 00676 * sent as the body of an HTML page, which is returned to the user 00677 * to describe the problem. The page is sent with a default HTML 00678 * header; the message is enclosed in simple body tags 00679 * (&lt;body&gt;&lt;/body&gt;). 00680 * 00681 * @param sc the status code 00682 * @param msg the detail message 00683 * @exception IOException If an I/O error has occurred. */ 00684 public void sendError(int scode, String msg) throws IOException { 00685 setStatus(scode, msg); 00686 if (os.discard()) { 00687 writer = null; 00688 } 00689 getWriterCalled = getOutputStreamCalled = false; 00690 setContentType("text/html"); 00691 PrintWriter p = getWriter(); 00692 p.println("<HEAD><TITLE>" + scode + " " + msg + "</TITLE></HEAD>"); 00693 p.print("<BODY><H1>"); 00694 p.print(msg); 00695 p.println("</H1>"); 00696 if (scode == HttpServletResponse.SC_NOT_FOUND) { 00697 p.print("The requested URL was not found on this server"); 00698 p.println("<P>"); 00699 } 00700 p.println("</BODY>"); 00701 flush(); 00702 } 00703 00704 /** 00705 * Sends an error response to the client using the specified 00706 * status code and a default message. 00707 * @param scode the status code 00708 * @exception IOException If an I/O error has occurred. 00709 */ 00710 public void sendError(int scode) throws IOException { 00711 sm = "Error " + scode; 00712 setStatus(scode); 00713 if (os.discard()) { 00714 writer = null; 00715 } 00716 getWriterCalled = getOutputStreamCalled = false; 00717 PrintWriter p = getWriter(); 00718 p.println("<html><head><title>" + sm + "</title></head>"); 00719 p.println("<body>"); 00720 p.println(sm); 00721 p.println("</body></html>"); 00722 flush(); 00723 } 00724 00725 /** 00726 * Flush the underlying output stream 00727 */ 00728 void flush() throws IOException { 00729 if (writer != null) writer.flush(); 00730 os.flush(); 00731 } 00732 00733 /** 00734 * Sends a temporary redirect response to the client using the 00735 * specified redirect location URL. The URL must be absolute (for 00736 * example, <code><em>https://hostname/path/file.html</em></code>). 00737 * Relative URLs are not permitted here. 00738 * 00739 * @param location the redirect location URL 00740 * @exception IOException If an I/O error has occurred. 00741 */ 00742 public void sendRedirect(String location) throws IOException { 00743 setHeader("Location", location); 00744 sendError(SC_MOVED_TEMPORARILY, 00745 "<a href=\"" + location + "\">" + location + "</A>"); 00746 } 00747 00748 /** 00749 * Encodes the specified URL by including the session ID in it, 00750 * or, if encoding is not needed, returns the URL unchanged. 00751 * The implementation of this method should include the logic to 00752 * determine whether the session ID needs to be encoded in the URL. 00753 * For example, if the browser supports cookies, or session 00754 * tracking is turned off, URL encoding is unnecessary. 00755 * 00756 * <p>All URLs emitted by a Servlet should be run through this 00757 * method. Otherwise, URL rewriting cannot be used with browsers 00758 * which do not support cookies. 00759 * 00760 * @param url the url to be encoded. 00761 * @return the encoded URL if encoding is needed; the unchanged URL 00762 * otherwise. 00763 */ 00764 public String encodeUrl (String url) { 00765 return url; 00766 } 00767 public String encodeURL(String url) { 00768 return url; 00769 } 00770 00771 /** 00772 * Encodes the specified URL for use in the 00773 * <code>sendRedirect</code> method or, if encoding is not needed, 00774 * returns the URL unchanged. The implementation of this method 00775 * should include the logic to determine whether the session ID 00776 * needs to be encoded in the URL. Because the rules for making 00777 * this determination differ from those used to decide whether to 00778 * encode a normal link, this method is seperate from the 00779 * <code>encodeUrl</code> method. 00780 * 00781 * <p>All URLs sent to the HttpServletResponse.sendRedirect 00782 * method should be run through this method. Otherwise, URL 00783 * rewriting canont be used with browsers which do not support 00784 * cookies. 00785 * 00786 * @param url the url to be encoded. 00787 * @return the encoded URL if encoding is needed; the unchanged URL 00788 * otherwise. 00789 * 00790 */ 00791 public String encodeRedirectUrl (String url) { 00792 return url; 00793 } 00794 public String encodeRedirectURL(String url) { 00795 return url; 00796 } 00797 00798 public void flushBuffer() throws IOException { 00799 if (writer != null) writer.flush(); 00800 os.flushBuffered(); 00801 } 00802 00803 public void setBufferSize(int size) throws IllegalStateException { 00804 os.setBufferSize(size); 00805 } 00806 00807 public int getBufferSize() { 00808 return os.getBufferSize(); 00809 } 00810 00811 public boolean isCommitted() { 00812 return os.isCommitted(); 00813 } 00814 00815 public void reset() throws IllegalStateException { 00816 os.reset(); // checks for committed, may throw IllegalStateException 00817 sc = SC_OK; 00818 headers.clear(); 00819 sm = "Request Completed"; 00820 changedCode = false; 00821 locale = defaultLocale; 00822 contentLength = -1; 00823 contentType = null; 00824 headerBuf.setLength(0); 00825 headerBufValid = true; 00826 writer = null; 00827 cookies = null; 00828 anyHeaders = false; 00829 getWriterCalled = false; 00830 jWriterInit = false; 00831 getOutputStreamCalled = false; 00832 } 00833 00834 public void setLocale(Locale locale) { 00835 this.locale = locale; 00836 if (locale != null) { 00837 String lang = locale.getLanguage(); 00838 if (lang != null) { 00839 setHeader("Content-Language", lang); 00840 } 00841 } 00842 00843 } 00844 00845 public Locale getLocale() { 00846 return locale; 00847 } 00848 }