KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > coyote > tomcat5 > CoyoteResponse


1
2
3 /*
4  * The contents of this file are subject to the terms
5  * of the Common Development and Distribution License
6  * (the "License"). You may not use this file except
7  * in compliance with the License.
8  *
9  * You can obtain a copy of the license at
10  * glassfish/bootstrap/legal/CDDLv1.0.txt or
11  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
12  * See the License for the specific language governing
13  * permissions and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL
16  * HEADER in each file and include the License file at
17  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
18  * add the following below this CDDL HEADER, with the
19  * fields enclosed by brackets "[]" replaced with your
20  * own identifying information: Portions Copyright [yyyy]
21  * [name of copyright owner]
22  *
23  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24  *
25  * Portions Copyright Apache Software Foundation.
26  */

27
28
29 package org.apache.coyote.tomcat5;
30
31
32 import java.io.IOException JavaDoc;
33 import java.io.OutputStream JavaDoc;
34 import java.io.PrintWriter JavaDoc;
35 import java.net.MalformedURLException JavaDoc;
36 import java.security.AccessController JavaDoc;
37 import java.security.PrivilegedAction JavaDoc;
38 import java.security.PrivilegedActionException JavaDoc;
39 import java.security.PrivilegedExceptionAction JavaDoc;
40 import java.text.SimpleDateFormat JavaDoc;
41 import java.util.ArrayList JavaDoc;
42 import java.util.Enumeration JavaDoc;
43 import java.util.Locale JavaDoc;
44 import java.util.TimeZone JavaDoc;
45 import java.util.Vector JavaDoc;
46
47 import javax.servlet.ServletOutputStream JavaDoc;
48 import javax.servlet.http.Cookie JavaDoc;
49 import javax.servlet.http.HttpServletResponse JavaDoc;
50
51 import org.apache.catalina.Connector;
52 import org.apache.catalina.Context;
53 import org.apache.catalina.Session;
54 import org.apache.catalina.HttpResponse;
55 import org.apache.catalina.Wrapper;
56 import org.apache.catalina.util.CharsetMapper;
57 import org.apache.catalina.util.DateTool;
58 import org.apache.catalina.util.StringManager;
59 import org.apache.catalina.security.SecurityUtil;
60 import org.apache.coyote.Response;
61 import org.apache.tomcat.util.buf.CharChunk;
62 import org.apache.tomcat.util.buf.UEncoder;
63 import org.apache.tomcat.util.http.FastHttpDateFormat;
64 import org.apache.tomcat.util.http.MimeHeaders;
65 import org.apache.tomcat.util.http.ServerCookie;
66 import org.apache.tomcat.util.net.URL;
67
68 // START S1AS 6170450
69
import com.sun.appserv.ProxyHandler;
70 // END S1AS 6170450
71

72 /**
73  * Wrapper object for the Coyote response.
74  *
75  * @author Remy Maucherat
76  * @author Craig R. McClanahan
77  * @version $Revision: 1.5 $ $Date: 2005/12/08 01:28:35 $
78  */

