1 | | /* | | 1 | | /* |
2 | | * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpResponseStream.java,v 1.7.2.4 2002/02/21 01:27:34 remm Exp $ | | 2 | | * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpResponseStream.java,v 1.14 2002/03/ 18 0 7:15:40 remm Exp $ |
3 | | * $Revision: 1.7.2.4 $ | | 3 | | * $Revision: 1.14 $ |
4 | | * $Date: 2002/02/21 01:27:34 $ | | 4 | | * $Date: 2002/03/ 18 0 7:15:40 $ |
5 | | * | | 5 | | * |
6 | | * ==================================================================== | | 6 | | * ==================================================================== |
7 | | * | | 7 | | * |
8 | | * The Apache Software License, Version 1.1 | | 8 | | * The Apache Software License, Version 1.1 |
9 | | * | | 9 | | * |
10 | | * Copyright (c) 1999 The Apache Software Foundation. All rights | | 10 | | * Copyright (c) 1999 The Apache Software Foundation. All rights |
11 | | * reserved. | | 11 | | * reserved. |
12 | | * | | 12 | | * |
13 | | * Redistribution and use in source and binary forms, with or without | | 13 | | * Redistribution and use in source and binary forms, with or without |
14 | | * modification, are permitted provided that the following conditions | | 14 | | * modification, are permitted provided that the following conditions |
15 | | * are met: | | 15 | | * are met: |
16 | | * | | 16 | | * |
17 | | * 1. Redistributions of source code must retain the above copyright | | 17 | | * 1. Redistributions of source code must retain the above copyright |
18 | | * notice, this list of conditions and the following disclaimer. | | 18 | | * notice, this list of conditions and the following disclaimer. |
19 | | * | | 19 | | * |
20 | | * 2. Redistributions in binary form must reproduce the above copyright | | 20 | | * 2. Redistributions in binary form must reproduce the above copyright |
21 | | * notice, this list of conditions and the following disclaimer in | | 21 | | * notice, this list of conditions and the following disclaimer in |
22 | | * the documentation and/or other materials provided with the | | 22 | | * the documentation and/or other materials provided with the |
23 | | * distribution. | | 23 | | * distribution. |
24 | | * | | 24 | | * |
25 | | * 3. The end-user documentation included with the redistribution, if | | 25 | | * 3. The end-user documentation included with the redistribution, if |
26 | | * any, must include the following acknowlegement: | | 26 | | * any, must include the following acknowlegement: |
27 | | * "This product includes software developed by the | | 27 | | * "This product includes software developed by the |
28 | | * Apache Software Foundation (http://www.apache.org/)." | | 28 | | * Apache Software Foundation (http://www.apache.org/)." |
29 | | * Alternately, this acknowlegement may appear in the software itself, | | 29 | | * Alternately, this acknowlegement may appear in the software itself, |
30 | | * if and wherever such third-party acknowlegements normally appear. | | 30 | | * if and wherever such third-party acknowlegements normally appear. |
31 | | * | | 31 | | * |
32 | | * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | | 32 | | * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software |
33 | | * Foundation" must not be used to endorse or promote products derived | | 33 | | * Foundation" must not be used to endorse or promote products derived |
34 | | * from this software without prior written permission. For written | | 34 | | * from this software without prior written permission. For written |
35 | | * permission, please contact apache@apache.org. | | 35 | | * permission, please contact apache@apache.org. |
36 | | * | | 36 | | * |
37 | | * 5. Products derived from this software may not be called "Apache" | | 37 | | * 5. Products derived from this software may not be called "Apache" |
38 | | * nor may "Apache" appear in their names without prior written | | 38 | | * nor may "Apache" appear in their names without prior written |
39 | | * permission of the Apache Group. | | 39 | | * permission of the Apache Group. |
40 | | * | | 40 | | * |
41 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | | 41 | | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
42 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 42 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
43 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | | 43 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
44 | | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR | | 44 | | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
45 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | | 45 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
46 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | | 46 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
47 | | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | | 47 | | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
48 | | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | | 48 | | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
49 | | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 49 | | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
50 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | | 50 | | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
51 | | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 51 | | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
52 | | * SUCH DAMAGE. | | 52 | | * SUCH DAMAGE. |
53 | | * ==================================================================== | | 53 | | * ==================================================================== |
54 | | * | | 54 | | * |
55 | | * This software consists of voluntary contributions made by many | | 55 | | * This software consists of voluntary contributions made by many |
56 | | * individuals on behalf of the Apache Software Foundation. For more | | 56 | | * individuals on behalf of the Apache Software Foundation. For more |
57 | | * information on the Apache Software Foundation, please see | | 57 | | * information on the Apache Software Foundation, please see |
58 | | * <http://www.apache.org/>. | | 58 | | * <http://www.apache.org/>. |
59 | | * | | 59 | | * |
60 | | * [Additional notices, if required by prior licensing conditions] | | 60 | | * [Additional notices, if required by prior licensing conditions] |
61 | | * | | 61 | | * |
62 | | */ | | 62 | | */ |
63 | | | | 63 | | |
64 | | | | 64 | | |
65 | | package org.apache.catalina.connector.http; | | 65 | | package org.apache.catalina.connector.http; |
66 | | | | 66 | | |
67 | | import java.io.IOException; | | 67 | | import java.io.IOException; |
68 | | import javax.servlet.http.HttpServletResponse; | | 68 | | import javax.servlet.http.HttpServletResponse; |
69 | | import javax.servlet.http.HttpServletRequest; | | 69 | | import javax.servlet.http.HttpServletRequest; |
70 | | import org.apache.catalina.Response; | | 70 | | import org.apache.catalina.Response; |
71 | | import org.apache.catalina.connector.ResponseStream; | | 71 | | import org.apache.catalina.connector.ResponseStream; |
72 | | | | 72 | | |
73 | | /** | | 73 | | /** |
74 | | * Response stream for the HTTP/1.1 connector. This stream will automatically | | 74 | | * Response stream for the HTTP/1.1 connector. This stream will automatically |
75 | | * chunk the answer if using HTTP/1.1 and no Content-Length has been properly | | 75 | | * chunk the answer if using HTTP/1.1 and no Content-Length has been properly |
76 | | * set. | | 76 | | * set. |
77 | | * | | 77 | | * |
78 | | * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> | | 78 | | * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> |
| | | | 79 | | * @deprecated |
79 | | */ | | 80 | | */ |
80 | | public final class HttpResponseStream extends ResponseStream { | | 81 | | public final class HttpResponseStream extends ResponseStream { |
81 | | | | 82 | | |
82 | | | | 83 | | |
83 | | // ----------------------------------------------------------- Constructors | | 84 | | // ----------------------------------------------------------- Constructors |
84 | | | | 85 | | |
85 | | | | 86 | | |
86 | | private static final int MAX_CHUNK_SIZE = 4096; | | 87 | | private static final int MAX_CHUNK_SIZE = 4096; |
87 | | | | 88 | | |
88 | | | | 89 | | |
89 | | private static final String CRLF = "\r\n"; | | 90 | | private static final String CRLF = "\r\n"; |
90 | | | | 91 | | |
91 | | | | 92 | | |
92 | | // ----------------------------------------------------------- Constructors | | 93 | | // ----------------------------------------------------------- Constructors |
93 | | | | 94 | | |
94 | | | | 95 | | |
95 | | /** | | 96 | | /** |
96 | | * Construct a servlet output stream associated with the specified Request. | | 97 | | * Construct a servlet output stream associated with the specified Request. |
97 | | * | | 98 | | * |
98 | | * @param response The associated response | | 99 | | * @param response The associated response |
99 | | */ | | 100 | | */ |
100 | | public HttpResponseStream(HttpResponseImpl response) { | | 101 | | public HttpResponseStream(HttpResponseImpl response) { |
101 | | | | 102 | | |
102 | | super(response); | | 103 | | super(response); |
103 | | checkChunking(response); | | 104 | | checkChunking(response); |
104 | | checkHead(response); | | 105 | | checkHead(response); |
105 | | | | 106 | | |
106 | | } | | 107 | | } |
107 | | | | 108 | | |
108 | | | | 109 | | |
109 | | // ----------------------------------------------------- Instance Variables | | 110 | | // ----------------------------------------------------- Instance Variables |
110 | | | | 111 | | |
111 | | | | 112 | | |
112 | | /** | | 113 | | /** |
113 | | * True if chunking is allowed. | | 114 | | * True if chunking is allowed. |
114 | | */ | | 115 | | */ |
115 | | private boolean useChunking; | | 116 | | private boolean useChunking; |
116 | | | | 117 | | |
117 | | | | 118 | | |
118 | | /** | | 119 | | /** |
119 | | * True if printing a chunk. | | 120 | | * True if printing a chunk. |
120 | | */ | | 121 | | */ |
121 | | private boolean writingChunk; | | 122 | | private boolean writingChunk; |
122 | | | | 123 | | |
123 | | | | 124 | | |
124 | | /** | | 125 | | /** |
125 | | * True if no content should be written. | | 126 | | * True if no content should be written. |
126 | | */ | | 127 | | */ |
127 | | private boolean writeContent; | | 128 | | private boolean writeContent; |
128 | | | | 129 | | |
129 | | | | 130 | | |
130 | | // -------------------------------------------- ServletOutputStream Methods | | 131 | | // -------------------------------------------- ServletOutputStream Methods |
131 | | | | 132 | | |
132 | | | | 133 | | |
133 | | /** | | 134 | | /** |
134 | | * Write the specified byte to our output stream. | | 135 | | * Write the specified byte to our output stream. |
135 | | * | | 136 | | * |
136 | | * @param b The byte to be written | | 137 | | * @param b The byte to be written |
137 | | * | | 138 | | * |
138 | | * @exception IOException if an input/output error occurs | | 139 | | * @exception IOException if an input/output error occurs |
139 | | */ | | 140 | | */ |
140 | | public void write(int b) | | 141 | | public void write(int b) |
141 | | throws IOException { | | 142 | | throws IOException { |
142 | | | | 143 | | |
143 | | if (suspended) | | 144 | | if (suspended) |
144 | | return; | | 145 | | return; |
145 | | | | 146 | | |
146 | | if (!writeContent) | | 147 | | if (!writeContent) |
147 | | return; | | 148 | | return; |
148 | | | | 149 | | |
149 | | if (useChunking && !writingChunk) { | | 150 | | if (useChunking && !writingChunk) { |
150 | | writingChunk = true; | | 151 | | writingChunk = true; |
151 | | try { | | 152 | | try { |
152 | | print("1\r\n"); | | 153 | | print("1\r\n"); |
153 | | super.write(b); | | 154 | | super.write(b); |
154 | | println(); | | 155 | | println(); |
155 | | } finally { | | 156 | | } finally { |
156 | | writingChunk = false; | | 157 | | writingChunk = false; |
157 | | } | | 158 | | } |
158 | | } else { | | 159 | | } else { |
159 | | super.write(b); | | 160 | | super.write(b); |
160 | | } | | 161 | | } |
161 | | | | 162 | | |
162 | | } | | 163 | | } |
163 | | | | 164 | | |
164 | | | | 165 | | |
165 | | /** | | 166 | | /** |
166 | | * Write the specified byte array. | | 167 | | * Write the specified byte array. |
167 | | */ | | 168 | | */ |
168 | | public void write(byte[] b, int off, int len) | | 169 | | public void write(byte[] b, int off, int len) |
169 | | throws IOException { | | 170 | | throws IOException { |
170 | | | | 171 | | |
171 | | if (suspended) | | 172 | | if (suspended) |
172 | | return; | | 173 | | return; |
173 | | | | 174 | | |
174 | | if (!writeContent) | | 175 | | if (!writeContent) |
175 | | return; | | 176 | | return; |
176 | | | | 177 | | |
177 | | if (useChunking && !writingChunk) { | | 178 | | if (useChunking && !writingChunk) { |
178 | | if (len > 0) { | | 179 | | if (len > 0) { |
179 | | writingChunk = true; | | 180 | | writingChunk = true; |
180 | | try { | | 181 | | try { |
181 | | println(Integer.toHexString(len)); | | 182 | | println(Integer.toHexString(len)); |
182 | | super.write(b, off, len); | | 183 | | super.write(b, off, len); |
183 | | println(); | | 184 | | println(); |
184 | | } finally { | | 185 | | } finally { |
185 | | writingChunk = false; | | 186 | | writingChunk = false; |
186 | | } | | 187 | | } |
187 | | } | | 188 | | } |
188 | | } else { | | 189 | | } else { |
189 | | super.write(b, off, len); | | 190 | | super.write(b, off, len); |
190 | | } | | 191 | | } |
191 | | | | 192 | | |
192 | | } | | 193 | | } |
193 | | | | 194 | | |
194 | | | | 195 | | |
195 | | /** | | 196 | | /** |
196 | | * Close this output stream, causing any buffered data to be flushed and | | 197 | | * Close this output stream, causing any buffered data to be flushed and |
197 | | * any further output data to throw an IOException. | | 198 | | * any further output data to throw an IOException. |
198 | | */ | | 199 | | */ |
199 | | public void close() throws IOException { | | 200 | | public void close() throws IOException { |
200 | | | | 201 | | |
201 | | if (suspended) | | 202 | | if (suspended) |
202 | | throw new IOException | | 203 | | throw new IOException |
203 | | (sm.getString("responseStream.suspended")); | | 204 | | (sm.getString("responseStream.suspended")); |
204 | | | | 205 | | |
205 | | if (!writeContent) | | 206 | | if (!writeContent) |
206 | | return; | | 207 | | return; |
207 | | | | 208 | | |
208 | | if (useChunking) { | | 209 | | if (useChunking) { |
209 | | // Write the final chunk. | | 210 | | // Write the final chunk. |
210 | | writingChunk = true; | | 211 | | writingChunk = true; |
211 | | try { | | 212 | | try { |
212 | | print("0\r\n\r\n"); | | 213 | | print("0\r\n\r\n"); |
213 | | } finally { | | 214 | | } finally { |
214 | | writingChunk = false; | | 215 | | writingChunk = false; |
215 | | } | | 216 | | } |
216 | | } | | 217 | | } |
217 | | super.close(); | | 218 | | super.close(); |
218 | | | | 219 | | |
219 | | } | | 220 | | } |
220 | | | | 221 | | |
221 | | | | 222 | | |
222 | | // -------------------------------------------------------- Package Methods | | 223 | | // -------------------------------------------------------- Package Methods |
223 | | | | 224 | | |
224 | | | | 225 | | |
225 | | void checkChunking(HttpResponseImpl response) { | | 226 | | void checkChunking(HttpResponseImpl response) { |
226 | | // If any data has already been written to the stream, we must not | | 227 | | // If any data has already been written to the stream, we must not |
227 | | // change the chunking mode | | 228 | | // change the chunking mode |
228 | | if (count != 0) | | 229 | | if (count != 0) |
229 | | return; | | 230 | | return; |
230 | | // Check the basic cases in which we chunk | | 231 | | // Check the basic cases in which we chunk |
231 | | useChunking = | | 232 | | useChunking = |
232 | | (!response.isCommitted() | | 233 | | (!response.isCommitted() |
233 | | && response.getContentLength() == -1 | | 234 | | && response.getContentLength() == -1 |
234 | | && response.getStatus() != HttpServletResponse.SC_NOT_MODIFIED); | | 235 | | && response.getStatus() != HttpServletResponse.SC_NOT_MODIFIED); |
235 | | if (!response.isChunkingAllowed() && useChunking) { | | 236 | | if (!response.isChunkingAllowed() && useChunking) { |
236 | | // If we should chunk, but chunking is forbidden by the connector, | | 237 | | // If we should chunk, but chunking is forbidden by the connector, |
237 | | // we close the connection | | 238 | | // we close the connection |
238 | | response.setHeader("Connection", "close"); | | 239 | | response.setHeader("Connection", "close"); |
239 | | } | | 240 | | } |
240 | | // Don't chunk is the connection will be closed | | 241 | | // Don't chunk is the connection will be closed |
241 | | useChunking = (useChunking && !response.isCloseConnection()); | | 242 | | useChunking = (useChunking && !response.isCloseConnection()); |
242 | | if (useChunking) { | | 243 | | if (useChunking) { |
243 | | response.setHeader("Transfer-Encoding", "chunked"); | | 244 | | response.setHeader("Transfer-Encoding", "chunked"); |
244 | | } else if (response.isChunkingAllowed()) { | | 245 | | } else if (response.isChunkingAllowed()) { |
245 | | response.removeHeader("Transfer-Encoding", "chunked"); | | 246 | | response.removeHeader("Transfer-Encoding", "chunked"); |
246 | | } | | 247 | | } |
247 | | } | | 248 | | } |
248 | | | | 249 | | |
249 | | | | 250 | | |
250 | | protected void checkHead(HttpResponseImpl response) { | | 251 | | protected void checkHead(HttpResponseImpl response) { |
251 | | HttpServletRequest servletRequest = | | 252 | | HttpServletRequest servletRequest = |
252 | | (HttpServletRequest) response.getRequest(); | | 253 | | (HttpServletRequest) response.getRequest(); |
253 | | if ("HEAD".equals(servletRequest.getMethod())) | | 254 | | if ("HEAD".equals(servletRequest.getMethod())) { |
254 | | writeContent = false; | | 255 | | writeContent = false; |
255 | | else | | 256 | | } else { |
256 | | writeContent = true; | | 257 | | writeContent = true; |
| | | | 258 | | } |
257 | | } | | 259 | | } |
258 | | | | 260 | | |
259 | | | | 261 | | |
260 | | } | | 262 | | } |