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 Anver Sotnikov <AS...@intralinks.com> on 2001/05/15 17:28:28 UTC
Huge attachments
I thought this change can be done and it will improve performance and
memory utilization in SOAP.
I went through org.apache.soap.util.net.HTTPUtil code. and realized that
it reads whole response in memory just to read headers from InputStream.
May be it will be much better for performance to read headers directly
from InputStream and pass the rest of the Stream to TransportMessage?
If you need concrete implementation I can send my code which replaces
current.
public static TransportMessage post(URL url, TransportMessage request,
int timeout,
String httpProxyHost, int
httpProxyPort)
throws IllegalArgumentException, IOException, SOAPException {
// This part sends request to HTTP server ( skip reading to next bold
comment)
/* Open the connection */
OutputStream outStream = null;
InputStream inStream = null;
BufferedReader in = null;
int port;
Socket s;
try {
port = getPort(url);
s = buildSocket(url, port, httpProxyHost, httpProxyPort);
if (timeout > 0) // Should be redundant but not every JVM likes
this
s.setSoTimeout(timeout);
outStream = s.getOutputStream ();
inStream = s.getInputStream ();
}
catch (Exception e) {
e.printStackTrace(); // DEBUG - remove me
throw new IllegalArgumentException("Error opening socket: " +
e.getMessage ());
}
/* Construct the HTTP header. */
StringBuffer headerbuf = new StringBuffer();
headerbuf.append(Constants.HEADER_POST).append(' ')
.append(httpProxyHost == null ? url.getFile() : url.toString())
.append(" HTTP/").append(HTTP_VERSION).append("\r\n")
.append(Constants.HEADER_HOST).append(":
").append(url.getHost())
.append(':').append(port).append("\r\n")
.append(Constants.HEADER_CONTENT_TYPE).append(": ")
.append(request.getContentType()).append("\r\n")
.append(Constants.HEADER_CONTENT_LENGTH).append(": ")
.append(request.getContentLength()).append("\r\n");
for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();
) {
Object key = e.nextElement();
headerbuf.append(key).append(": ")
.append(request.getHeader((String)key)).append("\r\n");
}
headerbuf.append("\r\n");
/* Send the request. */
BufferedOutputStream bOutStream = new
BufferedOutputStream(outStream);
bOutStream.write(
headerbuf.toString().getBytes(Constants.HEADERVAL_DEFAULT_CHARSET));
request.writeTo(bOutStream);
//bOutStream.write('\r'); bOutStream.write('\n');
//bOutStream.write('\r'); bOutStream.write('\n');
bOutStream.flush();
outStream.flush();
// This part reads response from Socket
BufferedInputStream bInStream = new BufferedInputStream(inStream);
/* Read the response status line. */
int statusCode = 0;
String statusString = null;
StringBuffer linebuf = new StringBuffer();
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();
while (st.hasMoreTokens()) {
sb.append (st.nextToken());
if (st.hasMoreTokens()) {
sb.append(" ");
}
}
statusString = sb.toString();
}
catch (Exception e) {
throw new IllegalArgumentException(
"Error parsing HTTP status line \"" + line + "\": " + e);
}
// Here comes a Santa Claus :o)))
// Next part can be easily replaced by direct reading from
BufferedInputStream.
/* 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();
Hashtable respHeaders = new Hashtable();
int respContentLength = -1;
String respContentType = null;
StringBuffer namebuf = new StringBuffer();
StringBuffer valuebuf = new StringBuffer();
boolean parsingName = true;
int offset;
for (offset = 0; offset < bytes.length; offset++) {
if (bytes[offset] == '\n') {
if (namebuf.length() == 0)
break;
String name = namebuf.toString();
// Remove trailing ; to prevent ContextType from throwing
exception
if (valuebuf.charAt(valuebuf.length()-1) == ';') {
valuebuf.deleteCharAt(valuebuf.length()-1);
}
String value = valuebuf.toString();
if (name.equalsIgnoreCase(Constants.HEADER_CONTENT_LENGTH))
respContentLength = Integer.parseInt(value);
else if
(name.equalsIgnoreCase(Constants.HEADER_CONTENT_TYPE))
respContentType = value;
else
respHeaders.put(name, value);
namebuf = new StringBuffer();
valuebuf = new StringBuffer();
parsingName = true;
}
else if (bytes[offset] != '\r') {
if (parsingName) {
if (bytes[offset] == ':') {
parsingName = false;
if ((offset != bytes.length-1) &&
bytes[offset+1] == ' ')
offset++;
}
else
namebuf.append((char)bytes[offset]);
}
else
valuebuf.append((char)bytes[offset]);
}
}
// Headers can be processed without reading everything in memory
// Check out InternetHeaders in javax.mail.internet.
// After reading headers we can just pass same input stream to
Transport Message
// This we do one reading of Mesage in memory less :o)
InputStream is = ds.getInputStream();
is.skip(offset + 1);
if (respContentLength < 0)
respContentLength = ds.getSize() - offset - 1;
/* Construct the response object. */
SOAPContext ctx;
TransportMessage response;
try {
// Create response SOAPContext.
ctx = new SOAPContext();
// Read content.
response = new TransportMessage(is, respContentLength,
respContentType, ctx,
respHeaders);
// Extract envelope and SOAPContext
response.read();
} catch (MessagingException me) {
throw new IllegalArgumentException("Error parsing response: " +
me);
}
/* All done here! */
bOutStream.close();
outStream.close();
bInStream.close();
inStream.close();
s.close();
return response;
}