Changelog: - Wire logging is now performed exclusively by HttpConnection class - All data retrieved or sent through an HttpConnection instance is captured in the wire log (when logging is activated) - Request/response headers content is correctly encoded/decoded using conversion routines of the HttpConstants class - Primitive parsing methods moved into one class named HttpParser
You are welcome to start throwing bad tomatoes at me Cheers Oleg
Index: java/org/apache/commons/httpclient/ChunkedInputStream.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedInputStream.java,v retrieving revision 1.13 diff -u -r1.13 ChunkedInputStream.java --- java/org/apache/commons/httpclient/ChunkedInputStream.java 11 Feb 2003 03:23:05 -0000 1.13 +++ java/org/apache/commons/httpclient/ChunkedInputStream.java 12 Feb 2003 14:15:45 -0000 @@ -63,11 +63,11 @@ package org.apache.commons.httpclient; +import java.util.ArrayList; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import org.apache.commons.httpclient.util.HeaderParser; /** * <p>Transparently coalesces chunks of a HTTP stream that uses @@ -315,7 +315,16 @@ * @throws IOException If an IO problem occurs */ private void parseTrailerHeaders() throws IOException { - Header[] footers = HeaderParser.parseHeaders(in); + ArrayList lines = new ArrayList(); + for (; ;) { + String line = HttpParser.readLine(in); + if ((line == null) || (line.length() < 1)) { + break; + } + lines.add(line); + } + Header[] footers = HttpParser.parseHeaders( + (String[])lines.toArray(new String[lines.size()])); for (int i = 0; i < footers.length; i++) { method.addResponseFooter(footers[i]); Index: java/org/apache/commons/httpclient/ChunkedOutputStream.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/ChunkedOutputStream.java,v retrieving revision 1.8 diff -u -r1.8 ChunkedOutputStream.java --- java/org/apache/commons/httpclient/ChunkedOutputStream.java 8 Feb 2003 19:22:49 -0000 1.8 +++ java/org/apache/commons/httpclient/ChunkedOutputStream.java 12 Feb 2003 14:15:46 -0000 @@ -103,9 +103,6 @@ /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(ChunkedOutputStream.class); - /** Log for any wire messages. */ - private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); - // ----------------------------------------------------- Instance Variables /** Has this stream been closed? */ @@ -190,10 +187,6 @@ stream.write(CRLF, 0, CRLF.length); stream.write(b); stream.write(ENDCHUNK, 0, ENDCHUNK.length); - if (WIRE_LOG.isDebugEnabled()) { - WIRE_LOG.debug(">> byte 1 \\r\\n (chunk length \"header\")"); - WIRE_LOG.debug(">> byte " + b + "\\r\\n (chunked byte)"); - } } /** @@ -215,12 +208,6 @@ stream.write(chunkHeader, 0, chunkHeader.length); stream.write(b, off, len); stream.write(ENDCHUNK, 0, ENDCHUNK.length); - if (WIRE_LOG.isDebugEnabled()) { - WIRE_LOG.debug(">> byte(s)" + len + " \\r\\n (chunk length " - + "\"header\")"); - WIRE_LOG.debug(">> \"" + new String(b, off, len) - + "\"\\r\\n (chunked bytes)"); - } } /** @@ -239,7 +226,6 @@ stream.write(ZERO, 0, ZERO.length); stream.write(CRLF, 0, CRLF.length); stream.write(ENDCHUNK, 0, ENDCHUNK.length); - WIRE_LOG.debug(">> byte 0 \\r\\n\\r\\n (final chunk)"); } catch (IOException e) { LOG.debug("Unexpected exception caught when closing " + "output stream", e); Index: java/org/apache/commons/httpclient/HttpConnection.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v retrieving revision 1.43 diff -u -r1.43 HttpConnection.java --- java/org/apache/commons/httpclient/HttpConnection.java 11 Feb 2003 03:23:05 -0000 1.43 +++ java/org/apache/commons/httpclient/HttpConnection.java 12 Feb 2003 14:15:44 -0000 @@ -110,42 +110,6 @@ */ public class HttpConnection { - /** - * Read up to <tt>"\r\n"</tt> from an (unchunked) input stream. - * If the stream ends before the line terminator is found, - * the last part of the string will still be returned. - * '\r' and '\n' are allowed to appear individually in the stream. - * - * @param inputStream the stream to read from - * - * @throws IOException if an I/O problem occurs - * @return a line from the stream - * - * @since 2.0beta1 - */ - public static String readLine(InputStream inputStream) throws IOException { - LOG.trace("enter HttpConnection.readLine()"); - - StringBuffer buf = new StringBuffer(); - int ch = inputStream.read(); - while (ch >= 0) { - if (ch == '\r') { - ch = inputStream.read(); - if (ch == '\n') { - break; - } else { - buf.append('\r'); - } - } - buf.append((char) ch); - ch = inputStream.read(); - } - if (WIRE_LOG.isDebugEnabled()) { - WIRE_LOG.debug("<< \"" + buf.toString() + (ch>0 ? "\" [\\r\\n]" : "")); - } - return (buf.toString()); - } - // ----------------------------------------------------------- Constructors /** @@ -631,7 +595,11 @@ throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.getRequestOutputStream()"); assertOpen(); - return outputStream; + OutputStream out = this.outputStream; + if (Wire.enabled()) { + out = new WireLogOutputStream(out, HttpConstants.HTTP_ELEMENT_CHARSET); + } + return out; } /** @@ -650,11 +618,14 @@ LOG.trace("enter HttpConnection.getRequestOutputStream(boolean)"); assertOpen(); + OutputStream out = this.outputStream; + if (Wire.enabled()) { + out = new WireLogOutputStream(out, HttpConstants.HTTP_ELEMENT_CHARSET); + } if (useChunking) { - return new ChunkedOutputStream(outputStream); - } else { - return outputStream; + out = new ChunkedOutputStream(out); } + return out; } /** @@ -688,7 +659,11 @@ throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.getResponseInputStream()"); assertOpen(); - return inputStream; + InputStream in = this.inputStream; + if (Wire.enabled()) { + in = new WireLogInputStream(in, HttpConstants.HTTP_ELEMENT_CHARSET); + } + return in; } /** @@ -764,9 +739,8 @@ assertOpen(); - if (WIRE_LOG.isDebugEnabled()) { - String dataString = new String(data, offset, length, "ISO-8859-1"); - WIRE_LOG.debug(">> \"" + dataString + "\" [\\r\\n]"); + if (Wire.enabled()) { + Wire.output(data, offset, length, HttpConstants.HTTP_ELEMENT_CHARSET); } try { outputStream.write(data, offset, length); @@ -795,9 +769,8 @@ LOG.trace("enter HttpConnection.writeLine(byte[])"); assertOpen(); - if (WIRE_LOG.isDebugEnabled() && (data.length > 0)) { - String dataString = HttpConstants.getContentString(data); - WIRE_LOG.debug(">> \"" + dataString.trim() + "\" [\\r\\n]"); + if (Wire.enabled()) { + Wire.output(data, HttpConstants.HTTP_ELEMENT_CHARSET); } try { outputStream.write(data); @@ -823,7 +796,9 @@ throws IOException, IllegalStateException, HttpRecoverableException { LOG.trace("enter HttpConnection.writeLine()"); - WIRE_LOG.debug(">> [\\r\\n]"); + if (Wire.enabled()) { + Wire.output(CRLF, HttpConstants.HTTP_ELEMENT_CHARSET); + } try { outputStream.write(CRLF); } catch (SocketException se) { @@ -894,9 +869,18 @@ LOG.trace("enter HttpConnection.readLine()"); assertOpen(); - return HttpConnection.readLine(inputStream); + byte[] rawdata = HttpParser.readRawLine(inputStream); + if (Wire.enabled()) { + Wire.input(rawdata, HttpConstants.HTTP_ELEMENT_CHARSET); + } + if ((rawdata.length >= 2) && (rawdata[0] == '\r') && (rawdata[1] == '\n')) { + return HttpConstants.getString(rawdata, 0, rawdata.length - 2); + } else { + return HttpConstants.getString(rawdata); + } } + /** * Shutdown my {@link Socket}'s output, via {@link Socket#shutdownOutput}. */ @@ -1079,9 +1063,6 @@ /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(HttpConnection.class); - - /** Log for any wire messages. */ - private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); // ----------------------------------------------------- Instance Variables /** My host. */ Index: java/org/apache/commons/httpclient/HttpMethodBase.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v retrieving revision 1.111 diff -u -r1.111 HttpMethodBase.java --- java/org/apache/commons/httpclient/HttpMethodBase.java 11 Feb 2003 03:23:05 -0000 1.111 +++ java/org/apache/commons/httpclient/HttpMethodBase.java 12 Feb 2003 14:15:53 -0000 @@ -71,11 +71,11 @@ import java.net.URL; import java.util.HashSet; import java.util.Set; +import java.util.ArrayList; import java.util.StringTokenizer; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.cookie.CookieSpec; -import org.apache.commons.httpclient.util.HeaderParser; import org.apache.commons.httpclient.util.URIUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -147,9 +147,6 @@ /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(HttpMethod.class); - /** Log for any wire messages. */ - private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); - /** The User-Agent header sent on every request. */ protected static final Header USER_AGENT; @@ -1777,9 +1774,6 @@ Header lengthHeader = getResponseHeader("Content-Length"); Header transferEncodingHeader = getResponseHeader("Transfer-Encoding"); InputStream is = conn.getResponseInputStream(); - if (WIRE_LOG.isDebugEnabled()) { - is = new WireLogInputStream(is); - } InputStream result = null; // We use Transfer-Encoding if present and ignore Content-Length. // RFC2616, 4.4 item number 3 @@ -1861,8 +1855,17 @@ LOG.trace("enter HttpMethodBase.readResponseHeaders(HttpState," + "HttpConnection)"); + ArrayList lines = new ArrayList(); + for (; ;) { + String line = conn.readLine(); + if ((line == null) || (line.length() < 1)) { + break; + } + lines.add(line); + } getResponseHeaderGroup().clear(); - Header[] headers = HeaderParser.parseHeaders(conn.getResponseInputStream()); + Header[] headers = HttpParser.parseHeaders( + (String[])lines.toArray(new String[lines.size()])); getResponseHeaderGroup().setHeaders(headers); } Index: java/org/apache/commons/httpclient/HttpParser.java =================================================================== RCS file: java/org/apache/commons/httpclient/HttpParser.java diff -N java/org/apache/commons/httpclient/HttpParser.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ java/org/apache/commons/httpclient/HttpParser.java 12 Feb 2003 14:15:46 -0000 @@ -0,0 +1,136 @@ +package org.apache.commons.httpclient; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A utility class for parsing http header values. + * + * @author Michael Becke + * @author <a href="mailto:[EMAIL PROTECTED]">Oleg Kalnichevski</a> + * + * @since 2.0beta1 + */ +public class HttpParser { + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(HttpParser.class); + + /** + * Constructor for HttpParser. + */ + private HttpParser() {} + + + /** + * Return byte array from an (unchunked) input stream. + * Stop reading when <tt>"\r\n"</tt> terminator encountered + * If the stream ends before the line terminator is found, + * the last part of the string will still be returned. + * '\r' and '\n' are allowed to appear individually in the stream. + * + * @param inputStream the stream to read from + * + * @throws IOException if an I/O problem occurs + * @return a byte array from the stream + */ + public static byte[] readRawLine(InputStream inputStream) throws IOException { + LOG.trace("enter HttpConnection.readRawLine()"); + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + int ch; + while ((ch = inputStream.read()) >= 0) { + buf.write(ch); + if (ch == '\r') { + ch = inputStream.read(); + if (ch < 0) { + break; + } + buf.write(ch); + if (ch == '\n') { + break; + } + } + } + return buf.toByteArray(); + } + + /** + * Read up to <tt>"\r\n"</tt> from an (unchunked) input stream. + * If the stream ends before the line terminator is found, + * the last part of the string will still be returned. + * '\r' and '\n' are allowed to appear individually in the stream. + * + * @param inputStream the stream to read from + * + * @throws IOException if an I/O problem occurs + * @return a line from the stream + */ + + public static String readLine(InputStream inputStream) throws IOException { + LOG.trace("enter HttpConnection.readLine()"); + byte[] rawdata = readRawLine(inputStream); + if ((rawdata.length >= 2) && (rawdata[0] == '\r') && (rawdata[1] == '\n')) { + return HttpConstants.getString(rawdata, 0, rawdata.length - 2); + } else { + return HttpConstants.getString(rawdata); + } + } + + /** + * Parses headers from the given array of strings. + * Headers with the same name are not combined. + * + * @param an array of strings to be parsed + * + * @return an array of headers in the order in which they were parsed + * + * @throws HttpException if there is an error parsing a header value + */ + public static Header[] parseHeaders(String[] lines) throws HttpException { + LOG.trace("enter HeaderParser.parseHeaders(HttpConnection, HeaderGroup)"); + + ArrayList headers = new ArrayList(); + String name = null; + StringBuffer value = null; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + // Parse the header name and value + // Check for folded headers first + // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2 + // discussion on folded headers + if ((line.charAt(0) == ' ') || (line.charAt(0) == '\t')) { + // we have continuation folded header + // so append value + value.append(' '); + value.append(line.trim()); + } else { + // make sure we save the previous name,value pair if present + if (name != null) { + headers.add(new Header(name, value.toString())); + } + + // Otherwise we should have normal HTTP header line + // Parse the header name and value + int colon = line.indexOf(":"); + if (colon < 0) { + throw new HttpException("Unable to parse header: " + line); + } + name = line.substring(0, colon).trim(); + value = new StringBuffer(line.substring(colon + 1).trim()); + } + + } + + // make sure we save the last name,value pair if present + if (name != null) { + headers.add(new Header(name, value.toString())); + } + + return (Header[]) headers.toArray(new Header[headers.size()]); + } +} Index: java/org/apache/commons/httpclient/Wire.java =================================================================== RCS file: java/org/apache/commons/httpclient/Wire.java diff -N java/org/apache/commons/httpclient/Wire.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ java/org/apache/commons/httpclient/Wire.java 12 Feb 2003 14:15:46 -0000 @@ -0,0 +1,167 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact [EMAIL PROTECTED] + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.apache.commons.httpclient; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.Reader; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.UnsupportedEncodingException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Logs data to the wire LOG. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Oleg Kalnichevski</a> + * + * @since 2.0beta1 + */ + +class Wire { + + /** Log for any wire messages. */ + private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); + + private static void wire(String header, InputStream instream, String charset) + throws IOException { + if (charset == null) { + charset = "US-ASCII"; + } + Reader reader = null; + try { + reader = new InputStreamReader(instream, charset); + } catch (UnsupportedEncodingException e) { + reader = new InputStreamReader(instream); + } + StringBuffer buffer = new StringBuffer(); + int ch; + while ((ch = reader.read()) != -1) { + if (ch == 13) { + buffer.append("[\\r]"); + } else if (ch == 10){ + buffer.append("[\\n]\""); + buffer.insert(0, "\""); + buffer.insert(0, header); + WIRE_LOG.debug(buffer.toString()); + buffer.setLength(0); + } else if ((ch < 32) || (ch > 127)) { + buffer.append("[0x"); + buffer.append(Integer.toHexString(ch)); + buffer.append("]"); + } else { + buffer.append((char)ch); + } + } + if (buffer.length() > 0) { + buffer.append("\""); + buffer.insert(0, "\""); + buffer.insert(0, header); + WIRE_LOG.debug(buffer.toString()); + } + } + + + public static final boolean enabled() { + return WIRE_LOG.isDebugEnabled(); + } + + public static final void output(InputStream instream, String charset) + throws IOException { + wire(">> ", instream, charset); + } + + public static final void input(InputStream instream, String charset) + throws IOException { + wire("<< ", instream, charset); + } + + public static final void output(byte[] b, int off, int len, String charset) + throws IOException { + wire(">> ", new ByteArrayInputStream(b, off, len), charset); + } + + public static final void input(byte[] b, int off, int len, String charset) + throws IOException { + wire("<< ", new ByteArrayInputStream(b, off, len), charset); + } + + public static final void output(byte[] b, String charset) + throws IOException { + wire(">> ", new ByteArrayInputStream(b), charset); + } + + public static final void input(byte[] b, String charset) + throws IOException { + wire("<< ", new ByteArrayInputStream(b), charset); + } + + public static final void output(int b, String charset) + throws IOException { + output(new byte[] {(byte)b}, charset); + } + + public static final void input(int b, String charset) + throws IOException { + input(new byte[] {(byte)b}, charset); + } +} Index: java/org/apache/commons/httpclient/WireLogInputStream.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/WireLogInputStream.java,v retrieving revision 1.8 diff -u -r1.8 WireLogInputStream.java --- java/org/apache/commons/httpclient/WireLogInputStream.java 31 Jan 2003 00:33:36 -0000 1.8 +++ java/org/apache/commons/httpclient/WireLogInputStream.java 12 Feb 2003 14:15:47 -0000 @@ -67,27 +67,38 @@ import java.io.IOException; import java.io.InputStream; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.apache.commons.logging.LogFactory; /** * Logs all data read to the wire LOG. * * @author Ortwin Gl� * @author <a href="mailto:[EMAIL PROTECTED]">Mike Bowler</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Oleg Kalnichevski</a> * * @since 2.0 */ class WireLogInputStream extends FilterInputStream { + /** Log for any wire messages. */ private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); + /** Content encoding. */ + private String charset = "US-ASCII"; + + /** Original input stream. */ + private InputStream in; /** * Create an instance that wraps the specified input stream. * @param in The input stream. */ - public WireLogInputStream(InputStream in) { + public WireLogInputStream(InputStream in, String charset) { super(in); + if (charset != null) { + this.charset = charset; + } + this.in = in; } /** @@ -95,8 +106,10 @@ * @see java.io.InputStream#read(byte[], int, int) */ public int read(byte[] b, int off, int len) throws IOException { - int l = super.read(b, off, len); - WIRE_LOG.debug("<< " + new String(b, off, len)); + int l = this.in.read(b, off, len); + if (l > 0) { + Wire.input(b, off, len, null); + } return l; } @@ -105,9 +118,9 @@ * @see java.io.InputStream#read() */ public int read() throws IOException { - int l = super.read(); + int l = this.in.read(); if (l > 0) { - WIRE_LOG.debug("<< " + (char) l); + Wire.input(l, null); } return l; } @@ -117,8 +130,10 @@ * @see java.io.InputStream#read(byte[]) */ public int read(byte[] b) throws IOException { - int l = super.read(b); - WIRE_LOG.debug("<< " + HttpConstants.getString(b)); + int l = this.in.read(b); + if (l > 0) { + Wire.input(b, null); + } return l; } } Index: java/org/apache/commons/httpclient/WireLogOutputStream.java =================================================================== RCS file: java/org/apache/commons/httpclient/WireLogOutputStream.java diff -N java/org/apache/commons/httpclient/WireLogOutputStream.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ java/org/apache/commons/httpclient/WireLogOutputStream.java 12 Feb 2003 14:15:53 -0000 @@ -0,0 +1,131 @@ +/* + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 1999-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact [EMAIL PROTECTED] + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + * + * [Additional notices, if required by prior licensing conditions] + * + */ + +package org.apache.commons.httpclient; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.ByteArrayInputStream; +import java.io.Reader; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.io.UnsupportedEncodingException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Logs all data written to the wire LOG. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Oleg Kalnichevski</a> + * + * @since 2.0beta1 + */ + +class WireLogOutputStream extends FilterOutputStream { + + /** Log for any wire messages. */ + private static final Log WIRE_LOG = LogFactory.getLog("httpclient.wire"); + + /** Content encoding. */ + private String charset = "US-ASCII"; + + /** Original input stream. */ + private OutputStream out; + + /** + * Create an instance that wraps the specified output stream. + * @param out The output stream. + */ + public WireLogOutputStream(OutputStream out, String charset) { + super(out); + if (charset != null) { + this.charset = charset; + } + this.out = out; + } + + /** + * + * @see java.io.OutputStream#write(byte[], int, int) + */ + public void write(byte[] b, int off, int len) throws IOException { + this.out.write(b, off, len); + Wire.output(b, off, len, this.charset); + } + + /** + * + * @see java.io.OutputStream#write() + */ + public void write(int b) throws IOException { + this.out.write(b); + Wire.output(b, this.charset); + } + + /** + * + * @see java.io.OutputStream#write(byte[]) + */ + public void write(byte[] b) throws IOException { + this.out.write(b); + Wire.output(b, this.charset); + } +} Index: java/org/apache/commons/httpclient/util/HeaderParser.java =================================================================== RCS file: java/org/apache/commons/httpclient/util/HeaderParser.java diff -N java/org/apache/commons/httpclient/util/HeaderParser.java --- java/org/apache/commons/httpclient/util/HeaderParser.java 11 Feb 2003 05:04:10 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,88 +0,0 @@ -package org.apache.commons.httpclient.util; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; - -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpConnection; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A utility class for parsing http header values. - * - * @author Michael Becke - * - * @since 2.0beta1 - */ -public class HeaderParser { - - /** Log object for this class. */ - private static final Log LOG = LogFactory.getLog(HeaderParser.class); - - /** - * Constructor for HeaderParser. - */ - private HeaderParser() {} - - /** - * Parses headers from the given stream. Headers with the same name are not - * combined. - * - * @param is the stream to read headers from - * - * @return an array of headers in the order in which they were parsed - * - * @throws IOException if an IO error occurs while reading from the stream - * @throws HttpException if there is an error parsing a header value - */ - public static Header[] parseHeaders(InputStream is) throws IOException, HttpException { - LOG.trace("enter HeaderParser.parseHeaders(HttpConnection, HeaderGroup)"); - - ArrayList headers = new ArrayList(); - String name = null; - StringBuffer value = null; - for (; ;) { - String line = HttpConnection.readLine(is); - if ((line == null) || (line.length() < 1)) { - break; - } - - // Parse the header name and value - // Check for folded headers first - // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2 - // discussion on folded headers - if ((line.charAt(0) == ' ') || (line.charAt(0) == '\t')) { - // we have continuation folded header - // so append value - value.append(' '); - value.append(line.trim()); - } else { - // make sure we save the previous name,value pair if present - if (name != null) { - headers.add(new Header(name, value.toString())); - } - - // Otherwise we should have normal HTTP header line - // Parse the header name and value - int colon = line.indexOf(":"); - if (colon < 0) { - throw new HttpException("Unable to parse header: " + line); - } - name = line.substring(0, colon).trim(); - value = new StringBuffer(line.substring(colon + 1).trim()); - } - - } - - // make sure we save the last name,value pair if present - if (name != null) { - headers.add(new Header(name, value.toString())); - } - - return (Header[]) headers.toArray(new Header[headers.size()]); - } - -} Index: test/org/apache/commons/httpclient/SimpleHttpConnection.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/SimpleHttpConnection.java,v retrieving revision 1.9 diff -u -r1.9 SimpleHttpConnection.java --- test/org/apache/commons/httpclient/SimpleHttpConnection.java 11 Feb 2003 03:23:05 -0000 1.9 +++ test/org/apache/commons/httpclient/SimpleHttpConnection.java 12 Feb 2003 14:15:41 -0000 @@ -186,7 +186,7 @@ public String readLine() throws IOException, IllegalStateException { - String str = HttpConnection.readLine(inputStream); + String str = HttpParser.readLine(inputStream); log.debug("read: " + str); return str; }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]