Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » tomcat4 » [javadoc | source]
    1   /*
    2    *  Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    *  Unless required by applicable law or agreed to in writing, software
   11    *  distributed under the License is distributed on an "AS IS" BASIS,
   12    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    *  See the License for the specific language governing permissions and
   14    *  limitations under the License.
   15    */
   16   
   17   package org.apache.coyote.tomcat4;
   18   
   19   
   20   import java.io.IOException;
   21   import java.io.OutputStream;
   22   import java.io.PrintWriter;
   23   import java.net.MalformedURLException;
   24   import java.text.SimpleDateFormat;
   25   import java.util.ArrayList;
   26   import java.util.Date;
   27   import java.util.Enumeration;
   28   import java.util.Locale;
   29   import java.util.TimeZone;
   30   import java.util.Vector;
   31   
   32   import javax.servlet.ServletOutputStream;
   33   import javax.servlet.ServletResponse;
   34   import javax.servlet.http.Cookie;
   35   import javax.servlet.http.HttpServletRequest;
   36   import javax.servlet.http.HttpServletResponse;
   37   import javax.servlet.http.HttpSession;
   38   
   39   import org.apache.catalina.Connector;
   40   import org.apache.catalina.Context;
   41   import org.apache.catalina.HttpResponse;
   42   import org.apache.catalina.util.CharsetMapper;
   43   import org.apache.catalina.util.StringManager;
   44   import org.apache.coyote.Response;
   45   import org.apache.tomcat.util.buf.CharChunk;
   46   import org.apache.tomcat.util.buf.UEncoder;
   47   import org.apache.tomcat.util.http.MimeHeaders;
   48   import org.apache.tomcat.util.http.ServerCookie;
   49   import org.apache.tomcat.util.net.URL;
   50   
   51   
   52   /**
   53    * Wrapper object for the Coyote response.
   54    *
   55    * @author Remy Maucherat
   56    * @author Craig R. McClanahan
   57    * @version $Revision: 299753 $ $Date: 2004-08-29 13:14:42 -0400 (Sun, 29 Aug 2004) $
   58    */
   59   
   60   public class CoyoteResponse
   61       implements HttpResponse, HttpServletResponse {
   62   
   63   
   64       // ----------------------------------------------------------- Constructors
   65   
   66   
   67       public CoyoteResponse() {
   68   
   69           format.setTimeZone(TimeZone.getTimeZone("GMT"));
   70           urlEncoder.addSafeCharacter('/');
   71   
   72       }
   73   
   74   
   75       // ----------------------------------------------------- Instance Variables
   76   
   77   
   78       /**
   79        * The date format we will use for creating date headers.
   80        */
   81       protected final SimpleDateFormat format =
   82           new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
   83   
   84   
   85       /**
   86        * Descriptive information about this Response implementation.
   87        */
   88       protected static final String info =
   89           "org.apache.coyote.tomcat4.CoyoteResponse/1.0";
   90   
   91   
   92       /**
   93        * The string manager for this package.
   94        */
   95       protected static StringManager sm =
   96           StringManager.getManager(Constants.Package);
   97   
   98   
   99       // ------------------------------------------------------------- Properties
  100   
  101   
  102       /**
  103        * Associated Catalina connector.
  104        */
  105       protected Connector connector;
  106   
  107       /**
  108        * Return the Connector through which this Request was received.
  109        */
  110       public Connector getConnector() {
  111           return (this.connector);
  112       }
  113   
  114       /**
  115        * Set the Connector through which this Request was received.
  116        *
  117        * @param connector The new connector
  118        */
  119       public void setConnector(Connector connector) {
  120           this.connector = connector;
  121       }
  122   
  123   
  124       /**
  125        * Coyote response.
  126        */
  127       protected Response coyoteResponse;
  128   
  129       /**
  130        * Set the Coyote response.
  131        * 
  132        * @param coyoteResponse The Coyote response
  133        */
  134       public void setCoyoteResponse(Response coyoteResponse) {
  135           this.coyoteResponse = coyoteResponse;
  136           outputBuffer.setResponse(coyoteResponse);
  137       }
  138   
  139       /**
  140        * Get the Coyote response.
  141        */
  142       public Response getCoyoteResponse() {
  143           return (coyoteResponse);
  144       }
  145   
  146   
  147       /**
  148        * The Context within which this Request is being processed.
  149        */
  150       protected Context context = null;
  151   
  152       /**
  153        * Return the Context within which this Request is being processed.
  154        */
  155       public Context getContext() {
  156           return (this.context);
  157       }
  158   
  159       /**
  160        * Set the Context within which this Request is being processed.  This
  161        * must be called as soon as the appropriate Context is identified, because
  162        * it identifies the value to be returned by <code>getContextPath()</code>,
  163        * and thus enables parsing of the request URI.
  164        *
  165        * @param context The newly associated Context
  166        */
  167       public void setContext(Context context) {
  168           this.context = context;
  169       }
  170   
  171   
  172       /**
  173        * The associated output buffer.
  174        */
  175       protected OutputBuffer outputBuffer = new OutputBuffer();
  176   
  177   
  178       /**
  179        * The associated output stream.
  180        */
  181       protected CoyoteOutputStream outputStream = 
  182           new CoyoteOutputStream(outputBuffer);
  183   
  184   
  185       /**
  186        * The associated writer.
  187        */
  188       protected CoyoteWriter writer = new CoyoteWriter(outputBuffer);
  189   
  190   
  191       /**
  192        * The application commit flag.
  193        */
  194       protected boolean appCommitted = false;
  195   
  196   
  197       /**
  198        * The included flag.
  199        */
  200       protected boolean included = false;
  201   
  202   
  203       /**
  204        * The error flag.
  205        */
  206       protected boolean error = false;
  207   
  208   
  209       /**
  210        * The set of Cookies associated with this Response.
  211        */
  212       protected ArrayList cookies = new ArrayList();
  213   
  214   
  215       /**
  216        * Using output stream flag.
  217        */
  218       protected boolean usingOutputStream = false;
  219   
  220   
  221       /**
  222        * Using writer flag.
  223        */
  224       protected boolean usingWriter = false;
  225   
  226   
  227       /**
  228        * URL encoder.
  229        */
  230       protected UEncoder urlEncoder = new UEncoder();
  231   
  232   
  233       /**
  234        * Recyclable buffer to hold the redirect URL.
  235        */
  236       protected CharChunk redirectURLCC = new CharChunk();
  237   
  238   
  239       // --------------------------------------------------------- Public Methods
  240   
  241   
  242       /**
  243        * Release all object references, and initialize instance variables, in
  244        * preparation for reuse of this object.
  245        */
  246       public void recycle() {
  247   
  248           outputBuffer.recycle();
  249           usingOutputStream = false;
  250           usingWriter = false;
  251           appCommitted = false;
  252           included = false;
  253           error = false;
  254           cookies.clear();
  255   
  256           if (facade != null) {
  257               facade.clear();
  258               facade = null;
  259           }
  260   
  261           writer.recycle();
  262   
  263       }
  264   
  265   
  266       // ------------------------------------------------------- Response Methods
  267   
  268   
  269       /**
  270        * Return the number of bytes actually written to the output stream.
  271        */
  272       public int getContentCount() {
  273           return outputBuffer.getContentWritten();
  274       }
  275   
  276   
  277       /**
  278        * Set the application commit flag.
  279        * 
  280        * @param appCommitted The new application committed flag value
  281        */
  282       public void setAppCommitted(boolean appCommitted) {
  283           this.appCommitted = appCommitted;
  284       }
  285   
  286   
  287       /**
  288        * Application commit flag accessor.
  289        */
  290       public boolean isAppCommitted() {
  291           return (this.appCommitted || isCommitted() || isSuspended());
  292       }
  293   
  294   
  295       /**
  296        * Return the "processing inside an include" flag.
  297        */
  298       public boolean getIncluded() {
  299           return included;
  300       }
  301   
  302   
  303       /**
  304        * Set the "processing inside an include" flag.
  305        *
  306        * @param included <code>true</code> if we are currently inside a
  307        *  RequestDispatcher.include(), else <code>false</code>
  308        */
  309       public void setIncluded(boolean included) {
  310           this.included = included;
  311       }
  312   
  313   
  314       /**
  315        * Return descriptive information about this Response implementation and
  316        * the corresponding version number, in the format
  317        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  318        */
  319       public String getInfo() {
  320           return (info);
  321       }
  322   
  323   
  324       /**
  325        * The request with which this response is associated.
  326        */
  327       protected CoyoteRequest request = null;
  328   
  329       /**
  330        * Return the Request with which this Response is associated.
  331        */
  332       public org.apache.catalina.Request getRequest() {
  333           return (this.request);
  334       }
  335   
  336       /**
  337        * Set the Request with which this Response is associated.
  338        *
  339        * @param request The new associated request
  340        */
  341       public void setRequest(org.apache.catalina.Request request) {
  342           this.request = (CoyoteRequest) request;
  343       }
  344   
  345   
  346       /**
  347        * The facade associated with this response.
  348        */
  349       protected CoyoteResponseFacade facade = null;
  350   
  351       /**
  352        * Return the <code>ServletResponse</code> for which this object
  353        * is the facade.
  354        */
  355       public ServletResponse getResponse() {
  356           if (facade == null) {
  357               facade = new CoyoteResponseFacade(this);
  358           }
  359           return (facade);
  360       }
  361   
  362   
  363       /**
  364        * Return the output stream associated with this Response.
  365        */
  366       public OutputStream getStream() {
  367           return outputStream;
  368       }
  369   
  370   
  371       /**
  372        * Set the output stream associated with this Response.
  373        *
  374        * @param stream The new output stream
  375        */
  376       public void setStream(OutputStream stream) {
  377           // This method is evil
  378       }
  379   
  380   
  381       /**
  382        * Set the suspended flag.
  383        * 
  384        * @param suspended The new suspended flag value
  385        */
  386       public void setSuspended(boolean suspended) {
  387           outputBuffer.setSuspended(suspended);
  388       }
  389   
  390   
  391       /**
  392        * Suspended flag accessor.
  393        */
  394       public boolean isSuspended() {
  395           return outputBuffer.isSuspended();
  396       }
  397   
  398   
  399       /**
  400        * Set the error flag.
  401        */
  402       public void setError() {
  403           error = true;
  404       }
  405   
  406   
  407       /**
  408        * Error flag accessor.
  409        */
  410       public boolean isError() {
  411           return error;
  412       }
  413   
  414   
  415       /**
  416        * Create and return a ServletOutputStream to write the content
  417        * associated with this Response.
  418        *
  419        * @exception IOException if an input/output error occurs
  420        */
  421       public ServletOutputStream createOutputStream() 
  422           throws IOException {
  423           // Probably useless
  424           return outputStream;
  425       }
  426   
  427   
  428       /**
  429        * Perform whatever actions are required to flush and close the output
  430        * stream or writer, in a single operation.
  431        *
  432        * @exception IOException if an input/output error occurs
  433        */
  434       public void finishResponse() 
  435           throws IOException {
  436           // Writing leftover bytes
  437           try {
  438               outputBuffer.close();
  439           } catch(IOException e) {
  440               ;
  441           } catch(Throwable t) {
  442               t.printStackTrace();
  443           }
  444       }
  445   
  446   
  447       /**
  448        * Return the content length that was set or calculated for this Response.
  449        */
  450       public int getContentLength() {
  451           return (coyoteResponse.getContentLength());
  452       }
  453   
  454   
  455       /**
  456        * Return the content type that was set or calculated for this response,
  457        * or <code>null</code> if no content type was set.
  458        */
  459       public String getContentType() {
  460           return (coyoteResponse.getContentType());
  461       }
  462   
  463   
  464       /**
  465        * Return a PrintWriter that can be used to render error messages,
  466        * regardless of whether a stream or writer has already been acquired.
  467        *
  468        * @return Writer which can be used for error reports. If the response is
  469        * not an error report returned using sendError or triggered by an
  470        * unexpected exception thrown during the servlet processing
  471        * (and only in that case), null will be returned if the response stream
  472        * has already been used.
  473        */
  474       public PrintWriter getReporter() {
  475           if (outputBuffer.isNew()) {
  476               return writer;
  477           } else {
  478               return null;
  479           }
  480       }
  481   
  482   
  483       // ------------------------------------------------ ServletResponse Methods
  484   
  485   
  486       /**
  487        * Flush the buffer and commit this response.
  488        *
  489        * @exception IOException if an input/output error occurs
  490        */
  491       public void flushBuffer() 
  492           throws IOException {
  493           outputBuffer.flush();
  494       }
  495   
  496   
  497       /**
  498        * Return the actual buffer size used for this Response.
  499        */
  500       public int getBufferSize() {
  501           return outputBuffer.getBufferSize();
  502       }
  503   
  504   
  505       /**
  506        * Return the character encoding used for this Response.
  507        */
  508       public String getCharacterEncoding() {
  509           return (coyoteResponse.getCharacterEncoding());
  510       }
  511   
  512   
  513       /**
  514        * Return the servlet output stream associated with this Response.
  515        *
  516        * @exception IllegalStateException if <code>getWriter</code> has
  517        *  already been called for this response
  518        * @exception IOException if an input/output error occurs
  519        */
  520       public ServletOutputStream getOutputStream() 
  521           throws IOException {
  522   
  523           if (usingWriter)
  524               throw new IllegalStateException
  525                   (sm.getString("coyoteResponse.getOutputStream.ise"));
  526   
  527           usingOutputStream = true;
  528           return outputStream;
  529   
  530       }
  531   
  532   
  533       /**
  534        * Return the Locale assigned to this response.
  535        */
  536       public Locale getLocale() {
  537           return (coyoteResponse.getLocale());
  538       }
  539   
  540   
  541       /**
  542        * Return the writer associated with this Response.
  543        *
  544        * @exception IllegalStateException if <code>getOutputStream</code> has
  545        *  already been called for this response
  546        * @exception IOException if an input/output error occurs
  547        */
  548       public PrintWriter getWriter() 
  549           throws IOException {
  550   
  551           if (usingOutputStream)
  552               throw new IllegalStateException
  553                   (sm.getString("coyoteResponse.getWriter.ise"));
  554   
  555           usingWriter = true;
  556           return writer;
  557   
  558       }
  559   
  560   
  561       /**
  562        * Has the output of this response already been committed?
  563        */
  564       public boolean isCommitted() {
  565           return (coyoteResponse.isCommitted());
  566       }
  567   
  568   
  569       /**
  570        * Clear any content written to the buffer.
  571        *
  572        * @exception IllegalStateException if this response has already
  573        *  been committed
  574        */
  575       public void reset() {
  576   
  577           if (included)
  578               return;     // Ignore any call from an included servlet
  579   
  580           coyoteResponse.reset();
  581           outputBuffer.reset();
  582   
  583       }
  584   
  585   
  586       /**
  587        * Reset the data buffer but not any status or header information.
  588        *
  589        * @exception IllegalStateException if the response has already
  590        *  been committed
  591        */
  592       public void resetBuffer() {
  593   
  594           if (isCommitted())
  595               throw new IllegalStateException
  596                   (sm.getString("coyoteResponse.resetBuffer.ise"));
  597   
  598           outputBuffer.reset();
  599   
  600       }
  601   
  602   
  603       /**
  604        * Set the buffer size to be used for this Response.
  605        *
  606        * @param size The new buffer size
  607        *
  608        * @exception IllegalStateException if this method is called after
  609        *  output has been committed for this response
  610        */
  611       public void setBufferSize(int size) {
  612   
  613           if (isCommitted() || !outputBuffer.isNew())
  614               throw new IllegalStateException
  615                   (sm.getString("coyoteResponse.setBufferSize.ise"));
  616   
  617           outputBuffer.setBufferSize(size);
  618   
  619       }
  620   
  621   
  622       /**
  623        * Set the content length (in bytes) for this Response.
  624        *
  625        * @param length The new content length
  626        */
  627       public void setContentLength(int length) {
  628   
  629           if (isCommitted())
  630               return;
  631   
  632           // Ignore any call from an included servlet
  633           if (included)
  634               return;
  635   
  636           coyoteResponse.setContentLength(length);
  637   
  638       }
  639   
  640   
  641       /**
  642        * Set the content type for this Response.
  643        *
  644        * @param type The new content type
  645        */
  646       public void setContentType(String type) {
  647   
  648           if (isCommitted())
  649               return;
  650   
  651           // Ignore any call from an included servlet
  652           if (included)
  653               return;
  654   
  655           coyoteResponse.setContentType(type);
  656   
  657       }
  658   
  659   
  660       /**
  661        * Set the Locale that is appropriate for this response, including
  662        * setting the appropriate character encoding.
  663        *
  664        * @param locale The new locale
  665        */
  666       public void setLocale(Locale locale) {
  667   
  668           if (isCommitted())
  669               return;
  670   
  671           // Ignore any call from an included servlet
  672           if (included)
  673               return;
  674   
  675           coyoteResponse.setLocale(locale);
  676           
  677           // Set the specified locale's default encoding of a response
  678           CharsetMapper cm = context.getCharsetMapper();
  679           String charset = cm.getCharset(locale);
  680   
  681           if (charset != null) {
  682               coyoteResponse.setCharacterEncoding(charset);
  683           }
  684       
  685       }
  686   
  687   
  688       // --------------------------------------------------- HttpResponse Methods
  689   
  690   
  691       /**
  692        * Return an array of all cookies set for this response, or
  693        * a zero-length array if no cookies have been set.
  694        */
  695       public Cookie[] getCookies() {
  696           return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
  697       }
  698   
  699   
  700       /**
  701        * Return the value for the specified header, or <code>null</code> if this
  702        * header has not been set.  If more than one value was added for this
  703        * name, only the first is returned; use getHeaderValues() to retrieve all
  704        * of them.
  705        *
  706        * @param name Header name to look up
  707        */
  708       public String getHeader(String name) {
  709           return coyoteResponse.getMimeHeaders().getHeader(name);
  710       }
  711   
  712   
  713       /**
  714        * Return an array of all the header names set for this response, or
  715        * a zero-length array if no headers have been set.
  716        */
  717       public String[] getHeaderNames() {
  718   
  719           MimeHeaders headers = coyoteResponse.getMimeHeaders();
  720           int n = headers.size();
  721           String[] result = new String[n];
  722           for (int i = 0; i < n; i++) {
  723               result[i] = headers.getName(i).toString();
  724           }
  725           return result;
  726   
  727       }
  728   
  729   
  730       /**
  731        * Return an array of all the header values associated with the
  732        * specified header name, or an zero-length array if there are no such
  733        * header values.
  734        *
  735        * @param name Header name to look up
  736        */
  737       public String[] getHeaderValues(String name) {
  738   
  739           Enumeration headerValues = coyoteResponse.getMimeHeaders().values(name);
  740           Vector result = new Vector();
  741           while (headerValues.hasMoreElements()) {
  742               result.addElement(headerValues.nextElement());
  743           }
  744           String[] resultArray = new String[result.size()];
  745           result.copyInto(resultArray);
  746           return resultArray;
  747   
  748       }
  749   
  750   
  751       /**
  752        * Return the error message that was set with <code>sendError()</code>
  753        * for this Response.
  754        */
  755       public String getMessage() {
  756           return coyoteResponse.getMessage();
  757       }
  758   
  759   
  760       /**
  761        * Return the HTTP status code associated with this Response.
  762        */
  763       public int getStatus() {
  764           return coyoteResponse.getStatus();
  765       }
  766   
  767   
  768       /**
  769        * Reset this response, and specify the values for the HTTP status code
  770        * and corresponding message.
  771        *
  772        * @exception IllegalStateException if this response has already been
  773        *  committed
  774        */
  775       public void reset(int status, String message) {
  776           reset();
  777           setStatus(status, message);
  778       }
  779   
  780   
  781       // -------------------------------------------- HttpServletResponse Methods
  782   
  783   
  784       /**
  785        * Add the specified Cookie to those that will be included with
  786        * this Response.
  787        *
  788        * @param cookie Cookie to be added
  789        */
  790       public void addCookie(Cookie cookie) {
  791   
  792           if (isCommitted())
  793               return;
  794   
  795           // Ignore any call from an included servlet
  796           if (included)
  797               return;
  798   
  799           cookies.add(cookie);
  800   
  801           StringBuffer sb = new StringBuffer();
  802           ServerCookie.appendCookieValue
  803               (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
  804                cookie.getPath(), cookie.getDomain(), cookie.getComment(), 
  805                cookie.getMaxAge(), cookie.getSecure());
  806           // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
  807           // RFC2965 is not supported by browsers and the Servlet spec
  808           // asks for 2109.
  809           addHeader("Set-Cookie", sb.toString());
  810   
  811       }
  812   
  813   
  814       /**
  815        * Add the specified date header to the specified value.
  816        *
  817        * @param name Name of the header to set
  818        * @param value Date value to be set
  819        */
  820       public void addDateHeader(String name, long value) {
  821   
  822           if (isCommitted())
  823               return;
  824   
  825           // Ignore any call from an included servlet
  826           if (included)
  827               return;
  828   
  829           addHeader(name, format.format(new Date(value)));
  830   
  831       }
  832   
  833   
  834       /**
  835        * Add the specified header to the specified value.
  836        *
  837        * @param name Name of the header to set
  838        * @param value Value to be set
  839        */
  840       public void addHeader(String name, String value) {
  841   
  842           if (isCommitted())
  843               return;
  844   
  845           // Ignore any call from an included servlet
  846           if (included)
  847               return;
  848   
  849           coyoteResponse.addHeader(name, value);
  850   
  851       }
  852   
  853   
  854       /**
  855        * Add the specified integer header to the specified value.
  856        *
  857        * @param name Name of the header to set
  858        * @param value Integer value to be set
  859        */
  860       public void addIntHeader(String name, int value) {
  861   
  862           if (isCommitted())
  863               return;
  864   
  865           // Ignore any call from an included servlet
  866           if (included)
  867               return;
  868   
  869           addHeader(name, "" + value);
  870   
  871       }
  872   
  873   
  874       /**
  875        * Has the specified header been set already in this response?
  876        *
  877        * @param name Name of the header to check
  878        */
  879       public boolean containsHeader(String name) {
  880           return coyoteResponse.containsHeader(name);
  881       }
  882   
  883   
  884       /**
  885        * Encode the session identifier associated with this response
  886        * into the specified redirect URL, if necessary.
  887        *
  888        * @param url URL to be encoded
  889        */
  890       public String encodeRedirectURL(String url) {
  891   
  892           if (isEncodeable(toAbsolute(url))) {
  893               HttpServletRequest hreq =
  894                   (HttpServletRequest) request.getRequest();
  895               return (toEncoded(url, hreq.getSession().getId()));
  896           } else {
  897               return (url);
  898           }
  899   
  900       }
  901   
  902   
  903       /**
  904        * Encode the session identifier associated with this response
  905        * into the specified redirect URL, if necessary.
  906        *
  907        * @param url URL to be encoded
  908        *
  909        * @deprecated As of Version 2.1 of the Java Servlet API, use
  910        *  <code>encodeRedirectURL()</code> instead.
  911        */
  912       public String encodeRedirectUrl(String url) {
  913           return (encodeRedirectURL(url));
  914       }
  915   
  916   
  917       /**
  918        * Encode the session identifier associated with this response
  919        * into the specified URL, if necessary.
  920        *
  921        * @param url URL to be encoded
  922        */
  923       public String encodeURL(String url) {
  924           
  925           String absolute = toAbsolute(url);
  926           if (isEncodeable(absolute)) {
  927               HttpServletRequest hreq =
  928                   (HttpServletRequest) request.getRequest();
  929               
  930               // W3c spec clearly said 
  931               if (url.equalsIgnoreCase("")){
  932                   url = absolute;
  933               }
  934               return (toEncoded(url, hreq.getSession().getId()));
  935           } else {
  936               return (url);
  937           }
  938   
  939       }
  940   
  941   
  942       /**
  943        * Encode the session identifier associated with this response
  944        * into the specified URL, if necessary.
  945        *
  946        * @param url URL to be encoded
  947        *
  948        * @deprecated As of Version 2.1 of the Java Servlet API, use
  949        *  <code>encodeURL()</code> instead.
  950        */
  951       public String encodeUrl(String url) {
  952           return (encodeURL(url));
  953       }
  954   
  955   
  956       /**
  957        * Send an acknowledgment of a request.
  958        * 
  959        * @exception IOException if an input/output error occurs
  960        */
  961       public void sendAcknowledgement()
  962           throws IOException {
  963   
  964           if (isCommitted())
  965               return;
  966   
  967           // Ignore any call from an included servlet
  968           if (included)
  969               return; 
  970   
  971           coyoteResponse.acknowledge();
  972   
  973       }
  974   
  975   
  976       /**
  977        * Send an error response with the specified status and a
  978        * default message.
  979        *
  980        * @param status HTTP status code to send
  981        *
  982        * @exception IllegalStateException if this response has
  983        *  already been committed
  984        * @exception IOException if an input/output error occurs
  985        */
  986       public void sendError(int status) 
  987           throws IOException {
  988           sendError(status, null);
  989       }
  990   
  991   
  992       /**
  993        * Send an error response with the specified status and message.
  994        *
  995        * @param status HTTP status code to send
  996        * @param message Corresponding message to send
  997        *
  998        * @exception IllegalStateException if this response has
  999        *  already been committed
 1000        * @exception IOException if an input/output error occurs
 1001        */
 1002       public void sendError(int status, String message) 
 1003           throws IOException {
 1004   
 1005           if (isCommitted())
 1006               throw new IllegalStateException
 1007                   (sm.getString("coyoteResponse.sendError.ise"));
 1008   
 1009           // Ignore any call from an included servlet
 1010           if (included)
 1011               return; 
 1012   
 1013           setError();
 1014   
 1015           coyoteResponse.setStatus(status);
 1016           coyoteResponse.setMessage(message);
 1017   
 1018           // Clear any data content that has been buffered
 1019           resetBuffer();
 1020   
 1021           // Cause the response to be finished (from the application perspective)
 1022           setSuspended(true);
 1023   
 1024       }
 1025   
 1026   
 1027       /**
 1028        * Send a temporary redirect to the specified redirect location URL.
 1029        *
 1030        * @param location Location URL to redirect to
 1031        *
 1032        * @exception IllegalStateException if this response has
 1033        *  already been committed
 1034        * @exception IOException if an input/output error occurs
 1035        */
 1036       public void sendRedirect(String location) 
 1037           throws IOException {
 1038   
 1039           if (isCommitted())
 1040               throw new IllegalStateException
 1041                   (sm.getString("coyoteResponse.sendRedirect.ise"));
 1042   
 1043           // Ignore any call from an included servlet
 1044           if (included)
 1045               return; 
 1046   
 1047           // Clear any data content that has been buffered
 1048           resetBuffer();
 1049   
 1050           // Generate a temporary redirect to the specified location
 1051           try {
 1052               String absolute = toAbsolute(location);
 1053               setStatus(SC_MOVED_TEMPORARILY);
 1054               setHeader("Location", absolute);
 1055           } catch (IllegalArgumentException e) {
 1056               setStatus(SC_NOT_FOUND);
 1057           }
 1058   
 1059           // Cause the response to be finished (from the application perspective)
 1060           setSuspended(true);
 1061   
 1062       }
 1063   
 1064   
 1065       /**
 1066        * Set the specified date header to the specified value.
 1067        *
 1068        * @param name Name of the header to set
 1069        * @param value Date value to be set
 1070        */
 1071       public void setDateHeader(String name, long value) {
 1072   
 1073           if (isCommitted())
 1074               return;
 1075   
 1076           // Ignore any call from an included servlet
 1077           if (included)
 1078               return;
 1079   
 1080           setHeader(name, format.format(new Date(value)));
 1081   
 1082       }
 1083   
 1084   
 1085       /**
 1086        * Set the specified header to the specified value.
 1087        *
 1088        * @param name Name of the header to set
 1089        * @param value Value to be set
 1090        */
 1091       public void setHeader(String name, String value) {
 1092   
 1093           if (isCommitted())
 1094               return;
 1095   
 1096           // Ignore any call from an included servlet
 1097           if (included)
 1098               return;
 1099   
 1100           coyoteResponse.setHeader(name, value);
 1101   
 1102       }
 1103   
 1104   
 1105       /**
 1106        * Set the specified integer header to the specified value.
 1107        *
 1108        * @param name Name of the header to set
 1109        * @param value Integer value to be set
 1110        */
 1111       public void setIntHeader(String name, int value) {
 1112   
 1113           if (isCommitted())
 1114               return;
 1115   
 1116           // Ignore any call from an included servlet
 1117           if (included)
 1118               return;
 1119   
 1120           setHeader(name, "" + value);
 1121   
 1122       }
 1123   
 1124   
 1125       /**
 1126        * Set the HTTP status to be returned with this response.
 1127        *
 1128        * @param status The new HTTP status
 1129        */
 1130       public void setStatus(int status) {
 1131           setStatus(status, null);
 1132       }
 1133   
 1134   
 1135       /**
 1136        * Set the HTTP status and message to be returned with this response.
 1137        *
 1138        * @param status The new HTTP status
 1139        * @param message The associated text message
 1140        *
 1141        * @deprecated As of Version 2.1 of the Java Servlet API, this method
 1142        *  has been deprecated due to the ambiguous meaning of the message
 1143        *  parameter.
 1144        */
 1145       public void setStatus(int status, String message) {
 1146   
 1147           if (isCommitted())
 1148               return;
 1149   
 1150           // Ignore any call from an included servlet
 1151           if (included)
 1152               return;
 1153   
 1154           coyoteResponse.setStatus(status);
 1155           coyoteResponse.setMessage(message);
 1156   
 1157       }
 1158   
 1159   
 1160       // ------------------------------------------------------ Protected Methods
 1161   
 1162   
 1163       /**
 1164        * Return <code>true</code> if the specified URL should be encoded with
 1165        * a session identifier.  This will be true if all of the following
 1166        * conditions are met:
 1167        * <ul>
 1168        * <li>The request we are responding to asked for a valid session
 1169        * <li>The requested session ID was not received via a cookie
 1170        * <li>The specified URL points back to somewhere within the web
 1171        *     application that is responding to this request
 1172        * </ul>
 1173        *
 1174        * @param location Absolute URL to be validated
 1175        */
 1176       protected boolean isEncodeable(String location) {
 1177   
 1178           if (location == null)
 1179               return (false);
 1180   
 1181           // Is this an intra-document reference?
 1182           if (location.startsWith("#"))
 1183               return (false);
 1184   
 1185           // Are we in a valid session that is not using cookies?
 1186           HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
 1187           HttpSession session = hreq.getSession(false);
 1188           if (session == null)
 1189               return (false);
 1190           if (hreq.isRequestedSessionIdFromCookie())
 1191               return (false);
 1192   
 1193           // Is this a valid absolute URL?
 1194           URL url = null;
 1195           try {
 1196               url = new URL(location);
 1197           } catch (MalformedURLException e) {
 1198               return (false);
 1199           }
 1200   
 1201           // Does this URL match down to (and including) the context path?
 1202           if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
 1203               return (false);
 1204           if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
 1205               return (false);
 1206           int serverPort = hreq.getServerPort();
 1207           if (serverPort == -1) {
 1208               if ("https".equals(hreq.getScheme()))
 1209                   serverPort = 443;
 1210               else
 1211                   serverPort = 80;
 1212           }
 1213           int urlPort = url.getPort();
 1214           if (urlPort == -1) {
 1215               if ("https".equals(url.getProtocol()))
 1216                   urlPort = 443;
 1217               else
 1218                   urlPort = 80;
 1219           }
 1220           if (serverPort != urlPort)
 1221               return (false);
 1222   
 1223           String contextPath = getContext().getPath();
 1224           if (contextPath != null) {
 1225               String file = url.getFile();
 1226               if ((file == null) || !file.startsWith(contextPath))
 1227                   return (false);
 1228               if( file.indexOf(";jsessionid=" + session.getId()) >= 0 )
 1229                   return (false);
 1230           }
 1231   
 1232           // This URL belongs to our web application, so it is encodeable
 1233           return (true);
 1234   
 1235       }
 1236   
 1237   
 1238       /**
 1239        * Convert (if necessary) and return the absolute URL that represents the
 1240        * resource referenced by this possibly relative URL.  If this URL is
 1241        * already absolute, return it unchanged.
 1242        *
 1243        * @param location URL to be (possibly) converted and then returned
 1244        *
 1245        * @exception IllegalArgumentException if a MalformedURLException is
 1246        *  thrown when converting the relative URL to an absolute one
 1247        */
 1248       private String toAbsolute(String location) {
 1249   
 1250           if (location == null)
 1251               return (location);
 1252   
 1253           // Construct a new absolute URL if possible (cribbed from
 1254           // the DefaultErrorPage servlet)
 1255           URL url = null;
 1256           try {
 1257               url = new URL(location);
 1258   
 1259               if (url.getAuthority() == null)
 1260                   return location;
 1261   
 1262           } catch (MalformedURLException e1) {
 1263               HttpServletRequest hreq =
 1264                   (HttpServletRequest) request.getRequest();
 1265               String requrl = request.getRequestURL().toString();
 1266               try {
 1267                   url = new URL(new URL(requrl), location);
 1268               } catch (MalformedURLException e2) {
 1269                   throw new IllegalArgumentException(location);
 1270               }
 1271           }
 1272           return (url.toExternalForm());
 1273       }
 1274   
 1275   
 1276       /**
 1277        * Return the specified URL with the specified session identifier
 1278        * suitably encoded.
 1279        *
 1280        * @param url URL to be encoded with the session id
 1281        * @param sessionId Session id to be included in the encoded URL
 1282        */
 1283       private String toEncoded(String url, String sessionId) {
 1284   
 1285           if ((url == null) || (sessionId == null))
 1286               return (url);
 1287   
 1288           String path = url;
 1289           String query = "";
 1290           String anchor = "";
 1291           int question = url.indexOf('?');
 1292           if (question >= 0) {
 1293               path = url.substring(0, question);
 1294               query = url.substring(question);
 1295           }
 1296           int pound = path.indexOf('#');
 1297           if (pound >= 0) {
 1298               anchor = path.substring(pound);
 1299               path = path.substring(0, pound);
 1300           }
 1301           StringBuffer sb = new StringBuffer(path);
 1302           if( sb.length() > 0 ) { // jsessionid can't be first.
 1303               sb.append(";jsessionid=");
 1304               sb.append(sessionId);
 1305           }
 1306           sb.append(anchor);
 1307           sb.append(query);
 1308           return (sb.toString());
 1309   
 1310       }
 1311   
 1312   
 1313   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » coyote » tomcat4 » [javadoc | source]