79
80 public class CoyoteResponse
81     implements HttpResponse, HttpServletResponse JavaDoc {
82
83
84     // ----------------------------------------------------------- Constructors
85

86     public CoyoteResponse() {
87         // START OF SJSAS 6231069
88
outputBuffer = new OutputBuffer();
89         outputStream = new CoyoteOutputStream(outputBuffer);
90         writer = new CoyoteWriter(outputBuffer);
91         // END OF SJSAS 6231069
92
urlEncoder.addSafeCharacter('/');
93     }
94     
95     // START OF SJSAS 6231069
96
public CoyoteResponse(boolean chunkingDisabled) {
97         outputBuffer = new OutputBuffer(chunkingDisabled);
98         outputStream = new CoyoteOutputStream(outputBuffer);
99         writer = new CoyoteWriter(outputBuffer);
100         urlEncoder.addSafeCharacter('/');
101     }
102     // END OF SJSAS 6231069
103

104
105     // ----------------------------------------------------- Instance Variables
106

107
108     // BEGIN S1AS 4878272
109
private String JavaDoc detailErrorMsg;
110     // END S1AS 4878272
111

112
113     /**
114      * The date format we will use for creating date headers.
115      */

116     protected SimpleDateFormat JavaDoc format = null;
117
118
119     /**
120      * Descriptive information about this Response implementation.
121      */

122     protected static final String JavaDoc info =
123         "org.apache.coyote.tomcat5.CoyoteResponse/1.0";
124
125
126     /**
127      * The string manager for this package.
128      */

129     protected static StringManager sm =
130         StringManager.getManager(Constants.Package);
131
132
133     // ------------------------------------------------------------- Properties
134

135
136     /**
137      * Associated Catalina connector.
138      */

139     protected Connector connector;
140
141     /**
142      * Return the Connector through which this Request was received.
143      */

144     public Connector getConnector() {
145         return (this.connector);
146     }
147
148     /**
149      * Set the Connector through which this Request was received.
150      *
151      * @param connector The new connector
152      */

153     public void setConnector(Connector connector) {
154         this.connector = connector;
155     }
156
157
158     /**
159      * Coyote response.
160      */

161     protected Response JavaDoc coyoteResponse;
162
163     /**
164      * Set the Coyote response.
165      *
166      * @param response The Coyote response
167      */

168     public void setCoyoteResponse(Response JavaDoc coyoteResponse) {
169         this.coyoteResponse = coyoteResponse;
170         outputBuffer.setResponse(coyoteResponse);
171     }
172
173     /**
174      * Get the Coyote response.
175      */

176     public Response JavaDoc getCoyoteResponse() {
177         return (coyoteResponse);
178     }
179
180
181     /**
182      * Return the Context within which this Request is being processed.
183      */

184     public Context getContext() {
185         return (request.getContext());
186     }
187
188     /**
189      * Set the Context within which this Request is being processed. This
190      * must be called as soon as the appropriate Context is identified, because
191      * it identifies the value to be returned by <code>getContextPath()</code>,
192      * and thus enables parsing of the request URI.
193      *
194      * @param context The newly associated Context
195      */

196     public void setContext(Context context) {
197         request.setContext(context);
198     }
199
200
201     /**
202      * The associated output buffer.
203      */

204     // START OF SJSAS 6231069
205
//protected OutputBuffer outputBuffer = new OutputBuffer();
206
protected OutputBuffer outputBuffer;
207     // END OF SJSAS 6231069
208

209     /**
210      * The associated output stream.
211      */

212     // START OF SJSAS 6231069
213
/*protected CoyoteOutputStream outputStream =
214         new CoyoteOutputStream(outputBuffer);*/

215     protected CoyoteOutputStream outputStream;
216     // END OF SJSAS 6231069
217

218     /**
219      * The associated writer.
220      */

221     // START OF SJSAS 6231069
222
// protected CoyoteWriter writer = new CoyoteWriter(outputBuffer);
223
protected CoyoteWriter writer;
224     // END OF SJSAS 6231069
225

226
227     /**
228      * The application commit flag.
229      */

230     protected boolean appCommitted = false;
231
232
233     /**
234      * The included flag.
235      */

236     protected boolean included = false;
237
238     
239     /**
240      * The characterEncoding flag
241      */

242     private boolean isCharacterEncodingSet = false;
243     
244     /**
245      * The contextType flag
246      */

247     private boolean isContentTypeSet = false;
248
249     
250     /**
251      * The error flag.
252      */

253     protected boolean error = false;
254
255
256     /**
257      * The set of Cookies associated with this Response.
258      */

259     protected ArrayList JavaDoc cookies = new ArrayList JavaDoc();
260
261
262     /**
263      * Using output stream flag.
264      */

265     protected boolean usingOutputStream = false;
266
267
268     /**
269      * Using writer flag.
270      */

271     protected boolean usingWriter = false;
272
273
274     /**
275      * URL encoder.
276      */

277     protected UEncoder urlEncoder = new UEncoder();
278
279
280     /**
281      * Recyclable buffer to hold the redirect URL.
282      */

283     protected CharChunk redirectURLCC = new CharChunk();
284
285
286     // --------------------------------------------------------- Public Methods
287

288
289     /**
290      * Release all object references, and initialize instance variables, in
291      * preparation for reuse of this object.
292      */

293     public void recycle() {
294
295         outputBuffer.recycle();
296         usingOutputStream = false;
297         usingWriter = false;
298         appCommitted = false;
299         included = false;
300         error = false;
301         isContentTypeSet = false;
302         isCharacterEncodingSet = false;
303         detailErrorMsg = null;
304
305         cookies.clear();
306
307         if (Constants.SECURITY) {
308             if (facade != null) {
309                 facade.clear();
310                 facade = null;
311             }
312             if (outputStream != null) {
313                 outputStream.clear();
314                 outputStream = null;
315             }
316             if (writer != null) {
317                 writer.clear();
318                 writer = null;
319             }
320         } else {
321             writer.recycle();
322         }
323
324     }
325
326
327     // ------------------------------------------------------- Response Methods
328

329
330     /**
331      * Return the number of bytes actually written to the output stream.
332      */

333     public int getContentCount() {
334         return outputBuffer.getContentWritten();
335     }
336
337
338     /**
339      * Set the application commit flag.
340      *
341      * @param appCommitted The new application committed flag value
342      */

343     public void setAppCommitted(boolean appCommitted) {
344         this.appCommitted = appCommitted;
345     }
346
347
348     /**
349      * Application commit flag accessor.
350      */

351     public boolean isAppCommitted() {
352         return (this.appCommitted || isCommitted() || isSuspended()
353                 || ((getContentLength() > 0)
354                     && (getContentCount() >= getContentLength())));
355     }
356
357
358     /**
359      * Return the "processing inside an include" flag.
360      */

361     public boolean getIncluded() {
362         return included;
363     }
364
365
366     /**
367      * Set the "processing inside an include" flag.
368      *
369      * @param included <code>true</code> if we are currently inside a
370      * RequestDispatcher.include(), else <code>false</code>
371      */

372     public void setIncluded(boolean included) {
373         this.included = included;
374     }
375
376
377     /**
378      * Return descriptive information about this Response implementation and
379      * the corresponding version number, in the format
380      * <code>&lt;description&gt;/&lt;version&gt;</code>.
381      */

382     public String JavaDoc getInfo() {
383         return (info);
384     }
385
386
387     /**
388      * The request with which this response is associated.
389      */

390     protected CoyoteRequest request = null;
391
392     /**
393      * Return the Request with which this Response is associated.
394      */

395     public org.apache.catalina.Request getRequest() {
396         return (this.request);
397     }
398
399     /**
400      * Set the Request with which this Response is associated.
401      *
402      * @param request The new associated request
403      */

404     public void setRequest(org.apache.catalina.Request request) {
405         this.request = (CoyoteRequest) request;
406     }
407
408
409     /**
410      * The facade associated with this response.
411      */

412     protected CoyoteResponseFacade facade = null;
413
414     /**
415      * Return the <code>ServletResponse</code> for which this object
416      * is the facade.
417      */

418     public HttpServletResponse JavaDoc getResponse() {
419         if (facade == null) {
420             facade = new CoyoteResponseFacade(this);
421         }
422         return (facade);
423     }
424
425
426     /**
427      * Return the output stream associated with this Response.
428      */

429     public OutputStream JavaDoc getStream() {
430         if (outputStream == null) {
431             outputStream = new CoyoteOutputStream(outputBuffer);
432         }
433         return outputStream;
434     }
435
436
437     /**
438      * Set the output stream associated with this Response.
439      *
440      * @param stream The new output stream
441      */

442     public void setStream(OutputStream JavaDoc stream) {
443         // This method is evil
444
}
445
446
447     /**
448      * Set the suspended flag.
449      *
450      * @param suspended The new suspended flag value
451      */

452     public void setSuspended(boolean suspended) {
453         outputBuffer.setSuspended(suspended);
454     }
455
456
457     /**
458      * Suspended flag accessor.
459      */

460     public boolean isSuspended() {
461         return outputBuffer.isSuspended();
462     }
463
464
465     /**
466      * Set the error flag.
467      */

468     public void setError() {
469         error = true;
470     }
471
472
473     /**
474      * Error flag accessor.
475      */

476     public boolean isError() {
477         return error;
478     }
479
480
481     // BEGIN S1AS 4878272
482
/**
483      * Sets detail error message.
484      *
485      * @param message detail error message
486      */

487     public void setDetailMessage(String JavaDoc message) {
488         this.detailErrorMsg = message;
489     }
490
491
492     /**
493      * Gets detail error message.
494      *
495      * @return the detail error message
496      */

497     public String JavaDoc getDetailMessage() {
498         return this.detailErrorMsg;
499     }
500     // END S1AS 4878272
501

502
503     /**
504      * Create and return a ServletOutputStream to write the content
505      * associated with this Response.
506      *
507      * @exception IOException if an input/output error occurs
508      */

509     public ServletOutputStream JavaDoc createOutputStream()
510         throws IOException JavaDoc {
511         // Probably useless
512
if (outputStream == null) {
513             outputStream = new CoyoteOutputStream(outputBuffer);
514         }
515         return outputStream;
516     }
517
518
519     /**
520      * Perform whatever actions are required to flush and close the output
521      * stream or writer, in a single operation.
522      *
523      * @exception IOException if an input/output error occurs
524      */

525     public void finishResponse()
526         throws IOException JavaDoc {
527         // Writing leftover bytes
528
try {
529             outputBuffer.close();
530         } catch(IOException JavaDoc e) {
531         ;
532         } catch(Throwable JavaDoc t) {
533         t.printStackTrace();
534         }
535     }
536
537
538     /**
539      * Return the content length that was set or calculated for this Response.
540      */

541     public int getContentLength() {
542         return (coyoteResponse.getContentLength());
543     }
544
545
546     /**
547      * Return the content type that was set or calculated for this response,
548      * or <code>null</code> if no content type was set.
549      */

550     public String JavaDoc getContentType() {
551         return (coyoteResponse.getContentType());
552     }
553
554
555     /**
556      * Return a PrintWriter that can be used to render error messages,
557      * regardless of whether a stream or writer has already been acquired.
558      *
559      * @return Writer which can be used for error reports. If the response is
560      * not an error report returned using sendError or triggered by an
561      * unexpected exception thrown during the servlet processing
562      * (and only in that case), null will be returned if the response stream
563      * has already been used.
564      *
565      * @exception IOException if an input/output error occurs
566      */

567     public PrintWriter JavaDoc getReporter() throws IOException JavaDoc {
568         if (outputBuffer.isNew()) {
569             outputBuffer.checkConverter();
570             if (writer == null) {
571                 writer = new CoyoteWriter(outputBuffer);
572             }
573             return writer;
574         } else {
575             return null;
576         }
577     }
578
579
580     // ------------------------------------------------ ServletResponse Methods
581

582
583     /**
584      * Flush the buffer and commit this response.
585      *
586      * @exception IOException if an input/output error occurs
587      */

588     public void flushBuffer()
589         throws IOException JavaDoc {
590         outputBuffer.flush();
591     }
592
593
594     /**
595      * Return the actual buffer size used for this Response.
596      */

597     public int getBufferSize() {
598         return outputBuffer.getBufferSize();
599     }
600
601
602     /**
603      * Return the character encoding used for this Response.
604      */

605     public String JavaDoc getCharacterEncoding() {
606         return (coyoteResponse.getCharacterEncoding());
607     }
608
609
610     /**
611      * Return the servlet output stream associated with this Response.
612      *
613      * @exception IllegalStateException if <code>getWriter</code> has
614      * already been called for this response
615      * @exception IOException if an input/output error occurs
616      */

617     public ServletOutputStream JavaDoc getOutputStream()
618         throws IOException JavaDoc {
619
620         if (usingWriter)
621             throw new IllegalStateException JavaDoc
622                 (sm.getString("coyoteResponse.getOutputStream.ise"));
623
624         usingOutputStream = true;
625         if (outputStream == null) {
626             outputStream = new CoyoteOutputStream(outputBuffer);
627         }
628         return outputStream;
629
630     }
631
632
633     /**
634      * Return the Locale assigned to this response.
635      */

636     public Locale JavaDoc getLocale() {
637         return (coyoteResponse.getLocale());
638     }
639
640
641     /**
642      * Return the writer associated with this Response.
643      *
644      * @exception IllegalStateException if <code>getOutputStream</code> has
645      * already been called for this response
646      * @exception IOException if an input/output error occurs
647      */

648     public PrintWriter JavaDoc getWriter()
649         throws IOException JavaDoc {
650
651         if (usingOutputStream)
652             throw new IllegalStateException JavaDoc
653                 (sm.getString("coyoteResponse.getWriter.ise"));
654
655         /*
656          * If the response's character encoding has not been specified as
657          * described in <code>getCharacterEncoding</code> (i.e., the method
658          * just returns the default value <code>ISO-8859-1</code>),
659          * <code>getWriter</code> updates it to <code>ISO-8859-1</code>
660          * (with the effect that a subsequent call to getContentType() will
661          * include a charset=ISO-8859-1 component which will also be
662          * reflected in the Content-Type response header, thereby satisfying
663          * the Servlet spec requirement that containers must communicate the
664          * character encoding used for the servlet response's writer to the
665          * client).
666          */

667         setCharacterEncoding(getCharacterEncoding());
668
669         usingWriter = true;
670         outputBuffer.checkConverter();
671         if (writer == null) {
672             writer = new CoyoteWriter(outputBuffer);
673         }
674         return writer;
675
676     }
677
678
679     /**
680      * Has the output of this response already been committed?
681      */

682     public boolean isCommitted() {
683         return (coyoteResponse.isCommitted());
684     }
685
686
687     /**
688      * Clear any content written to the buffer.
689      *
690      * @exception IllegalStateException if this response has already
691      * been committed
692      */

693     public void reset() {
694
695         if (included)
696             return; // Ignore any call from an included servlet
697

698         coyoteResponse.reset();
699         outputBuffer.reset();
700     }
701
702
703     /**
704      * Reset the data buffer but not any status or header information.
705      *
706      * @exception IllegalStateException if the response has already
707      * been committed
708      */

709     public void resetBuffer() {
710
711         if (isCommitted())
712             throw new IllegalStateException JavaDoc
713                 (sm.getString("coyoteResponse.resetBuffer.ise"));
714
715         outputBuffer.reset();
716
717     }
718
719
720     /**
721      * Set the buffer size to be used for this Response.
722      *
723      * @param size The new buffer size
724      *
725      * @exception IllegalStateException if this method is called after
726      * output has been committed for this response
727      */

728     public void setBufferSize(int size) {
729
730         if (isCommitted() || !outputBuffer.isNew())
731             throw new IllegalStateException JavaDoc
732                 (sm.getString("coyoteResponse.setBufferSize.ise"));
733
734         outputBuffer.setBufferSize(size);
735
736     }
737
738
739     /**
740      * Set the content length (in bytes) for this Response.
741      *
742      * @param length The new content length
743      */

744     public void setContentLength(int length) {
745
746         if (isCommitted())
747             return;
748
749         // Ignore any call from an included servlet
750
if (included)
751             return;
752         
753         if (usingWriter)
754             return;
755         
756         coyoteResponse.setContentLength(length);
757
758     }
759
760
761     /**
762      * Set the content type for this Response.
763      *
764      * @param type The new content type
765      */

766     public void setContentType(String JavaDoc type) {
767
768         if (isCommitted())
769             return;
770
771         // Ignore any call from an included servlet
772
if (included)
773             return;
774
775         // Ignore charset if getWriter() has already been called
776
if (usingWriter) {
777             if (type != null) {
778                 int index = type.indexOf(";");
779                 if (index != -1) {
780                     type = type.substring(0, index);
781                 }
782             }
783         }
784
785         coyoteResponse.setContentType(type);
786
787         // Check to see if content type contains charset
788
if (type != null) {
789             int index = type.indexOf(";");
790             if (index != -1) {
791                 int len = type.length();
792                 index++;
793                 while (index < len && Character.isSpace(type.charAt(index))) {
794                     index++;
795                 }
796                 if (index+7 < len
797                         && type.charAt(index) == 'c'
798                         && type.charAt(index+1) == 'h'
799                         && type.charAt(index+2) == 'a'
800                         && type.charAt(index+3) == 'r'
801                         && type.charAt(index+4) == 's'
802                         && type.charAt(index+5) == 'e'
803                         && type.charAt(index+6) == 't'
804                         && type.charAt(index+7) == '=') {
805                     isCharacterEncodingSet = true;
806                 }
807             }
808         }
809
810         isContentTypeSet = true;
811     }
812
813
814     /*
815      * Overrides the name of the character encoding used in the body
816      * of the request. This method must be called prior to reading
817      * request parameters or reading input using getReader().
818      *
819      * @param charset String containing the name of the chararacter encoding.
820      */

821     public void setCharacterEncoding(String JavaDoc charset) {
822
823         if (isCommitted())
824             return;
825         
826         // Ignore any call from an included servlet
827
if (included)
828             return;
829         
830         // Ignore any call made after the getWriter has been invoked
831
// The default should be used
832
if (usingWriter)
833             return;
834
835         coyoteResponse.setCharacterEncoding(charset);
836         isCharacterEncodingSet = true;
837     }
838
839     
840     
841     /**
842      * Set the Locale that is appropriate for this response, including
843      * setting the appropriate character encoding.
844      *
845      * @param locale The new locale
846      */

847     public void setLocale(Locale JavaDoc locale) {
848
849         if (isCommitted())
850             return;
851
852         // Ignore any call from an included servlet
853
if (included)
854             return;
855
856         coyoteResponse.setLocale(locale);
857
858         // Ignore any call made after the getWriter has been invoked.
859
// The default should be used
860
if (usingWriter)
861             return;
862
863         if (isCharacterEncodingSet) {
864             return;
865         }
866
867         CharsetMapper cm = getContext().getCharsetMapper();
868         String JavaDoc charset = cm.getCharset( locale );
869         if ( charset != null ){
870             coyoteResponse.setCharacterEncoding(charset);
871         }
872
873     }
874
875
876     // --------------------------------------------------- HttpResponse Methods
877

878
879     /**
880      * Return an array of all cookies set for this response, or
881      * a zero-length array if no cookies have been set.
882      */

883     public Cookie JavaDoc[] getCookies() {
884         return ((Cookie JavaDoc[]) cookies.toArray(new Cookie JavaDoc[cookies.size()]));
885     }
886
887
888     /**
889      * Return the value for the specified header, or <code>null</code> if this
890      * header has not been set. If more than one value was added for this
891      * name, only the first is returned; use getHeaderValues() to retrieve all
892      * of them.
893      *
894      * @param name Header name to look up
895      */

896     public String JavaDoc getHeader(String JavaDoc name) {
897         return coyoteResponse.getMimeHeaders().getHeader(name);
898     }
899
900
901     /**
902      * Return an array of all the header names set for this response, or
903      * a zero-length array if no headers have been set.
904      */

905     public String JavaDoc[] getHeaderNames() {
906
907         MimeHeaders headers = coyoteResponse.getMimeHeaders();
908         int n = headers.size();
909         String JavaDoc[] result = new String JavaDoc[n];
910         for (int i = 0; i < n; i++) {
911             result[i] = headers.getName(i).toString();
912         }
913         return result;
914
915     }
916
917
918     /**
919      * Return an array of all the header values associated with the
920      * specified header name, or an zero-length array if there are no such
921      * header values.
922      *
923      * @param name Header name to look up
924      */

925     public String JavaDoc[] getHeaderValues(String JavaDoc name) {
926
927         Enumeration JavaDoc e = coyoteResponse.getMimeHeaders().values(name);
928         Vector JavaDoc result = new Vector JavaDoc();
929         while (e.hasMoreElements()) {
930             result.addElement(e.nextElement());
931         }
932         String JavaDoc[] resultArray = new String JavaDoc[result.size()];
933         result.copyInto(resultArray);
934         return resultArray;
935
936     }
937
938
939     /**
940      * Return the error message that was set with <code>sendError()</code>
941      * for this Response.
942      */

943     public String JavaDoc getMessage() {
944         return coyoteResponse.getMessage();
945     }
946
947
948     /**
949      * Return the HTTP status code associated with this Response.
950      */

951     public int getStatus() {
952         return coyoteResponse.getStatus();
953     }
954
955
956     /**
957      * Reset this response, and specify the values for the HTTP status code
958      * and corresponding message.
959      *
960      * @exception IllegalStateException if this response has already been
961      * committed
962      */

963     public void reset(int status, String JavaDoc message) {
964         reset();
965         setStatus(status, message);
966     }
967
968
969     // -------------------------------------------- HttpServletResponse Methods
970

971
972     /**
973      * Add the specified Cookie to those that will be included with
974      * this Response.
975      *
976      * @param cookie Cookie to be added
977      */

978     public void addCookie(final Cookie JavaDoc cookie) {
979
980         if (isCommitted())
981             return;
982
983         // Ignore any call from an included servlet
984
if (included)
985             return;
986
987         cookies.add(cookie);
988
989         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
990         if (SecurityUtil.isPackageProtectionEnabled()) {
991             AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
992                 public Object JavaDoc run(){
993                     ServerCookie.appendCookieValue
994                         (sb, cookie.getVersion(), cookie.getName(),
995                          cookie.getValue(), cookie.getPath(),
996                          cookie.getDomain(), cookie.getComment(),
997                          cookie.getMaxAge(), cookie.getSecure());
998                     return null;
999                 }
1000            });
1001        } else {
1002            ServerCookie.appendCookieValue
1003                (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
1004                     cookie.getPath(), cookie.getDomain(), cookie.getComment(),
1005                     cookie.getMaxAge(), cookie.getSecure());
1006        }
1007
1008        // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
1009
// RFC2965 is not supported by browsers and the Servlet spec
1010
// asks for 2109.
1011
addHeader("Set-Cookie", sb.toString());
1012
1013    }
1014
1015
1016    /**
1017     * Add the specified date header to the specified value.
1018     *
1019     * @param name Name of the header to set
1020     * @param value Date value to be set
1021     */

