You are viewing a plain text version of this content. The canonical link for it is here.
Posted to soap-dev@xml.apache.org by sn...@apache.org on 2002/11/12 15:15:38 UTC
cvs commit: xml-soap/java/src/org/apache/soap/transport/http SOAPHTTPConnection.java
snichol 2002/11/12 06:15:38
Modified: java/src/org/apache/soap/util/net HTTPUtils.java
java/src/org/apache/soap/transport TransportMessage.java
java/src/org/apache/soap/transport/http
SOAPHTTPConnection.java
Log:
Reduce the number of times a response is copied in part or in whole.
Improve error reporting during response parsing.
Support services that shutdown the write half of the socket rather than
provide a Content-Length header.
Add getEnvelope to SOAPHTTPConnection. (The method will also be added
to SOAPTransport soon.)
Revision Changes Path
1.36 +104 -82 xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java
Index: HTTPUtils.java
===================================================================
RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- HTTPUtils.java 18 Oct 2002 20:30:54 -0000 1.35
+++ HTTPUtils.java 12 Nov 2002 14:15:38 -0000 1.36
@@ -57,21 +57,30 @@
package org.apache.soap.util.net;
-import java.io.*;
-import java.lang.reflect.*;
-import java.net.*;
-import java.util.*;
-
-import javax.mail.*;
-import javax.mail.internet.*;
-import javax.activation.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
-import org.apache.soap.*;
+import javax.mail.MessagingException;
+
+import org.apache.soap.Constants;
+import org.apache.soap.SOAPException;
import org.apache.soap.encoding.soapenc.Base64;
-import org.apache.soap.rpc.*;
-import org.apache.soap.transport.*;
+import org.apache.soap.rpc.SOAPContext;
+import org.apache.soap.transport.TransportMessage;
import org.apache.soap.util.MutableBoolean;
-import org.apache.soap.util.mime.*;
/**
* A bunch of utility stuff for doing HTTP things.
@@ -91,6 +100,7 @@
private static final String HTTP_VERSION = "1.0";
private static final int HTTP_DEFAULT_PORT = 80;
private static final int HTTPS_DEFAULT_PORT = 443;
+ private static final String ISO_8859_1 = "8859_1";
public static final int DEFAULT_OUTPUT_BUFFER_SIZE = 8 * 1024;
@@ -100,7 +110,7 @@
public static String encodeAuth(String userName, String password)
throws SOAPException {
try {
- return Base64.encode((userName + ":" + password).getBytes("8859_1"));
+ return Base64.encode((userName + ":" + password).getBytes(ISO_8859_1));
} catch (UnsupportedEncodingException e) {
throw new SOAPException (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
}
@@ -482,65 +492,93 @@
bOutStream.flush();
BufferedInputStream bInStream = new BufferedInputStream(inStream);
+ byte[] linebuf = new byte[1024];
+ int count = 0;
+ int b;
+
/* Read the response status line. */
+ String versionString = null;
int statusCode = 0;
String statusString = null;
- StringBuffer linebuf = new StringBuffer(128);
- int b = 0;
- while (b != '\n' && b != -1) {
- b = bInStream.read();
- if (b != '\n' && b != '\r' && b != -1)
- linebuf.append((char)b);
- }
- String line = linebuf.toString();
+
try {
- StringTokenizer st = new StringTokenizer(line);
- st.nextToken(); // ignore version part
- statusCode = Integer.parseInt (st.nextToken());
- StringBuffer sb = new StringBuffer(128);
- while (st.hasMoreTokens()) {
- sb.append (st.nextToken());
- if (st.hasMoreTokens()) {
- sb.append(" ");
+ int versionEnd = -1;
+ int codeStart = -1;
+ int codeEnd = -1;
+ int stringStart = -1;
+
+ for (count = 0, b = bInStream.read(); b != '\n' && b != -1; b = bInStream.read()) {
+ if (b != '\r') {
+ if (b == ' ') {
+ if (versionEnd == -1) {
+ versionEnd = count;
+ } else if (codeStart != -1 && codeEnd == -1) {
+ codeEnd = count;
+ }
+ } else {
+ if (versionEnd != -1 && codeStart == -1) {
+ codeStart = count;
+ } else if (codeEnd != -1 && stringStart == -1) {
+ stringStart = count;
+ }
+ }
+ if (count >= linebuf.length) {
+ byte[] newbuf = new byte[linebuf.length * 2];
+ System.arraycopy(linebuf, 0, newbuf, 0, linebuf.length);
+ linebuf = newbuf;
+ }
+ linebuf[count++] = (byte) b;
}
}
- statusString = sb.toString();
- }
- catch (Exception e) {
+ if (b == -1)
+ throw new Exception("Reached end of stream while reading HTTP response status");
+ versionString = new String(linebuf, 0, versionEnd, ISO_8859_1);
+ statusCode = Integer.parseInt(new String(linebuf, codeStart, codeEnd - codeStart, ISO_8859_1));
+ statusString = new String(linebuf, stringStart, count - stringStart, ISO_8859_1);
+ } catch (Exception e) {
throw new SOAPException(Constants.FAULT_CODE_CLIENT,
- "Error parsing HTTP status line \"" + line + "\": " + e, e);
+ "Error parsing HTTP status line \"" + new String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
}
- /* Read the entire response (following the status line)
- * into a byte array. */
- ByteArrayDataSource ds = new ByteArrayDataSource(bInStream,
- Constants.HEADERVAL_DEFAULT_CHARSET);
-
- /* Extract the headers, content type and content length. */
- byte[] bytes = ds.toByteArray();
+ /* Read the HTTP headers. */
Hashtable respHeaders = new Hashtable();
int respContentLength = -1;
String respContentType = null;
- int nameStart = 0;
- int nameEnd = 0;
- int valStart = 0;
- boolean parsingName = true;
- int offset;
-
- for (offset = 0; offset < bytes.length; offset++) {
- if (bytes[offset] == '\n') {
- if (nameStart >= nameEnd)
+ try {
+ // Read all headers
+ for (;;) {
+ // Read and parse one header
+ int nameEnd = -1;
+ int valStart = -1;
+ for (count = 0, b = bInStream.read(); b != '\n' && b != -1; b = bInStream.read()) {
+ if (b != '\r') {
+ if (nameEnd == -1 && b == ':') {
+ nameEnd = count;
+ } else if (nameEnd != -1 && valStart == -1 && b != ' ' & b != '\t') {
+ valStart = count;
+ }
+ if (count >= linebuf.length) {
+ byte[] newbuf = new byte[linebuf.length * 2];
+ System.arraycopy(linebuf, 0, newbuf, 0, linebuf.length);
+ linebuf = newbuf;
+ }
+ linebuf[count++] = (byte) b;
+ }
+ }
+ if (b == -1)
+ throw new Exception("Reached end of stream while reading HTTP response header");
+ if (count == 0) // Read the header/entity separator
break;
- String name = new String(bytes, nameStart, nameEnd-nameStart+1);
-
- // Remove trailing ; to prevent ContextType from throwing exception
- int valueLen = offset - valStart -1;
+ if (nameEnd == -1 || valStart == -1)
+ throw new Exception("Incorrectly formed HTTP response header");
- if (valueLen > 0 && bytes[offset-1] == ';')
- valueLen--;
+ String name = new String(linebuf, 0, nameEnd, ISO_8859_1);
+ // Remove trailing ; to prevent ContentType from throwing exception
+ if (linebuf[count - 1] == ';')
+ --count;
+ String value = new String(linebuf, valStart, count - valStart, ISO_8859_1);
- String value = new String(bytes, valStart, valueLen);
if (name.equalsIgnoreCase(Constants.HEADER_CONTENT_LENGTH))
respContentLength = Integer.parseInt(value);
else if (name.equalsIgnoreCase(Constants.HEADER_CONTENT_TYPE))
@@ -556,27 +594,11 @@
}
}
}
- parsingName = true;
- nameStart = offset+1;
}
- else if (bytes[offset] != '\r') {
- if (parsingName) {
- if (bytes[offset] == ':') {
- parsingName = false;
- nameEnd = offset - 1;
- if ((offset != bytes.length-1) &&
- bytes[offset+1] == ' ')
- offset++;
- valStart = offset+1;
- }
- }
- }
- } // End of for
-
- InputStream is = ds.getInputStream();
- is.skip(offset + 1);
- if (respContentLength < 0)
- respContentLength = ds.getSize() - offset - 1;
+ } catch (Exception e) {
+ throw new SOAPException(Constants.FAULT_CODE_CLIENT,
+ "Error parsing HTTP header line \"" + new String(linebuf, 0, count, ISO_8859_1) + "\": " + e, e);
+ }
/* Handle redirect here */
if (statusCode >= HttpURLConnection.HTTP_MULT_CHOICE &&
@@ -595,11 +617,6 @@
}
}
- /* If required, capture a copy of the response. */
- if (responseCopy != null) {
- responseCopy.append(line).append("\r\n").append(new String(bytes)); /* May get junk due to actual encoding */
- }
-
// TODO: process differently depending on statusCode and respContentLength
// (TransportMessage does not even get statusCode)
// e.g. statusCode 401 is Unauthorized
@@ -612,13 +629,18 @@
// Create response SOAPContext.
ctx = new SOAPContext();
// Read content.
- response = new TransportMessage(is, respContentLength,
+ response = new TransportMessage(bInStream, respContentLength,
respContentType, ctx, respHeaders);
// Extract envelope and SOAPContext
response.read();
} catch (MessagingException me) {
throw new SOAPException(Constants.FAULT_CODE_CLIENT,
"Error parsing response: " + me, me);
+ }
+
+ /* If required, capture a copy of the response. */
+ if (responseCopy != null) {
+ responseCopy.append(new String(response.getBytes())); /* May get junk due to actual encoding */
}
/* All done here! */
1.17 +51 -37 xml-soap/java/src/org/apache/soap/transport/TransportMessage.java
Index: TransportMessage.java
===================================================================
RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/transport/TransportMessage.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- TransportMessage.java 6 Sep 2002 17:02:58 -0000 1.16
+++ TransportMessage.java 12 Nov 2002 14:15:38 -0000 1.17
@@ -128,25 +128,36 @@
this.ctx = ctx;
this.contentType = contentType;
- if (contentLength < 0)
- throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
- "Content length must be specified.");
-
- bytes = new byte[contentLength];
- int offset = 0;
- int bytesRead = 0;
-
- // We're done reading when we get all the content OR when the stream
- // returns a -1.
- while ((offset < contentLength) && (bytesRead >= 0)) {
- bytesRead = is.read(bytes, offset, contentLength - offset);
- offset += bytesRead;
- }
- if (offset < contentLength)
- throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
- "Premature end of stream. Data is truncated. Read "
- + offset + " bytes successfully, expected "
- + contentLength);
+ bytes = new byte[contentLength >= 0 ? contentLength : 4096];
+ if (contentLength != 0) {
+ int offset = 0;
+ int bytesRead = 0;
+
+ // We're done reading when we get all the content OR when the stream
+ // returns a -1.
+ while ((contentLength < 0 || offset < contentLength) && (bytesRead >= 0)) {
+ bytesRead = is.read(bytes, offset, bytes.length - offset);
+ offset += bytesRead;
+ if (contentLength < 0 && offset >= bytes.length) {
+ byte[] newbuf = new byte[bytes.length * 2];
+ System.arraycopy(bytes, 0, newbuf, 0, bytes.length);
+ bytes = newbuf;
+ }
+ }
+
+ if (contentLength < 0) {
+ if (offset < bytes.length) {
+ byte[] newbuf = new byte[offset];
+ System.arraycopy(bytes, 0, newbuf, 0, offset);
+ bytes = newbuf;
+ }
+ } else if (offset < contentLength) {
+ throw new SOAPException (Constants.FAULT_CODE_PROTOCOL,
+ "Premature end of stream. Data is truncated. Read "
+ + offset + " bytes successfully, expected "
+ + contentLength);
+ }
+ }
}
/**
@@ -284,7 +295,7 @@
}
// If the root part is text, extract it as a String.
- // Note that we could use JAF's help to do this (see getEnvelope())
+ // Note that we could use JAF's help to do this (see save())
// but implementing it ourselves is safer and faster.
if (rootContentType.match("text/*")) {
String charset = rootContentType.getParameter("charset");
@@ -323,9 +334,11 @@
*/
public void save()
throws MessagingException, IOException {
- /* If an envelope was provided as a string, set it as the root part.
- * Otherwise, assume that the SOAPContext already has a root part.
+ /*
+ * If an envelope was provided as a string, set it as the root part.
* If there was already a root part, preserve its content-type.
+ * Otherwise, assume that the SOAPContext already has a root part,
+ * and try to use it as the envelope.
*/
String rootContentType = null;
if (ctx.isRootPartSet()) {
@@ -339,8 +352,18 @@
}
if (rootContentType == null)
rootContentType = Constants.HEADERVAL_CONTENT_TYPE_UTF8;
- if (getEnvelope() != null)
+ if (getEnvelope() != null) {
ctx.setRootPart(envelope, rootContentType);
+ } else {
+ MimeBodyPart rootPart = ctx.getRootPart();
+ if (rootPart != null) {
+ if (rootPart.isMimeType("text/*")) {
+ ByteArrayDataSource ds = new ByteArrayDataSource(
+ rootPart.getInputStream(), rootPart.getContentType());
+ envelope = ds.getText();
+ }
+ }
+ }
// Print the whole response to a byte array.
ByteArrayOutputStream payload =
@@ -428,20 +451,9 @@
}
/**
- * Get SOAP Envelope/root part as a String.
- * This method will extract the root part from the SOAPContext as a String
- * if there is no SOAP Envelope.
+ * Get SOAP Envelope as a String.
*/
- public String getEnvelope() throws MessagingException, IOException {
- if (envelope == null) {
- MimeBodyPart rootPart = ctx.getRootPart();
- if (rootPart != null)
- if (rootPart.isMimeType("text/*")) {
- ByteArrayDataSource ds = new ByteArrayDataSource(
- rootPart.getInputStream(), rootPart.getContentType());
- envelope = ds.getText();
- }
- }
+ public String getEnvelope() {
return envelope;
}
@@ -449,7 +461,7 @@
* Get SOAP Envelope/root part as a Reader. Returns null if the root part
* is not text.
*/
- public Reader getEnvelopeReader() throws MessagingException, IOException {
+ public Reader getEnvelopeReader() {
if (getEnvelope() == null)
return null;
else
@@ -530,6 +542,8 @@
/**
* Set the byte array of the response.
+ *
+ * @deprecated After 2.3.1
*/
public void readFully(InputStream is) throws IOException {
offset = 0;
1.29 +19 -16 xml-soap/java/src/org/apache/soap/transport/http/SOAPHTTPConnection.java
Index: SOAPHTTPConnection.java
===================================================================
RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/transport/http/SOAPHTTPConnection.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- SOAPHTTPConnection.java 16 Oct 2002 04:16:15 -0000 1.28
+++ SOAPHTTPConnection.java 12 Nov 2002 14:15:38 -0000 1.29
@@ -84,9 +84,7 @@
* @author Arek Wnukowski (apache@wnuko.demon.co.uk)
*/
public class SOAPHTTPConnection implements SOAPTransport {
- private BufferedReader responseReader;
- private Hashtable responseHeaders;
- private SOAPContext responseSOAPContext;
+ private TransportMessage response;
private String httpProxyHost;
private int httpProxyPort = 80;
@@ -369,7 +367,6 @@
"Basic " + HTTPUtils.encodeAuth(proxyUserName, proxyPassword));
}
- TransportMessage response;
try
{
TransportMessage msg = new TransportMessage(payload, ctx, headers);
@@ -385,18 +382,12 @@
throw new IOException ("Failed to encode mime multipart: " + uee);
}
- Reader envReader = response.getEnvelopeReader();
- if (envReader != null)
- responseReader = new BufferedReader(envReader);
- else
- responseReader = null;
- responseSOAPContext = response.getSOAPContext();
- responseHeaders = response.getHeaders();
if (maintainSession) {
// look for Set-Cookie2 and Set-Cookie headers and save them.
// Only update my state iff the header is there .. otherwise
// leave the current
// Note: Header is case-insensitive
+ Hashtable responseHeaders = response.getHeaders();
String hdr;
hdr = HTTPUtils.getHeaderValue (responseHeaders, "Set-Cookie2");
@@ -421,8 +412,6 @@
}
} catch (IllegalArgumentException e) {
throw new SOAPException (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
- } catch (MessagingException e) {
- throw new SOAPException (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
} catch (IOException e) {
throw new SOAPException (Constants.FAULT_CODE_CLIENT, e.getMessage(), e);
}
@@ -436,7 +425,21 @@
* possible.
*/
public BufferedReader receive () {
- return responseReader;
+ if (response != null) {
+ Reader envReader = response.getEnvelopeReader();
+ if (envReader != null)
+ return new BufferedReader(envReader);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the SOAP envelope.
+ *
+ * @return The SOAP envelope.
+ */
+ public String getEnvelope() {
+ return response != null ? response.getEnvelope() : null;
}
/**
@@ -445,7 +448,7 @@
* @return a hashtable containing all the headers
*/
public Hashtable getHeaders () {
- return responseHeaders;
+ return response != null ? response.getHeaders() : null;
}
/**
@@ -454,6 +457,6 @@
* @return response SOAPContext
*/
public SOAPContext getResponseSOAPContext () {
- return responseSOAPContext;
+ return response != null ? response.getSOAPContext() : null;
}
}
--
To unsubscribe, e-mail: <ma...@xml.apache.org>
For additional commands, e-mail: <ma...@xml.apache.org>