| 1 | | /* | | 1 | | /* | | 1 | | /* |
| 2 | | * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v 1.10 2001/07/22 20 :25: 07 pier Exp $ | | 2 | | * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v 1.11 2002/03/18 07:15:40 remm Exp $ | | 2 | | * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestStream.java,v 1.11 2002/03/18 07:15:40 remm Exp $ |
| 3 | | * $Revision: 1.10 $ | | 3 | | * $Revision: 1.11 $ | | 3 | | * $Revision: 1.11 $ |
| 4 | | * $Date: 2001/07/22 20 :25: 07 $ | | 4 | | * $Date: 2002/03/18 07:15:40 $ | | 4 | | * $Date: 2002/03/18 07:15:40 $ |
| 5 | | * | | 5 | | * | | 5 | | * |
| 6 | | * ==================================================================== | | 6 | | * ==================================================================== | | 6 | | * ==================================================================== |
| 7 | | * | | 7 | | * | | 7 | | * |
| 8 | | * The Apache Software License, Version 1.1 | | 8 | | * The Apache Software License, Version 1.1 | | 8 | | * The Apache Software License, Version 1.1 |
| 9 | | * | | 9 | | * | | 9 | | * |
| 10 | | * Copyright (c) 1999 The Apache Software Foundation. All rights | | 10 | | * Copyright (c) 1999 The Apache Software Foundation. All rights | | 10 | | * Copyright (c) 1999 The Apache Software Foundation. All rights |
| 11 | | * reserved. | | 11 | | * reserved. | | 11 | | * reserved. |
| 12 | | * | | 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 | | 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 | | 14 | | * modification, are permitted provided that the following conditions |
| 15 | | * are met: | | 15 | | * are met: | | 15 | | * are met: |
| 16 | | * | | 16 | | * | | 16 | | * |
| 17 | | * 1. Redistributions of source code must retain the above copyright | | 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. | | 18 | | * notice, this list of conditions and the following disclaimer. |
| 19 | | * | | 19 | | * | | 19 | | * |
| 20 | | * 2. Redistributions in binary form must reproduce the above copyright | | 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 | | 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 | | 22 | | * the documentation and/or other materials provided with the |
| 23 | | * distribution. | | 23 | | * distribution. | | 23 | | * distribution. |
| 24 | | * | | 24 | | * | | 24 | | * |
| 25 | | * 3. The end-user documentation included with the redistribution, if | | 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: | | 26 | | * any, must include the following acknowlegement: |
| 27 | | * "This product includes software developed by the | | 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/)." | | 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, | | 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. | | 30 | | * if and wherever such third-party acknowlegements normally appear. |
| 31 | | * | | 31 | | * | | 31 | | * |
| 32 | | * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software | | 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 | | 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 | | 34 | | * from this software without prior written permission. For written |
| 35 | | * permission, please contact apache@apache.org. | | 35 | | * permission, please contact apache@apache.org. | | 35 | | * permission, please contact apache@apache.org. |
| 36 | | * | | 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" | | 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 | | 38 | | * nor may "Apache" appear in their names without prior written |
| 39 | | * permission of the Apache Group. | | 39 | | * permission of the Apache Group. | | 39 | | * permission of the Apache Group. |
| 40 | | * | | 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 | | 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 | | 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 | | 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 | | 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, | | 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 | | 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 | | 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 | | 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, | | 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 | | 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 | | 51 | | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 52 | | * SUCH DAMAGE. | | 52 | | * SUCH DAMAGE. | | 52 | | * SUCH DAMAGE. |
| 53 | | * ==================================================================== | | 53 | | * ==================================================================== | | 53 | | * ==================================================================== |
| 54 | | * | | 54 | | * | | 54 | | * |
| 55 | | * This software consists of voluntary contributions made by many | | 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 | | 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 | | 57 | | * information on the Apache Software Foundation, please see |
| 58 | | * <http://www.apache.org/>. | | 58 | | * <http://www.apache.org/>. | | 58 | | * <http://www.apache.org/>. |
| 59 | | * | | 59 | | * | | 59 | | * |
| 60 | | * [Additional notices, if required by prior licensing conditions] | | 60 | | * [Additional notices, if required by prior licensing conditions] | | 60 | | * [Additional notices, if required by prior licensing conditions] |
| 61 | | * | | 61 | | * | | 61 | | * |
| 62 | | */ | | 62 | | */ | | 62 | | */ |
| 63 | | | | 63 | | | | 63 | | |
| 64 | | | | 64 | | | | 64 | | |
| 65 | | package org.apache.catalina.connector.http; | | 65 | | package org.apache.catalina.connector.http; | | 65 | | package org.apache.catalina.connector.http; |
| 66 | | | | 66 | | | | 66 | | |
| 67 | | import java.io.IOException; | | 67 | | import java.io.IOException; | | 67 | | import java.io.IOException; |
| 68 | | import org.apache.catalina.Request; | | 68 | | import org.apache.catalina.Request; | | 68 | | import org.apache.catalina.Request; |
| 69 | | import org.apache.catalina.connector.RequestStream; | | 69 | | import org.apache.catalina.connector.RequestStream; | | 69 | | import org.apache.catalina.connector.RequestStream; |
| 70 | | | | 70 | | | | 70 | | |
| 71 | | /** | | 71 | | /** | | 71 | | /** |
| 72 | | * | | 72 | | * | | 72 | | * |
| 73 | | * | | 73 | | * | | 73 | | * |
| 74 | | * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> | | 74 | | * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> | | 74 | | * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> |
| | | | | 75 | | * @deprecated | | 75 | | * @deprecated |
| 75 | | */ | | 76 | | */ | | 76 | | */ |
| 76 | | public class HttpRequestStream extends RequestStream { | | 77 | | public class HttpRequestStream extends RequestStream { | | 77 | | public class HttpRequestStream extends RequestStream { |
| 77 | | | | 78 | | | | 78 | | |
| 78 | | | | 79 | | | | 79 | | |
| 79 | | // ----------------------------------------------------------- Constructors | | 80 | | // ----------------------------------------------------------- Constructors | | 80 | | // ----------------------------------------------------------- Constructors |
| 80 | | | | 81 | | | | 81 | | |
| 81 | | | | 82 | | | | 82 | | |
| 82 | | /** | | 83 | | /** | | 83 | | /** |
| 83 | | * Construct a servlet input stream associated with the specified Request. | | 84 | | * Construct a servlet input stream associated with the specified Request. | | 84 | | * Construct a servlet input stream associated with the specified Request. |
| 84 | | * | | 85 | | * | | 85 | | * |
| 85 | | * @param request The associated request | | 86 | | * @param request The associated request | | 86 | | * @param request The associated request |
| 86 | | * @param response The associated response | | 87 | | * @param response The associated response | | 87 | | * @param response The associated response |
| 87 | | */ | | 88 | | */ | | 88 | | */ |
| 88 | | public HttpRequestStream(HttpRequestImpl request, | | 89 | | public HttpRequestStream(HttpRequestImpl request, | | 89 | | public HttpRequestStream(HttpRequestImpl request, |
| 89 | | HttpResponseImpl response) { | | 90 | | HttpResponseImpl response) { | | 90 | | HttpResponseImpl response) { |
| 90 | | | | 91 | | | | 91 | | |
| 91 | | super(request); | | 92 | | super(request); | | 92 | | super(request); |
| 92 | | String transferEncoding = request.getHeader("Transfer-Encoding"); | | 93 | | String transferEncoding = request.getHeader("Transfer-Encoding"); | | 93 | | String transferEncoding = request.getHeader("Transfer-Encoding"); |
| 93 | | | | 94 | | | | 94 | | |
| 94 | | http11 = request.getProtocol().equals("HTTP/1.1"); | | 95 | | http11 = request.getProtocol().equals("HTTP/1.1"); | | 95 | | http11 = request.getProtocol().equals("HTTP/1.1"); |
| 95 | | chunk = ((transferEncoding != null) | | 96 | | chunk = ((transferEncoding != null) | | 96 | | chunk = ((transferEncoding != null) |
| 96 | | && (transferEncoding.indexOf("chunked") != -1)); | | 97 | | && (transferEncoding.indexOf("chunked") != -1)); | | 97 | | && (transferEncoding.indexOf("chunked") != -1)); |
| 97 | | | | 98 | | | | 98 | | |
| 98 | | if ((!chunk) && (length == -1)) { | | 99 | | if ((!chunk) && (length == -1)) { | | 99 | | if ((!chunk) && (length == -1)) { |
| 99 | | // Ask for connection close | | 100 | | // Ask for connection close | | 100 | | // Ask for connection close |
| 100 | | response.addHeader("Connection", "close"); | | 101 | | response.addHeader("Connection", "close"); | | 101 | | response.addHeader("Connection", "close"); |
| 101 | | } | | 102 | | } | | 102 | | } |
| 102 | | | | 103 | | | | 103 | | |
| 103 | | } | | 104 | | } | | 104 | | } |
| 104 | | | | 105 | | | | 105 | | |
| 105 | | | | 106 | | | | 106 | | |
| 106 | | // ----------------------------------------------------- Instance Variables | | 107 | | // ----------------------------------------------------- Instance Variables | | 107 | | // ----------------------------------------------------- Instance Variables |
| 107 | | | | 108 | | | | 108 | | |
| 108 | | | | 109 | | | | 109 | | |
| 109 | | /** | | 110 | | /** | | 110 | | /** |
| 110 | | * Use chunking ? | | 111 | | * Use chunking ? | | 111 | | * Use chunking ? |
| 111 | | */ | | 112 | | */ | | 112 | | */ |
| 112 | | protected boolean chunk = false; | | 113 | | protected boolean chunk = false; | | 113 | | protected boolean chunk = false; |
| 113 | | | | 114 | | | | 114 | | |
| 114 | | | | 115 | | | | 115 | | |
| 115 | | /** | | 116 | | /** | | 116 | | /** |
| 116 | | * True if the final chunk was found. | | 117 | | * True if the final chunk was found. | | 117 | | * True if the final chunk was found. |
| 117 | | */ | | 118 | | */ | | 118 | | */ |
| 118 | | protected boolean endChunk = false; | | 119 | | protected boolean endChunk = false; | | 119 | | protected boolean endChunk = false; |
| 119 | | | | 120 | | | | 120 | | |
| 120 | | | | 121 | | | | 121 | | |
| 121 | | /** | | 122 | | /** | | 122 | | /** |
| 122 | | * Chunk buffer. | | 123 | | * Chunk buffer. | | 123 | | * Chunk buffer. |
| 123 | | */ | | 124 | | */ | | 124 | | */ |
| 124 | | protected byte[] chunkBuffer = null; | | 125 | | protected byte[] chunkBuffer = null; | | 125 | | protected byte[] chunkBuffer = null; |
| 125 | | | | 126 | | | | 126 | | |
| 126 | | | | 127 | | | | 127 | | |
| 127 | | /** | | 128 | | /** | | 128 | | /** |
| 128 | | * Chunk length. | | 129 | | * Chunk length. | | 129 | | * Chunk length. |
| 129 | | */ | | 130 | | */ | | 130 | | */ |
| 130 | | protected int chunkLength = 0; | | 131 | | protected int chunkLength = 0; | | 131 | | protected int chunkLength = 0; |
| 131 | | | | 132 | | | | 132 | | |
| 132 | | | | 133 | | | | 133 | | |
| 133 | | /** | | 134 | | /** | | 134 | | /** |
| 134 | | * Chunk buffer position. | | 135 | | * Chunk buffer position. | | 135 | | * Chunk buffer position. |
| 135 | | */ | | 136 | | */ | | 136 | | */ |
| 136 | | protected int chunkPos = 0; | | 137 | | protected int chunkPos = 0; | | 137 | | protected int chunkPos = 0; |
| 137 | | | | 138 | | | | 138 | | |
| 138 | | | | 139 | | | | 139 | | |
| 139 | | /** | | 140 | | /** | | 140 | | /** |
| 140 | | * HTTP/1.1 flag. | | 141 | | * HTTP/1.1 flag. | | 141 | | * HTTP/1.1 flag. |
| 141 | | */ | | 142 | | */ | | 142 | | */ |
| 142 | | protected boolean http11 = false; | | 143 | | protected boolean http11 = false; | | 143 | | protected boolean http11 = false; |
| 143 | | | | 144 | | | | 144 | | |
| 144 | | | | 145 | | | | 145 | | |
| 145 | | // --------------------------------------------------------- Public Methods | | 146 | | // --------------------------------------------------------- Public Methods | | 146 | | // --------------------------------------------------------- Public Methods |
| 146 | | | | 147 | | | | 147 | | |
| 147 | | | | 148 | | | | 148 | | |
| 148 | | /** | | 149 | | /** | | 149 | | /** |
| 149 | | * Close this input stream. No physical level I-O is performed, but | | 150 | | * Close this input stream. No physical level I-O is performed, but | | 150 | | * Close this input stream. No physical level I-O is performed, but |
| 150 | | * any further attempt to read from this stream will throw an IOException. | | 151 | | * any further attempt to read from this stream will throw an IOException. | | 151 | | * any further attempt to read from this stream will throw an IOException. |
| 151 | | * If a content length has been set but not all of the bytes have yet been | | 152 | | * If a content length has been set but not all of the bytes have yet been | | 152 | | * If a content length has been set but not all of the bytes have yet been |
| 152 | | * consumed, the remaining bytes will be swallowed. | | 153 | | * consumed, the remaining bytes will be swallowed. | | 153 | | * consumed, the remaining bytes will be swallowed. |
| 153 | | */ | | 154 | | */ | | 154 | | */ |
| 154 | | public void close() | | 155 | | public void close() | | 155 | | public void close() |
| 155 | | throws IOException { | | 156 | | throws IOException { | | 156 | | throws IOException { |
| 156 | | | | 157 | | | | 157 | | |
| 157 | | if (closed) | | 158 | | if (closed) | | 158 | | if (closed) |
| 158 | | throw new IOException(sm.getString("requestStream.close.closed")); | | 159 | | throw new IOException(sm.getString("requestStream.close.closed")); | | 159 | | throw new IOException(sm.getString("requestStream.close.closed")); |
| 159 | | | | 160 | | | | 160 | | |
| 160 | | if (chunk) { | | 161 | | if (chunk) { | | 161 | | if (chunk) { |
| 161 | | | | 162 | | | | 162 | | |
| 162 | | while (!endChunk) { | | 163 | | while (!endChunk) { | | 163 | | while (!endChunk) { |
| 163 | | int b = read(); | | 164 | | int b = read(); | | 164 | | int b = read(); |
| 164 | | if (b < 0) | | 165 | | if (b < 0) | | 165 | | if (b < 0) |
| 165 | | break; | | 166 | | break; | | 166 | | break; |
| 166 | | } | | 167 | | } | | 167 | | } |
| 167 | | | | 168 | | | | 168 | | |
| 168 | | } else { | | 169 | | } else { | | 169 | | } else { |
| 169 | | | | 170 | | | | 170 | | |
| 170 | | if (http11 && (length > 0)) { | | 171 | | if (http11 && (length > 0)) { | | 171 | | if (http11 && (length > 0)) { |
| 171 | | while (count < length) { | | 172 | | while (count < length) { | | 172 | | while (count < length) { |
| 172 | | int b = read(); | | 173 | | int b = read(); | | 173 | | int b = read(); |
| 173 | | if (b < 0) | | 174 | | if (b < 0) | | 174 | | if (b < 0) |
| 174 | | break; | | 175 | | break; | | 175 | | break; |
| 175 | | } | | 176 | | } | | 176 | | } |
| 176 | | } | | 177 | | } | | 177 | | } |
| 177 | | | | 178 | | | | 178 | | |
| 178 | | } | | 179 | | } | | 179 | | } |
| 179 | | | | 180 | | | | 180 | | |
| 180 | | closed = true; | | 181 | | closed = true; | | 181 | | closed = true; |
| 181 | | | | 182 | | | | 182 | | |
| 182 | | } | | 183 | | } | | 183 | | } |
| 183 | | | | 184 | | | | 184 | | |
| 184 | | | | 185 | | | | 185 | | |
| 185 | | /** | | 186 | | /** | | 186 | | /** |
| 186 | | * Read and return a single byte from this input stream, or -1 if end of | | 187 | | * Read and return a single byte from this input stream, or -1 if end of | | 187 | | * Read and return a single byte from this input stream, or -1 if end of |
| 187 | | * file has been encountered. | | 188 | | * file has been encountered. | | 188 | | * file has been encountered. |
| 188 | | * | | 189 | | * | | 189 | | * |
| 189 | | * @exception IOException if an input/output error occurs | | 190 | | * @exception IOException if an input/output error occurs | | 190 | | * @exception IOException if an input/output error occurs |
| 190 | | */ | | 191 | | */ | | 191 | | */ |
| 191 | | public int read() | | 192 | | public int read() | | 192 | | public int read() |
| 192 | | throws IOException { | | 193 | | throws IOException { | | 193 | | throws IOException { |
| 193 | | | | 194 | | | | 194 | | |
| 194 | | // Has this stream been closed? | | 195 | | // Has this stream been closed? | | 195 | | // Has this stream been closed? |
| 195 | | if (closed) | | 196 | | if (closed) | | 196 | | if (closed) |
| 196 | | throw new IOException(sm.getString("requestStream.read.closed")); | | 197 | | throw new IOException(sm.getString("requestStream.read.closed")); | | 197 | | throw new IOException(sm.getString("requestStream.read.closed")); |
| 197 | | | | 198 | | | | 198 | | |
| 198 | | if (chunk) { | | 199 | | if (chunk) { | | 199 | | if (chunk) { |
| 199 | | | | 200 | | | | 200 | | |
| 200 | | if (endChunk) | | 201 | | if (endChunk) | | 201 | | if (endChunk) |
| 201 | | return (-1); | | 202 | | return (-1); | | 202 | | return (-1); |
| 202 | | | | 203 | | | | 203 | | |
| 203 | | if ((chunkBuffer == null) | | 204 | | if ((chunkBuffer == null) | | 204 | | if ((chunkBuffer == null) |
| 204 | | || (chunkPos >= chunkLength)) { | | 205 | | || (chunkPos >= chunkLength)) { | | 205 | | || (chunkPos >= chunkLength)) { |
| 205 | | if (!fillChunkBuffer()) | | 206 | | if (!fillChunkBuffer()) | | 206 | | if (!fillChunkBuffer()) |
| 206 | | return (-1); | | 207 | | return (-1); | | 207 | | return (-1); |
| 207 | | } | | 208 | | } | | 208 | | } |
| 208 | | | | 209 | | | | 209 | | |
| 209 | | return (chunkBuffer[chunkPos++] & 0xff); | | 210 | | return (chunkBuffer[chunkPos++] & 0xff); | | 210 | | return (chunkBuffer[chunkPos++] & 0xff); |
| 210 | | | | 211 | | | | 211 | | |
| 211 | | } else { | | 212 | | } else { | | 212 | | } else { |
| 212 | | | | 213 | | | | 213 | | |
| 213 | | return (super.read()); | | 214 | | return (super.read()); | | 214 | | return (super.read()); |
| 214 | | | | 215 | | | | 215 | | |
| 215 | | } | | 216 | | } | | 216 | | } |
| 216 | | | | 217 | | | | 217 | | |
| 217 | | } | | 218 | | } | | 218 | | } |
| 218 | | | | 219 | | | | 219 | | |
| 219 | | | | 220 | | | | 220 | | |
| 220 | | /** | | 221 | | /** | | 221 | | /** |
| 221 | | * Read up to <code>len</code> bytes of data from the input stream | | 222 | | * Read up to <code>len</code> bytes of data from the input stream | | 222 | | * Read up to <code>len</code> bytes of data from the input stream |
| 222 | | * into an array of bytes. An attempt is made to read as many as | | 223 | | * into an array of bytes. An attempt is made to read as many as | | 223 | | * into an array of bytes. An attempt is made to read as many as |
| 223 | | * <code>len</code> bytes, but a smaller number may be read, | | 224 | | * <code>len</code> bytes, but a smaller number may be read, | | 224 | | * <code>len</code> bytes, but a smaller number may be read, |
| 224 | | * possibly zero. The number of bytes actually read is returned as | | 225 | | * possibly zero. The number of bytes actually read is returned as | | 225 | | * possibly zero. The number of bytes actually read is returned as |
| 225 | | * an integer. This method blocks until input data is available, | | 226 | | * an integer. This method blocks until input data is available, | | 226 | | * an integer. This method blocks until input data is available, |
| 226 | | * end of file is detected, or an exception is thrown. | | 227 | | * end of file is detected, or an exception is thrown. | | 227 | | * end of file is detected, or an exception is thrown. |
| 227 | | * | | 228 | | * | | 228 | | * |
| 228 | | * @param b The buffer into which the data is read | | 229 | | * @param b The buffer into which the data is read | | 229 | | * @param b The buffer into which the data is read |
| 229 | | * @param off The start offset into array <code>b</code> at which | | 230 | | * @param off The start offset into array <code>b</code> at which | | 230 | | * @param off The start offset into array <code>b</code> at which |
| 230 | | * the data is written | | 231 | | * the data is written | | 231 | | * the data is written |
| 231 | | * @param len The maximum number of bytes to read | | 232 | | * @param len The maximum number of bytes to read | | 232 | | * @param len The maximum number of bytes to read |
| 232 | | * | | 233 | | * | | 233 | | * |
| 233 | | * @exception IOException if an input/output error occurs | | 234 | | * @exception IOException if an input/output error occurs | | 234 | | * @exception IOException if an input/output error occurs |
| 234 | | */ | | 235 | | */ | | 235 | | */ |
| 235 | | public int read(byte b[], int off, int len) throws IOException { | | 236 | | public int read(byte b[], int off, int len) throws IOException { | | 236 | | public int read(byte b[], int off, int len) throws IOException { |
| 236 | | if (chunk) { | | 237 | | if (chunk) { | | 237 | | if (chunk) { |
| 237 | | | | 238 | | | | 238 | | |
| 238 | | int avail = chunkLength - chunkPos; | | 239 | | int avail = chunkLength - chunkPos; | | 239 | | int avail = chunkLength - chunkPos; |
| 239 | | if (avail == 0) | | 240 | | if (avail == 0) | | 240 | | if (avail == 0) |
| 240 | | fillChunkBuffer(); | | 241 | | fillChunkBuffer(); | | 241 | | fillChunkBuffer(); |
| 241 | | avail = chunkLength - chunkPos; | | 242 | | avail = chunkLength - chunkPos; | | 242 | | avail = chunkLength - chunkPos; |
| 242 | | if (avail == 0) | | 243 | | if (avail == 0) | | 243 | | if (avail == 0) |
| 243 | | return (-1); | | 244 | | return (-1); | | 244 | | return (-1); |
| 244 | | | | 245 | | | | 245 | | |
| 245 | | int toCopy = avail; | | 246 | | int toCopy = avail; | | 246 | | int toCopy = avail; |
| 246 | | if (avail > len) | | 247 | | if (avail > len) | | 247 | | if (avail > len) |
| 247 | | toCopy = len; | | 248 | | toCopy = len; | | 248 | | toCopy = len; |
| 248 | | System.arraycopy(chunkBuffer, chunkPos, b, off, toCopy); | | 249 | | System.arraycopy(chunkBuffer, chunkPos, b, off, toCopy); | | 249 | | System.arraycopy(chunkBuffer, chunkPos, b, off, toCopy); |
| 249 | | chunkPos += toCopy; | | 250 | | chunkPos += toCopy; | | 250 | | chunkPos += toCopy; |
| 250 | | return toCopy; | | 251 | | return toCopy; | | 251 | | return toCopy; |
| 251 | | | | 252 | | | | 252 | | |
| 252 | | } else { | | 253 | | } else { | | 253 | | } else { |
| 253 | | return super.read(b, off, len); | | 254 | | return super.read(b, off, len); | | 254 | | return super.read(b, off, len); |
| 254 | | } | | 255 | | } | | 255 | | } |
| 255 | | } | | 256 | | } | | 256 | | } |
| 256 | | | | 257 | | | | 257 | | |
| 257 | | | | 258 | | | | 258 | | |
| 258 | | // -------------------------------------------------------- Private Methods | | 259 | | // -------------------------------------------------------- Private Methods | | 259 | | // -------------------------------------------------------- Private Methods |
| 259 | | | | 260 | | | | 260 | | |
| 260 | | | | 261 | | | | 261 | | |
| 261 | | /** | | 262 | | /** | | 262 | | /** |
| 262 | | * Fill the chunk buffer. | | 263 | | * Fill the chunk buffer. | | 263 | | * Fill the chunk buffer. |
| 263 | | */ | | 264 | | */ | | 264 | | */ |
| 264 | | private synchronized boolean fillChunkBuffer() | | 265 | | private synchronized boolean fillChunkBuffer() | | 265 | | private synchronized boolean fillChunkBuffer() |
| 265 | | throws IOException { | | 266 | | throws IOException { | | 266 | | throws IOException { |
| 266 | | | | 267 | | | | 267 | | |
| 267 | | chunkPos = 0; | | 268 | | chunkPos = 0; | | 268 | | chunkPos = 0; |
| 268 | | | | 269 | | | | 269 | | |
| 269 | | try { | | 270 | | try { | | 270 | | try { |
| 270 | | String numberValue = readLineFromStream(); | | 271 | | String numberValue = readLineFromStream(); | | 271 | | String numberValue = readLineFromStream(); |
| 271 | | if (numberValue != null) | | 272 | | if (numberValue != null) | | 272 | | if (numberValue != null) |
| 272 | | numberValue = numberValue.trim(); | | 273 | | numberValue = numberValue.trim(); | | 273 | | numberValue = numberValue.trim(); |
| 273 | | chunkLength = | | 274 | | chunkLength = | | 274 | | chunkLength = |
| 274 | | Integer.parseInt(numberValue, 16); | | 275 | | Integer.parseInt(numberValue, 16); | | 275 | | Integer.parseInt(numberValue, 16); |
| 275 | | } catch (NumberFormatException e) { | | 276 | | } catch (NumberFormatException e) { | | 276 | | } catch (NumberFormatException e) { |
| 276 | | // Critical error, unable to parse the chunk length | | 277 | | // Critical error, unable to parse the chunk length | | 277 | | // Critical error, unable to parse the chunk length |
| 277 | | chunkLength = 0; | | 278 | | chunkLength = 0; | | 278 | | chunkLength = 0; |
| 278 | | chunk = false; | | 279 | | chunk = false; | | 279 | | chunk = false; |
| 279 | | close(); | | 280 | | close(); | | 280 | | close(); |
| 280 | | return false; | | 281 | | return false; | | 281 | | return false; |
| 281 | | } | | 282 | | } | | 282 | | } |
| 282 | | | | 283 | | | | 283 | | |
| 283 | | if (chunkLength == 0) { | | 284 | | if (chunkLength == 0) { | | 284 | | if (chunkLength == 0) { |
| 284 | | | | 285 | | | | 285 | | |
| 285 | | // Skipping trailing headers, if any | | 286 | | // Skipping trailing headers, if any | | 286 | | // Skipping trailing headers, if any |
| 286 | | String trailingLine = readLineFromStream(); | | 287 | | String trailingLine = readLineFromStream(); | | 287 | | String trailingLine = readLineFromStream(); |
| 287 | | while (!trailingLine.equals("")) | | 288 | | while (!trailingLine.equals("")) | | 288 | | while (!trailingLine.equals("")) |
| 288 | | trailingLine = readLineFromStream(); | | 289 | | trailingLine = readLineFromStream(); | | 289 | | trailingLine = readLineFromStream(); |
| 289 | | endChunk = true; | | 290 | | endChunk = true; | | 290 | | endChunk = true; |
| 290 | | return false; | | 291 | | return false; | | 291 | | return false; |
| 291 | | // TODO : Should the stream be automatically closed ? | | 292 | | // TODO : Should the stream be automatically closed ? | | 292 | | // TODO : Should the stream be automatically closed ? |
| 292 | | | | 293 | | | | 293 | | |
| 293 | | } else { | | 294 | | } else { | | 294 | | } else { |
| 294 | | | | 295 | | | | 295 | | |
| 295 | | if ((chunkBuffer == null) | | 296 | | if ((chunkBuffer == null) | | 296 | | if ((chunkBuffer == null) |
| 296 | | || (chunkLength > chunkBuffer.length)) | | 297 | | || (chunkLength > chunkBuffer.length)) | | 297 | | || (chunkLength > chunkBuffer.length)) |
| 297 | | chunkBuffer = new byte[chunkLength]; | | 298 | | chunkBuffer = new byte[chunkLength]; | | 298 | | chunkBuffer = new byte[chunkLength]; |
| 298 | | | | 299 | | | | 299 | | |
| 299 | | // Now read the whole chunk into the buffer | | 300 | | // Now read the whole chunk into the buffer | | 300 | | // Now read the whole chunk into the buffer |
| 300 | | | | 301 | | | | 301 | | |
| 301 | | int nbRead = 0; | | 302 | | int nbRead = 0; | | 302 | | int nbRead = 0; |
| 302 | | int currentRead = 0; | | 303 | | int currentRead = 0; | | 303 | | int currentRead = 0; |
| 303 | | | | 304 | | | | 304 | | |
| 304 | | while (nbRead < chunkLength) { | | 305 | | while (nbRead < chunkLength) { | | 305 | | while (nbRead < chunkLength) { |
| 305 | | try { | | 306 | | try { | | 306 | | try { |
| 306 | | currentRead = | | 307 | | currentRead = | | 307 | | currentRead = |
| 307 | | stream.read(chunkBuffer, nbRead, | | 308 | | stream.read(chunkBuffer, nbRead, | | 308 | | stream.read(chunkBuffer, nbRead, |
| 308 | | chunkLength - nbRead); | | 309 | | chunkLength - nbRead); | | 309 | | chunkLength - nbRead); |
| 309 | | } catch (Throwable t) { | | 310 | | } catch (Throwable t) { | | 310 | | } catch (Throwable t) { |
| 310 | | t.printStackTrace(); | | 311 | | t.printStackTrace(); | | 311 | | t.printStackTrace(); |
| 311 | | throw new IOException(); | | 312 | | throw new IOException(); | | 312 | | throw new IOException(); |
| 312 | | } | | 313 | | } | | 313 | | } |
| 313 | | if (currentRead < 0) { | | 314 | | if (currentRead < 0) { | | 314 | | if (currentRead < 0) { |
| 314 | | throw new IOException | | 315 | | throw new IOException | | 315 | | throw new IOException |
| 315 | | (sm.getString("requestStream.read.error")); | | 316 | | (sm.getString("requestStream.read.error")); | | 316 | | (sm.getString("requestStream.read.error")); |
| 316 | | } | | 317 | | } | | 317 | | } |
| 317 | | nbRead += currentRead; | | 318 | | nbRead += currentRead; | | 318 | | nbRead += currentRead; |
| 318 | | } | | 319 | | } | | 319 | | } |
| 319 | | | | 320 | | | | 320 | | |
| 320 | | // Skipping the CRLF | | 321 | | // Skipping the CRLF | | 321 | | // Skipping the CRLF |
| 321 | | String blank = readLineFromStream(); | | 322 | | String blank = readLineFromStream(); | | 322 | | String blank = readLineFromStream(); |
| 322 | | | | 323 | | | | 323 | | |
| 323 | | } | | 324 | | } | | 324 | | } |
| 324 | | | | 325 | | | | 325 | | |
| 325 | | return true; | | 326 | | return true; | | 326 | | return true; |
| 326 | | | | 327 | | | | 327 | | |
| 327 | | } | | 328 | | } | | 328 | | } |
| 328 | | | | 329 | | | | 329 | | |
| 329 | | | | 330 | | | | 330 | | |
| 330 | | /** | | 331 | | /** | | 331 | | /** |
| 331 | | * Reads the input stream, one line at a time. Reads bytes into an array, | | 332 | | * Reads the input stream, one line at a time. Reads bytes into an array, | | 332 | | * Reads the input stream, one line at a time. Reads bytes into an array, |
| 332 | | * until it reads a certain number of bytes or reaches a newline character, | | 333 | | * until it reads a certain number of bytes or reaches a newline character, | | 333 | | * until it reads a certain number of bytes or reaches a newline character, |
| 333 | | * which it reads into the array as well. | | 334 | | * which it reads into the array as well. | | 334 | | * which it reads into the array as well. |
| 334 | | * | | 335 | | * | | 335 | | * |
| 335 | | * @param input Input stream on which the bytes are read | | 336 | | * @param input Input stream on which the bytes are read | | 336 | | * @param input Input stream on which the bytes are read |
| 336 | | * @return The line that was read, or <code>null</code> if end-of-file | | 337 | | * @return The line that was read, or <code>null</code> if end-of-file | | 337 | | * @return The line that was read, or <code>null</code> if end-of-file |
| 337 | | * was encountered | | 338 | | * was encountered | | 338 | | * was encountered |
| 338 | | * @exception IOException if an input or output exception has occurred | | 339 | | * @exception IOException if an input or output exception has occurred | | 339 | | * @exception IOException if an input or output exception has occurred |
| 339 | | */ | | 340 | | */ | | 340 | | */ |
| 340 | | private String readLineFromStream() | | 341 | | private String readLineFromStream() | | 341 | | private String readLineFromStream() |
| 341 | | throws IOException { | | 342 | | throws IOException { | | 342 | | throws IOException { |
| 342 | | | | 343 | | | | 343 | | |
| 343 | | StringBuffer sb = new StringBuffer(); | | 344 | | StringBuffer sb = new StringBuffer(); | | 344 | | StringBuffer sb = new StringBuffer(); |
| 344 | | while (true) { | | 345 | | while (true) { | | 345 | | while (true) { |
| 345 | | int ch = super.read(); | | 346 | | int ch = super.read(); | | 346 | | int ch = super.read(); |
| 346 | | if (ch < 0) { | | 347 | | if (ch < 0) { | | 347 | | if (ch < 0) { |
| 347 | | if (sb.length() == 0) { | | 348 | | if (sb.length() == 0) { | | 348 | | if (sb.length() == 0) { |
| 348 | | return (null); | | 349 | | return (null); | | 349 | | return (null); |
| 349 | | } else { | | 350 | | } else { | | 350 | | } else { |
| 350 | | break; | | 351 | | break; | | 351 | | break; |
| 351 | | } | | 352 | | } | | 352 | | } |
| 352 | | } else if (ch == '\r') { | | 353 | | } else if (ch == '\r') { | | 353 | | } else if (ch == '\r') { |
| 353 | | continue; | | 354 | | continue; | | 354 | | continue; |
| 354 | | } else if (ch == '\n') { | | 355 | | } else if (ch == '\n') { | | 355 | | } else if (ch == '\n') { |
| 355 | | break; | | 356 | | break; | | 356 | | break; |
| 356 | | } | | 357 | | } | | 357 | | } |
| 357 | | sb.append((char) ch); | | 358 | | sb.append((char) ch); | | 358 | | sb.append((char) ch); |
| 358 | | } | | 359 | | } | | 359 | | } |
| 359 | | return (sb.toString()); | | 360 | | return (sb.toString()); | | 360 | | return (sb.toString()); |
| 360 | | | | 361 | | | | 361 | | |
| 361 | | } | | 362 | | } | | 362 | | } |
| 362 | | | | 363 | | | | 363 | | |
| 363 | | | | 364 | | | | 364 | | |
| 364 | | } | | 365 | | } | | 365 | | } |