1022    public void addDateHeader(String JavaDoc name, long value) {
1023
1024        if (isCommitted())
1025            return;
1026
1027        // Ignore any call from an included servlet
1028
if (included) {
1029            return;
1030        }
1031
1032        if (format == null) {
1033            format = new SimpleDateFormat JavaDoc(DateTool.HTTP_RESPONSE_DATE_HEADER,
1034                                          Locale.US);
1035            format.setTimeZone(TimeZone.getTimeZone("GMT"));
1036        }
1037
1038        addHeader(name, FastHttpDateFormat.formatDate(value, format));
1039
1040    }
1041
1042
1043    /**
1044     * Add the specified header to the specified value.
1045     *
1046     * @param name Name of the header to set
1047     * @param value Value to be set
1048     */

1049    public void addHeader(String JavaDoc name, String JavaDoc value) {
1050
1051        if (isCommitted())
1052            return;
1053
1054        // Ignore any call from an included servlet
1055
if (included)
1056            return;
1057
1058        coyoteResponse.addHeader(name, value);
1059
1060    }
1061
1062
1063    /**
1064     * Add the specified integer header to the specified value.
1065     *
1066     * @param name Name of the header to set
1067     * @param value Integer value to be set
1068     */

1069    public void addIntHeader(String JavaDoc name, int value) {
1070
1071        if (isCommitted())
1072            return;
1073
1074        // Ignore any call from an included servlet
1075
if (included)
1076            return;
1077
1078        addHeader(name, "" + value);
1079
1080    }
1081
1082
1083    /**
1084     * Has the specified header been set already in this response?
1085     *
1086     * @param name Name of the header to check
1087     */

