Hello, I created a patch, which allows HTTPUtils follow redirects, with simple check that this occurs no more than 5 times. Since it uses recurrent call, I had to add additional parameter to the function post (interfaces do not changed, old function exists). Also I removed StringBuffer creation, while parsing headers, creating header/value directly from byte[].
I did small testing with IIS & one java app server. Please review Pavel
Index: HTTPUtils.java =================================================================== RCS file: /home/cvspublic/xml-soap/java/src/org/apache/soap/util/net/HTTPUtils.java,v retrieving revision 1.32 diff -u -r1.32 HTTPUtils.java --- HTTPUtils.java 4 Oct 2002 19:50:19 -0000 1.32 +++ HTTPUtils.java 14 Oct 2002 13:25:54 -0000 @@ -203,7 +203,7 @@ msg.append(": ").append(e.toString()); throw new SOAPException(Constants.FAULT_CODE_CLIENT, msg.toString(), e); } - + if (s != null && tcpNoDelay != null) s.setTcpNoDelay(tcpNoDelay.booleanValue()); @@ -317,9 +317,9 @@ int outputBufferSize, Boolean tcpNoDelay) throws IOException, SOAPException { - + return post(url, request, timeout, httpProxyHost, httpProxyPort, - outputBufferSize, tcpNoDelay, null, null); + outputBufferSize, tcpNoDelay, null, null, 0); } /** @@ -354,8 +354,47 @@ Boolean tcpNoDelay, StringBuffer requestCopy, StringBuffer responseCopy) - throws IOException, SOAPException { + throws IOException, SOAPException { + return post(url, request, timeout, httpProxyHost, httpProxyPort, + outputBufferSize, tcpNoDelay, null, null, 0); + } + /** + * POST something to the given URL. The headers are put in as + * HTTP headers, the content length is calculated and the content + * byte array is sent as the POST content. + * + * This method allows the caller to provide buffers in which to capture + * request and response data. This is useful when debugging SSL, as + * wire dumps are not very useful in that case. However, it is important + * to note that the bytes send or received are optimistically handled + * with the default encoding, much as TcpTunnelGui treats everything + * as iso-8859-1. + * + * @param url the url to post to + * @param request the message + * @param timeout the amount of time, in ms, to block on reading data + * @param httpProxyHost the HTTP proxy host or null if no proxy + * @param httpProxyPort the HTTP proxy port, if the proxy host is not null + * @param outputBufferSize the size of the output buffer on the HTTP stream + * @param tcpNoDelay the tcpNoDelay setting for the socket + * @param requestCopy the buffer for capturing copy of the request or null + * if capture is not required. + * @param responseCopy the buffer for capturing copy of the response or null + * if capture is not required. + * @param numRedirects the current number of redirects - to prevent cycles + * @return the response message + */ + private static TransportMessage post(URL url, TransportMessage request, + int timeout, + String httpProxyHost, int httpProxyPort, + int outputBufferSize, + Boolean tcpNoDelay, + StringBuffer requestCopy, + StringBuffer responseCopy, + int numRedirects) + + throws IOException, SOAPException { OutputStream outStream = null; InputStream inStream = null; BufferedReader in = null; @@ -425,17 +464,14 @@ bOutStream.write( headerbuf.toString().getBytes(Constants.HEADERVAL_DEFAULT_CHARSET)); request.writeTo(bOutStream); - + /* If required, capture a copy of the request. */ if (requestCopy != null) { requestCopy.append(headerbuf) .append(new String(request.getBytes())); /* Note: could get junk depending on actual encoding */ } - - //bOutStream.write('\r'); bOutStream.write('\n'); - //bOutStream.write('\r'); bOutStream.write('\n'); + bOutStream.flush(); - outStream.flush(); BufferedInputStream bInStream = new BufferedInputStream(inStream); /* Read the response status line. */ @@ -477,24 +513,26 @@ Hashtable respHeaders = new Hashtable(); int respContentLength = -1; String respContentType = null; - StringBuffer namebuf = new StringBuffer(64); - StringBuffer valuebuf = new StringBuffer(64); + + 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 (namebuf.length() == 0) + if (nameStart >= nameEnd) break; - String name = namebuf.toString(); + String name = new String(bytes, nameStart, nameEnd-nameStart+1); // Remove trailing ; to prevent ContextType from throwing exception - int valueLen = valuebuf.length(); + int valueLen = offset - valStart -1; - if (valueLen > 0 && valuebuf.charAt(valueLen - 1) == ';') { - valuebuf.deleteCharAt(valueLen - 1); - } + if (valueLen > 0 && bytes[offset-1] == ';') + valueLen--; - String value = valuebuf.toString(); + 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)) @@ -510,35 +548,50 @@ } } } - namebuf = new StringBuffer(64); - valuebuf = new StringBuffer(64); 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; } - else - namebuf.append((char)bytes[offset]); } - else - valuebuf.append((char)bytes[offset]); } - } + } // End of for + InputStream is = ds.getInputStream(); is.skip(offset + 1); if (respContentLength < 0) respContentLength = ds.getSize() - offset - 1; + /* Handle redirect here */ + if (statusCode >= HttpURLConnection.HTTP_MULT_CHOICE && + statusCode <= HttpURLConnection.HTTP_USE_PROXY && + statusCode != HttpURLConnection.HTTP_NOT_MODIFIED && (++numRedirects)<5 ) { + String newLocation = getHeaderValue(respHeaders, "Location"); + if (newLocation != null) { + URL newURL = new URL(url, newLocation); + /* Close current streams */ + bOutStream.close(); + bInStream.close(); + s.close(); + // Post to new location + return post(newURL, request, timeout, httpProxyHost, httpProxyPort, + outputBufferSize, tcpNoDelay, null, responseCopy, numRedirects); + } + } + /* 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 @@ -562,9 +615,7 @@ /* All done here! */ bOutStream.close(); - outStream.close(); bInStream.close(); - inStream.close(); s.close(); return response; }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>