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]>

Reply via email to