1088    public boolean containsHeader(String JavaDoc name) {
1089        return coyoteResponse.containsHeader(name);
1090    }
1091
1092
1093    /**
1094     * Encode the session identifier associated with this response
1095     * into the specified redirect URL, if necessary.
1096     *
1097     * @param url URL to be encoded
1098     */

1099    public String JavaDoc encodeRedirectURL(String JavaDoc url) {
1100
1101        if (isEncodeable(toAbsolute(url))) {
1102            return (toEncoded(url, request.getSessionInternal().getIdInternal()));
1103        } else {
1104            return (url);
1105        }
1106
1107    }
1108
1109
1110    /**
1111     * Encode the session identifier associated with this response
1112     * into the specified redirect URL, if necessary.
1113     *
1114     * @param url URL to be encoded
1115     *
1116     * @deprecated As of Version 2.1 of the Java Servlet API, use
1117     * <code>encodeRedirectURL()</code> instead.
1118     */

1119    public String JavaDoc encodeRedirectUrl(String JavaDoc url) {
1120        return (encodeRedirectURL(url));
1121    }
1122
1123
1124    /**
1125     * Encode the session identifier associated with this response
1126     * into the specified URL, if necessary.
1127     *
1128     * @param url URL to be encoded
1129     */

1130    public String JavaDoc encodeURL(String JavaDoc url) {
1131        
1132        String JavaDoc absolute = toAbsolute(url);
1133        if (isEncodeable(absolute)) {
1134            // W3c spec clearly said
1135
if (url.equalsIgnoreCase("")){
1136                url = absolute;
1137            }
1138            return (toEncoded(url, request.getSessionInternal().getIdInternal()));
1139        } else {
1140            return (url);
1141        }
1142
1143    }
1144
1145
1146    /**
1147     * Encode the session identifier associated with this response
1148     * into the specified URL, if necessary.
1149     *
1150     * @param url URL to be encoded
1151     *
1152     * @deprecated As of Version 2.1 of the Java Servlet API, use
1153     * <code>encodeURL()</code> instead.
1154     */

1155    public String JavaDoc encodeUrl(String JavaDoc url) {
1156        return (encodeURL(url));
1157    }
1158
1159
1160    /**
1161     * Send an acknowledgment of a request.
1162     *
1163     * @exception IOException if an input/output error occurs
1164     */

1165    public void sendAcknowledgement()
1166        throws IOException JavaDoc {
1167
1168        if (isCommitted())
1169            return;
1170
1171        // Ignore any call from an included servlet
1172
if (included)
1173            return;
1174
1175        coyoteResponse.acknowledge();
1176
1177    }
1178
1179
1180    /**
1181     * Send an error response with the specified status and a
1182     * default message.
1183     *
1184     * @param status HTTP status code to send
1185     *
1186     * @exception IllegalStateException if this response has
1187     * already been committed
1188     * @exception IOException if an input/output error occurs
1189     */

1190    public void sendError(int status)
1191        throws IOException JavaDoc {
1192        sendError(status, null);
1193    }
1194
1195
1196    /**
1197     * Send an error response with the specified status and message.
1198     *
1199     * @param status HTTP status code to send
1200     * @param message Corresponding message to send
1201     *
1202     * @exception IllegalStateException if this response has
1203     * already been committed
1204     * @exception IOException if an input/output error occurs
1205     */

1206    public void sendError(int status, String JavaDoc message)
1207        throws IOException JavaDoc {
1208
1209        if (isCommitted())
1210            throw new IllegalStateException JavaDoc
1211                (sm.getString("coyoteResponse.sendError.ise"));
1212
1213        // Ignore any call from an included servlet
1214
if (included)
1215            return;
1216
1217        Wrapper wrapper = getRequest().getWrapper();
1218        if (wrapper != null) {
1219            wrapper.incrementErrorCount();
1220        }
1221
1222        setError();
1223
1224        coyoteResponse.setStatus(status);
1225        coyoteResponse.setMessage(message);
1226
1227        // Clear any data content that has been buffered
1228
resetBuffer();
1229
1230        // Cause the response to be finished (from the application perspective)
1231
setSuspended(true);
1232
1233    }
1234
1235
1236    /**
1237     * Send a temporary redirect to the specified redirect location URL.
1238     *
1239     * @param location Location URL to redirect to
1240     *
1241     * @exception IllegalStateException if this response has
1242     * already been committed
1243     * @exception IOException if an input/output error occurs
1244     */

1245    public void sendRedirect(String JavaDoc location)
1246        throws IOException JavaDoc {
1247
1248        if (isCommitted())
1249            throw new IllegalStateException JavaDoc
1250                (sm.getString("coyoteResponse.sendRedirect.ise"));
1251
1252        // Ignore any call from an included servlet
1253
if (included)
1254            return;
1255
1256        // Clear any data content that has been buffered
1257
resetBuffer();
1258
1259        // Generate a temporary redirect to the specified location
1260
try {
1261            /* RIMOD 4642650
1262            String absolute = toAbsolute(location);
1263            */

1264            // START RIMOD 4642650
1265
String JavaDoc absolute;
1266            if (getContext().getAllowRelativeRedirect())
1267                absolute = location;
1268            else
1269                absolute = toAbsolute(location);
1270            // END RIMOD 4642650
1271
setStatus(SC_FOUND);
1272            setHeader("Location", absolute);
1273        } catch (IllegalArgumentException JavaDoc e) {
1274            setStatus(SC_NOT_FOUND);
1275        }
1276
1277        // Cause the response to be finished (from the application perspective)
1278
setSuspended(true);
1279
1280    }
1281
1282
1283    /**
1284     * Set the specified date header to the specified value.
1285     *
1286     * @param name Name of the header to set
1287     * @param value Date value to be set
1288     */

1289    public void setDateHeader(String JavaDoc name, long value) {
1290
1291        if (isCommitted())
1292            return;
1293
1294        // Ignore any call from an included servlet
1295
if (included) {
1296            return;
1297        }
1298
1299        if (format == null) {
1300            format = new SimpleDateFormat JavaDoc(DateTool.HTTP_RESPONSE_DATE_HEADER,
1301                                          Locale.US);
1302            format.setTimeZone(TimeZone.getTimeZone("GMT"));
1303        }
1304
1305        setHeader(name, FastHttpDateFormat.formatDate(value, format));
1306
1307    }
1308
1309
1310    /**
1311     * Set the specified header to the specified value.
1312     *
1313     * @param name Name of the header to set
1314     * @param value Value to be set
1315     */

1316    public void setHeader(String JavaDoc name, String JavaDoc value) {
1317
1318        if (isCommitted())
1319            return;
1320
1321        // Ignore any call from an included servlet
1322
if (included)
1323            return;
1324
1325        coyoteResponse.setHeader(name, value);
1326
1327    }
1328
1329
1330    /**
1331     * Set the specified integer header to the specified value.
1332     *
1333     * @param name Name of the header to set
1334     * @param value Integer value to be set
1335     */

1336    public void setIntHeader(String JavaDoc name, int value) {
1337
1338        if (isCommitted())
1339            return;
1340
1341        // Ignore any call from an included servlet
1342
if (included)
1343            return;
1344
1345        setHeader(name, "" + value);
1346
1347    }
1348
1349
1350    /**
1351     * Set the HTTP status to be returned with this response.
1352     *
1353     * @param status The new HTTP status
1354     */

1355    public void setStatus(int status) {
1356        setStatus(status, null);
1357    }
1358
1359
1360    /**
1361     * Set the HTTP status and message to be returned with this response.
1362     *
1363     * @param status The new HTTP status
1364     * @param message The associated text message
1365     *
1366     * @deprecated As of Version 2.1 of the Java Servlet API, this method
1367     * has been deprecated due to the ambiguous meaning of the message
1368     * parameter.
1369     */

1370    public void setStatus(int status, String JavaDoc message) {
1371
1372        if (isCommitted())
1373            return;
1374
1375        // Ignore any call from an included servlet
1376
if (included)
1377            return;
1378
1379        coyoteResponse.setStatus(status);
1380        coyoteResponse.setMessage(message);
1381
1382    }
1383
1384
1385    // ------------------------------------------------------ Protected Methods
1386

1387
1388    /**
1389     * Return <code>true</code> if the specified URL should be encoded with
1390     * a session identifier. This will be true if all of the following
1391     * conditions are met:
1392     * <ul>
1393     * <li>The request we are responding to asked for a valid session
1394     * <li>The requested session ID was not received via a cookie
1395     * <li>The specified URL points back to somewhere within the web
1396     * application that is responding to this request
1397     * </ul>
1398     *
1399     * @param location Absolute URL to be validated
1400     */

1401    protected boolean isEncodeable(final String JavaDoc location) {
1402
1403        if (location == null)
1404            return (false);
1405
1406        // Is this an intra-document reference?
1407
if (location.startsWith("#"))
1408            return (false);
1409
1410        // Are we in a valid session that is not using cookies?
1411
final CoyoteRequest hreq = request;
1412        final Session session = hreq.getSessionInternal(false);
1413        if (session == null)
1414            return (false);
1415        if (hreq.isRequestedSessionIdFromCookie())
1416            return (false);
1417        
1418        if (SecurityUtil.isPackageProtectionEnabled()) {
1419            return ((Boolean JavaDoc)
1420                AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
1421
1422                public Object JavaDoc run(){
1423                    return new Boolean JavaDoc(doIsEncodeable(hreq, session, location));
1424                }
1425            })).booleanValue();
1426        } else {
1427            return doIsEncodeable(hreq, session, location);
1428        }
1429    }
1430
1431    private boolean doIsEncodeable(CoyoteRequest hreq, Session session,
1432                                   String JavaDoc location){
1433        // Is this a valid absolute URL?
1434
URL url = null;
1435        try {
1436            url = new URL(location);
1437        } catch (MalformedURLException JavaDoc e) {
1438            return (false);
1439        }
1440
1441        // Does this URL match down to (and including) the context path?
1442
if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
1443            return (false);
1444        if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
1445            return (false);
1446        int serverPort = hreq.getServerPort();
1447        if (serverPort == -1) {
1448            if ("https".equals(hreq.getScheme()))
1449                serverPort = 443;
1450            else
1451                serverPort = 80;
1452        }
1453        int urlPort = url.getPort();
1454        if (urlPort == -1) {
1455            if ("https".equals(url.getProtocol()))
1456                urlPort = 443;
1457            else
1458                urlPort = 80;
1459        }
1460        if (serverPort != urlPort)
1461            return (false);
1462
1463        String JavaDoc contextPath = getContext().getPath();
1464        if ( contextPath != null ) {
1465            String JavaDoc file = url.getFile();
1466            if ((file == null) || !file.startsWith(contextPath))
1467                return (false);
1468            if( file.indexOf(";jsessionid=" + session.getIdInternal()) >= 0 )
1469                return (false);
1470        }
1471
1472        // This URL belongs to our web application, so it is encodeable
1473
return (true);
1474
1475    }
1476
1477
1478    /**
1479     * Convert (if necessary) and return the absolute URL that represents the
1480     * resource referenced by this possibly relative URL. If this URL is
1481     * already absolute, return it unchanged.
1482     *
1483     * @param location URL to be (possibly) converted and then returned
1484     *
1485     * @exception IllegalArgumentException if a MalformedURLException is
1486     * thrown when converting the relative URL to an absolute one
1487     */

1488    protected String JavaDoc toAbsolute(String JavaDoc location) {
1489
1490        if (location == null)
1491            return (location);
1492
1493        boolean leadingSlash = location.startsWith("/");
1494
1495        if (leadingSlash
1496            || (!leadingSlash && (location.indexOf("://") == -1))) {
1497
1498            redirectURLCC.recycle();
1499
1500            String JavaDoc scheme = request.getScheme();
1501
1502            // START S1AS 6170450
1503
if (getConnector() != null
1504                    && getConnector().getAuthPassthroughEnabled()) {
1505                ProxyHandler proxyHandler = getConnector().getProxyHandler();
1506                if (proxyHandler != null
1507                        && proxyHandler.getSSLKeysize(request) > 0) {
1508                    scheme = "https";
1509                }
1510            }
1511            // END S1AS 6170450
1512

1513            String JavaDoc name = request.getServerName();
1514            int port = request.getServerPort();
1515
1516            try {
1517                redirectURLCC.append(scheme, 0, scheme.length());
1518                redirectURLCC.append("://", 0, 3);
1519                redirectURLCC.append(name, 0, name.length());
1520                if ((scheme.equals("http") && port != 80)
1521                    || (scheme.equals("https") && port != 443)) {
1522                    redirectURLCC.append(':');
1523                    String JavaDoc portS = port + "";
1524                    redirectURLCC.append(portS, 0, portS.length());
1525                }
1526                if (!leadingSlash) {
1527                    String JavaDoc relativePath = request.getDecodedRequestURI();
1528                    int pos = relativePath.lastIndexOf('/');
1529                    relativePath = relativePath.substring(0, pos);
1530                    
1531                    String JavaDoc encodedURI = null;
1532                    final String JavaDoc frelativePath = relativePath;
1533                    
1534                     if (SecurityUtil.isPackageProtectionEnabled() ){
1535                        try{
1536                            encodedURI = (String JavaDoc)AccessController.doPrivileged(
1537                                new PrivilegedExceptionAction JavaDoc(){
1538                                    public Object JavaDoc run() throws IOException JavaDoc{
1539                                        return urlEncoder.encodeURL(frelativePath);
1540                                    }
1541                           });
1542                        } catch (PrivilegedActionException JavaDoc pae){
1543                            IllegalArgumentException JavaDoc iae =
1544                                new IllegalArgumentException JavaDoc(location);
1545                            iae.initCause(pae.getCause());
1546                            throw iae;
1547                        }
1548                    } else {
1549                        encodedURI = urlEncoder.encodeURL(relativePath);
1550                    }
1551                          
1552                    redirectURLCC.append(encodedURI, 0, encodedURI.length());
1553                    redirectURLCC.append('/');
1554                }
1555                redirectURLCC.append(location, 0, location.length());
1556            } catch (IOException JavaDoc e) {
1557                IllegalArgumentException JavaDoc iae =
1558                    new IllegalArgumentException JavaDoc(location);
1559                iae.initCause(e);
1560                throw iae;
1561            }
1562
1563            return redirectURLCC.toString();
1564
1565        } else {
1566
1567            return (location);
1568
1569        }
1570
1571    }
1572
1573
1574    /**
1575     * Return the specified URL with the specified session identifier
1576     * suitably encoded.
1577     *
1578     * @param url URL to be encoded with the session id
1579     * @param sessionId Session id to be included in the encoded URL
1580     */

1581    protected String JavaDoc toEncoded(String JavaDoc url, String JavaDoc sessionId) {
1582
1583        if ((url == null) || (sessionId == null))
1584            return (url);
1585
1586        String JavaDoc path = url;
1587        String JavaDoc query = "";
1588        String JavaDoc anchor = "";
1589        int question = url.indexOf('?');
1590        if (question >= 0) {
1591            path = url.substring(0, question);
1592            query = url.substring(question);
1593        }
1594        int pound = path.indexOf('#');
1595        if (pound >= 0) {
1596            anchor = path.substring(pound);
1597            path = path.substring(0, pound);
1598        }
1599        StringBuffer JavaDoc sb = new StringBuffer JavaDoc(path);
1600        if( sb.length() > 0 ) { // jsessionid can't be first.
1601
sb.append(";jsessionid=");
1602            sb.append(sessionId);
1603        }
1604
1605        // START SJSAS 6337561
1606
String JavaDoc jrouteId = request.getHeader(Constants.PROXY_JROUTE);
1607        if (jrouteId != null) {
1608            sb.append(":");
1609            sb.append(jrouteId);
1610        }
1611        // END SJSAS 6337561
1612

1613        sb.append(anchor);
1614        sb.append(query);
1615        return (sb.toString());
1616
1617    }
1618
1619
1620}
1621
1622
Popular Tags