Hi, Attached is a patch (diff.txt) and the full changed files (changes-evert.zip) which includes: - Sachin's changes for SSL tunneling - Changes to enable an alternative SSLSocketFactory to be set, for getting around "untrusted server certificate chain" errors. - Changes to give access to the time when the request was made and the connection established, for monitoring purposes. - Lastly, I've been trying to implement support for authenticated proxies, BUT WITHOUT SUCCESS YET.
With the authenticated proxy, I don't know whether there is something wrong with the proxy I am using or something else. The code is supposed to handle authenticated proxies for both http and https requests. I am getting "no route to host" responses with https and "access to host forbidden on this server" responses with http. I might just no longer have the right permissions on the proxy server. If someone has access to an authenticated proxy and is willing to help test and debug this, I would greatly appreciate it. BTW, it might be a good idea to compare my files to the ones that Sachin sent yesterday, because I had to make changes to his changes in order to support authenticated proxies. Regards, Evert
Index: src/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.9
diff -c -r1.9 HttpConnection.java
*** src/java/org/apache/commons/httpclient/HttpConnection.java 12 Apr 2002 21:09:20 -0000 1.9
--- src/java/org/apache/commons/httpclient/HttpConnection.java 13 Jun 2002 14:22:10 -0000
***************
*** 66,72 ****
--- 66,74 ----
import java.net.SocketException;
import java.io.InputStream;
import java.io.OutputStream;
+ import java.io.UnsupportedEncodingException;
import java.io.IOException;
+ import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.apache.commons.httpclient.log.*;
***************
*** 115,121 ****
}
/**
! * Fully-specified constructor.
* @param proxyHost the host I should proxy via
* @param proxyPort the port I should proxy via
* @param host the host I should connect to. Parameter value must be non-null.
--- 117,123 ----
}
/**
! * Constructor.
* @param proxyHost the host I should proxy via
* @param proxyPort the port I should proxy via
* @param host the host I should connect to. Parameter value must be non-null.
***************
*** 123,128 ****
--- 125,145 ----
* @param secure when <tt>true</tt>, connect via HTTPS (SSL)
*/
public HttpConnection(String proxyHost, int proxyPort, String host, int port, boolean secure) {
+ this(proxyHost, proxyPort, host, port, secure, null, null);
+ }
+
+ /**
+ * Fully-specified constructor.
+ * @param proxyHost the host I should proxy via
+ * @param proxyPort the port I should proxy via
+ * @param host the host I should connect to. Parameter value must be non-null.
+ * @param port the port I should connect to
+ * @param secure when <tt>true</tt>, connect via HTTPS (SSL)
+ * @param state the HttpSharedState for establishing connections through authenticated proxies.
+ * @param factory the factory to be used for creating SSL sockets. Or, null for the default.
+ */
+ public HttpConnection(String proxyHost, int proxyPort, String host, int port, boolean secure,
+ HttpSharedState state, SSLSocketFactory factory) {
log.debug("HttpConnection.HttpConnection");
if (host == null) {
throw new NullPointerException("host parameter is null");
***************
*** 132,137 ****
--- 149,156 ----
_host = host;
_port = port;
_ssl = secure;
+ _state = state;
+ _sslSocketFactory = factory;
}
// ------------------------------------------ Attribute Setters and Getters
***************
*** 278,289 ****
assertNotOpen(); // ??? is this worth doing?
try {
if (null == _socket) {
- String host = (null == _proxyHost) ? _host : _proxyHost;
- int port = (null == _proxyHost) ? _port : _proxyPort;
if (_ssl) {
! _socket = SSLSocketFactory.getDefault().createSocket(host,port);
} else {
_socket = new Socket(host,port);
}
}
_socket.setSoTimeout(_so_timeout);
--- 297,322 ----
assertNotOpen(); // ??? is this worth doing?
try {
if (null == _socket) {
if (_ssl) {
! if (_sslSocketFactory == null)
! _sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
! if ((_proxyHost != null) && (_proxyPort > 0)) {
! // ssl using proxy - create a tunnellec connection
! doTunnelHandshake(false, null);
! Socket tunnel = _socket;
! _socket = _sslSocketFactory.createSocket(tunnel, _host, _port, true);
! } else {
! // using with no proxy
! _socket = _sslSocketFactory.createSocket(_host, _port);
! }
} else {
+ // non ssl connection
+ String host = (null == _proxyHost) ? _host : _proxyHost;
+ int port = (null == _proxyHost) ? _port : _proxyPort;
_socket = new Socket(host,port);
+ // Not creating a tunnel socket, but authenticating.
+ if ((_proxyHost != null) && (_proxyPort > 0))
+ doTunnelHandshake(false, null);
}
}
_socket.setSoTimeout(_so_timeout);
***************
*** 298,303 ****
--- 331,428 ----
}
}
+ private void doTunnelHandshake(boolean authenticate, String realm) throws IOException
+ {
+ String authorizationHeader = null;
+ if (authenticate && _state != null) {
+ Credentials credentials = _state.getCredentials(realm);
+ if ((credentials != null) &&
+ (credentials instanceof UsernamePasswordCredentials)) {
+ try {
+ authorizationHeader = Authenticator.basic((UsernamePasswordCredentials)credentials);
+ } catch (HttpException ex) {
+ log.debug("doTunnelHandshake(): Exception reading credentials: " + ex);
+ }
+ }
+ else if (realm != null) {
+ // Try it once with the default credentials that are stored
+ // with a null realm.
+ doTunnelHandshake(true, null);
+ return;
+ }
+ }
+ Socket tunnel = new Socket(_proxyHost, _proxyPort);
+ OutputStream out = tunnel.getOutputStream();
+ String msg = "CONNECT " + _host + ":" + _port + " HTTP/1.0\r\n" +
+ "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.userAgent + "\r\n" +
+ "Host: " + _host + ":" + _port + "\r\n" +
+ "Content-Length: 0\r\n" +
+ "Proxy-Connection: Keep-Alive\r\n" +
+ "Pragma: no-cache\r\n";
+ if (authorizationHeader != null)
+ msg += "Proxy-Authorization: " + authorizationHeader + "\r\n";
+ msg += "\r\n";
+
+ wireLog.info(">>\r\n" + msg);
+
+ byte b[];
+ try {
+ b = msg.getBytes("ASCII7");
+ } catch (UnsupportedEncodingException ignored) {
+ b = msg.getBytes();
+ }
+ out.write(b);
+ out.flush();
+
+ _input = tunnel.getInputStream();
+ boolean error = false;
+
+ _open = true;
+ StringBuffer replyBuffer = new StringBuffer();
+ String proxyAuthenticate = null;
+ while (true) {
+ String line = readLine();
+ if (line == null || line.length() < 0)
+ break;
+ replyBuffer.append(line + "\r\n");
+ int colonPosition = line.indexOf(":");
+ if (colonPosition > -1) {
+ String key = line.substring(0, colonPosition);
+ String value = line.substring(colonPosition);
+ if (key.trim().equalsIgnoreCase("Proxy-Authenticate"))
+ proxyAuthenticate = value;
+ }
+ }
+ String replyStr = replyBuffer.toString();
+ _open = false;
+
+ realm = null;
+ if (proxyAuthenticate != null) {
+ int start = proxyAuthenticate.indexOf("\"") + 1;
+ int end = proxyAuthenticate.lastIndexOf("\"");
+ if (start > -1 && end > -1 && start != end)
+ realm = proxyAuthenticate.substring(start, end);
+ }
+ if (realm != null)
+ log.debug("doTunnelHandshake(): Authentication required for realm '" + realm + "'");
+
+ if (realm != null) {
+ doTunnelHandshake(true, realm);
+ return;
+ }
+
+ log.debug("doTunnelHandshake(): Reply: " + replyStr);
+
+ /* We asked for HTTP/1.0, so we should get that back */
+ if (!replyStr.startsWith("HTTP/1.0 200")) {
+ throw new IOException("Unable to tunnel through "
+ + _proxyHost + ":" + _proxyPort
+ + ". Proxy returns \"" + replyStr + "\"");
+ }
+
+ /* tunneling Handshake was successful! */
+ }
+
/**
* Return a {@link RequestOutputStream}
* suitable for writing (possibly chunked)
***************
*** 593,597 ****
private static final byte[] CRLF = "\r\n".getBytes();
/** SO_TIMEOUT value */
private int _so_timeout = 0;
!
}
--- 718,725 ----
private static final byte[] CRLF = "\r\n".getBytes();
/** SO_TIMEOUT value */
private int _so_timeout = 0;
! /** The factory to be used for creating SSL sockets. **/
! private SSLSocketFactory _sslSocketFactory = null;
! /** The state to be used for establishing connections through authenticated proxies. **/
! private HttpSharedState _state = null;
}
Index: src/java/org/apache/commons/httpclient/HttpConnectionManager.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnectionManager.java,v
retrieving revision 1.5
diff -c -r1.5 HttpConnectionManager.java
*** src/java/org/apache/commons/httpclient/HttpConnectionManager.java 15 Apr 2002 18:35:29 -0000 1.5
--- src/java/org/apache/commons/httpclient/HttpConnectionManager.java 13 Jun 2002 14:22:15 -0000
***************
*** 67,72 ****
--- 67,73 ----
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
+ import javax.net.ssl.SSLSocketFactory;
import org.apache.commons.httpclient.log.*;
***************
*** 87,92 ****
--- 88,95 ----
private int maxConnections = 2; // Per RFC 2616 sec 8.1.4
private String proxyHost = null;
private int proxyPort = -1;
+ private HttpSharedState state = null;
+ private SSLSocketFactory factory = null;
/**
* No-args constructor
***************
*** 96,101 ****
--- 99,113 ----
}
/**
+ * This constructor is necessary for making connections through authenticated proxies.
+ * @param state for making connections through authenticated proxies, or null.
+ */
+ public HttpConnectionManager(HttpSharedState state)
+ {
+ this.state = state;
+ }
+
+ /**
* Set the proxy host to use for all connections.
*
* @param proxyHost - the proxy host name
***************
*** 157,162 ****
--- 169,183 ----
}
/**
+ * Allows you to specify a new factory to be used as the default
+ * for creating SSL sockets. Setting the factory to null will
+ * reset it to using SSLSocketFactory.getDefault().
+ */
+ public void setSSLSocketFactory(SSLSocketFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
* Get an HttpConnection for a given URL. The URL must be fully
* specified (i.e. contain a protocol and a host (and optional port number).
* If the maximum number of connections for the host has been reached, this
***************
*** 249,255 ****
if(log.isDebugEnabled()){
log.debug("HttpConnectionManager.getConnection: creating connection for " + host + ":" + port + " via " + proxyHost + ":" + proxyPort);
}
! conn = new HttpConnection(proxyHost, proxyPort, host, port, isSecure);
numConnections = new Integer(numConnections.intValue()+1);
mapNumConnections.put(key, numConnections);
}else{
--- 270,276 ----
if(log.isDebugEnabled()){
log.debug("HttpConnectionManager.getConnection: creating connection for " + host + ":" + port + " via " + proxyHost + ":" + proxyPort);
}
! conn = new HttpConnection(proxyHost, proxyPort, host, port, isSecure, state, factory);
numConnections = new Integer(numConnections.intValue()+1);
mapNumConnections.put(key, numConnections);
}else{
Index: src/java/org/apache/commons/httpclient/HttpMethod.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethod.java,v
retrieving revision 1.12
diff -c -r1.12 HttpMethod.java
*** src/java/org/apache/commons/httpclient/HttpMethod.java 22 Feb 2002 19:15:54 -0000 1.12
--- src/java/org/apache/commons/httpclient/HttpMethod.java 13 Jun 2002 14:22:16 -0000
***************
*** 262,267 ****
--- 262,290 ----
public InputStream getResponseBodyAsStream() throws IOException;
/**
+ * Returns the time in milliseconds when a connection was
+ * available and open.
+ * If an error occurred before this event, then it will return <tt>-1</tt>.
+ */
+ public long getWhenConnectedMillis();
+
+ /**
+ * Returns the time in milliseconds when the headers of the request
+ * were sent, not the body of the request. It might first wait for
+ * a 100 response before sending the body of the request.
+ * If an error occurred before this event, then it will return <tt>-1</tt>.
+ */
+ public long getWhenRequestedMillis();
+
+ /**
+ * Returns the time in milliseconds when the first response was received
+ * from the server, regardless of whether it was a success, failure
+ * or continue response.
+ * If an error occurred before this event, then it will return <tt>-1</tt>.
+ */
+ public long getWhenRespondedMillis();
+
+ /**
* Return <tt>true</tt> if I have been {@link #execute executed}
* but not recycled.
*/
Index: src/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.28
diff -c -r1.28 HttpMethodBase.java
*** src/java/org/apache/commons/httpclient/HttpMethodBase.java 16 Apr 2002 14:30:42 -0000 1.28
--- src/java/org/apache/commons/httpclient/HttpMethodBase.java 13 Jun 2002 14:22:23 -0000
***************
*** 405,410 ****
--- 405,439 ----
}
/**
+ * Returns the time in milliseconds when a connection was
+ * available and open.
+ * If an error occurred before this event, then it will return <tt>-1</tt>.
+ */
+ public long getWhenConnectedMillis() {
+ return whenConnected;
+ }
+
+ /**
+ * Returns the time in milliseconds when the headers of the request
+ * were sent, not the body of the request. It might first wait for
+ * a 100 response before sending the body of the request.
+ * If an error occurred before this event, then it will return <tt>-1</tt>.
+ */
+ public long getWhenRequestedMillis() {
+ return whenRequested;
+ }
+
+ /**
+ * Returns the time in milliseconds when the first response was received
+ * from the server, regardless of whether it was a success, failure
+ * or continue response.
+ * If an error occurred before this event, then it will return <tt>-1</tt>.
+ */
+ public long getWhenRespondedMillis() {
+ return whenResponded;
+ }
+
+ /**
* Return <tt>true</tt> if I have been {@link #execute executed}
* but not recycled.
*/
***************
*** 466,476 ****
--- 495,514 ----
connection.open();
}
+ if (whenConnected == -1)
+ whenConnected = System.currentTimeMillis();
+
writeRequest(state,connection);
used = true;
+ if (whenRequested == -1)
+ whenRequested = System.currentTimeMillis();
+
// need to close output?, but when?
readResponse(state,connection);
+
+ if (whenResponded == -1)
+ whenResponded = System.currentTimeMillis();
}catch(HttpRecoverableException e){
if(retryCount >= maxRetries){
throw new HttpException(e.toString());
***************
*** 539,657 ****
continue;
}
}
- } else if (HttpStatus.SC_MOVED_TEMPORARILY == statusCode ||
- HttpStatus.SC_MOVED_PERMANENTLY == statusCode ||
- HttpStatus.SC_TEMPORARY_REDIRECT == statusCode) {
- if (getFollowRedirects()) {
- //
- // Note that we cannot current support
- // redirects that change the HttpConnection
- // parameters (host, port, protocol)
- // because we don't yet have a good way to
- // get the new connection.
- //
- // For the time being, we just return
- // the 302 response, and allow the user
- // agent to resubmit if desired.
- //
- Header location = getResponseHeader("location");
- if (location != null) {
- URL url = null;
- try {
- if (location.getValue().startsWith("/")) {
- if (log.isDebugEnabled()) {
- log.debug("Following relative Location header \"" + location + "\".");
- }
- String protocol = connection.isSecure() ? "https" : "http";
- int port = connection.getPort();
- if (-1 == port) {
- port = connection.isSecure() ? 443 : 80;
- }
- url = new URL(protocol,connection.getHost(),port,location.getValue());
- } else if(!isStrictMode() && location.getValue().indexOf("://") < 0) {
- /*
- * Location doesn't start with / but it doesn't contain a protocol.
- * Per RFC 2616, that's an error. In non-strict mode we'll try
- * to build a URL relative to the current path.
- */
- String protocol = connection.isSecure() ? "https" : "http";
- int port = connection.getPort();
- if(-1 == port) {
- port = connection.isSecure() ? 443 : 80;
- }
- URL currentUrl = new URL(protocol,connection.getHost(),port,getPath());
- url = new URL(currentUrl, location.getValue());
- } else {
- url = new URL(location.getValue());
- }
- } catch(MalformedURLException e) {
- log.error("Exception while parsing location header \"" + location + "\"",e);
- throw new HttpException(e.toString());
- }
- if ("http".equalsIgnoreCase(url.getProtocol())) {
- if (connection.isSecure()) {
- log.info("Server is attempting to redirect an HTTPS request to an HTTP one.");
- throw new HttpException("Server is attempting to redirect an HTTPS request to an HTTP one.");
- }
- } else if ("https".equalsIgnoreCase(url.getProtocol())) {
- if (!connection.isSecure()) {
- log.info("Server is attempting to convert an HTTP request to an HTTP one, which is currently not supported. Returning " + statusCode + ".");
- break;
- }
- }
- if (!connection.getHost().equalsIgnoreCase(url.getHost())) {
- log.info("Server is attempting to redirect a different host, which is currently not supported. Returning " + statusCode + ".");
- break;
- }
- if (url.getPort() == -1) {
- if (connection.isSecure()) {
- if (connection.getPort() != 443) {
- log.info("Server is attempting to redirect a different port, which is currently not supported. Returning " + statusCode + ".");
- break;
- }
- } else {
- if (connection.getPort() != 80) {
- log.info("Server is attempting to redirect a different port, which is currently not supported. Returning " + statusCode + ".");
- break;
- }
- }
- } else if (connection.getPort() != url.getPort()) {
- log.info("Server is attempting to redirect a different port, which is currently not supported. Returning " + statusCode + ".");
- break;
- }
- String absolutePath = URIUtil.getPath(url.toString());
- String qs = URIUtil.getQueryString(url.toString());
-
- // if we haven't already, let's try it again with the new path
- if (visited.contains(connection.getHost() + ":" + connection.getPort() + "|" + HttpMethodBase.generateRequestLine(connection, getName(),absolutePath,qs,(http11 ? "HTTP/1.1" : "HTTP/1.0")))) {
- throw new HttpException("Redirect going into a loop, visited \"" + absolutePath + "\" already.");
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Changing path from \"" + getPath() + "\" to \"" + absolutePath + "\" in response to " + statusCode + " response.");
- log.debug("Changing query string from \"" + getQueryString() + "\" to \"" + qs + "\" in response to " + statusCode + " response.");
- }
- setPath(URIUtil.decode(absolutePath));
- setQueryString(qs);
- continue;
- }
- } else {
- // got a redirect response, but no location header
- if (log.isInfoEnabled()) {
- log.info("HttpMethodBase.execute(): Received " + statusCode + " response, but no \"Location\" header. Returning " + statusCode + ".");
- }
- break;
- }
- } else {
- // got a redirect response,
- // but followRedirects is false
- log.info("HttpMethodBase.execute(): Received " + statusCode + " response, but followRedirects is false. Returning " + statusCode + ".");
- break;
- }
- } else {
- // neither an UNAUTHORIZED nor a redirect response
- // so exit
- break;
}
}
return statusCode;
--- 577,587 ----
continue;
}
}
}
+ // Moved the handling of redirects to HttpMultiClient. Replaced all the
+ // code to build a URL relative to the original URL with:
+ // URL newUrl = new URL( URL context, String newUrlStr ) --Evert
+ break;
}
return statusCode;
***************
*** 789,795 ****
protected void addHostRequestHeader(HttpState state, HttpConnection conn) throws IOException, HttpException {
// add host (should do this conditionally?, i.e., don't send to http/1.0?)
if (!requestHeaders.containsKey("host")) {
! setRequestHeader("Host",conn.getHost());
}
}
--- 719,725 ----
protected void addHostRequestHeader(HttpState state, HttpConnection conn) throws IOException, HttpException {
// add host (should do this conditionally?, i.e., don't send to http/1.0?)
if (!requestHeaders.containsKey("host")) {
! setRequestHeader("Host", conn.getHost() + ":" + conn.getPort());
}
}
***************
*** 1239,1244 ****
--- 1169,1177 ----
http11 = true;
bodySent = false;
responseBody = null;
+ whenConnected = -1;
+ whenRequested = -1;
+ whenResponded = -1;
}
// ---------------------------------------------- Protected Utility Methods
***************
*** 1299,1312 ****
return (name + " " + buf.toString() + " " + protocol + "\r\n");
} else {
if (connection.isSecure()) {
! return (name +
! " https://" +
! connection.getHost() +
! ((443 == connection.getPort() || -1 == connection.getPort()) ? "" : (":" + connection.getPort()) ) +
! buf.toString() +
! " " +
! protocol +
! "\r\n");
} else {
return (name +
" http://" +
--- 1232,1246 ----
return (name + " " + buf.toString() + " " + protocol + "\r\n");
} else {
if (connection.isSecure()) {
! // return (name +
! // " https://" +
! // connection.getHost() +
! // ((443 == connection.getPort() || -1 == connection.getPort()) ? "" : (":" + connection.getPort()) ) +
! // buf.toString() +
! // " " +
! // protocol +
! // "\r\n");
! return (name + " " + buf.toString() + " " + protocol + "\r\n");
} else {
return (name +
" http://" +
***************
*** 1367,1372 ****
--- 1301,1312 ----
private int maxRetries = 3;
/** True if we're in strict mode. */
private boolean strictMode = true;
+ /** The moment when an open connection is available. **/
+ private long whenConnected = -1;
+ /** The moment when the request headers have been sent, not the request body. **/
+ private long whenRequested = -1;
+ /** The moment of the first response received back from the server. **/
+ private long whenResponded = -1;
// -------------------------------------------------------------- Constants
Index: src/java/org/apache/commons/httpclient/HttpMultiClient.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMultiClient.java,v
retrieving revision 1.4
diff -c -r1.4 HttpMultiClient.java
*** src/java/org/apache/commons/httpclient/HttpMultiClient.java 9 May 2002 19:30:22 -0000 1.4
--- src/java/org/apache/commons/httpclient/HttpMultiClient.java 13 Jun 2002 14:22:24 -0000
***************
*** 63,70 ****
--- 63,74 ----
package org.apache.commons.httpclient;
import java.io.IOException;
+ import java.net.MalformedURLException;
+ import java.net.URL;
+ import javax.net.ssl.SSLSocketFactory;
import org.apache.commons.httpclient.log.*;
+ import org.apache.commons.httpclient.methods.PostMethod;
/**
*
***************
*** 85,91 ****
// ----------------------------------------------------- Instance Variables
private HttpSharedState state = null;
! private HttpConnectionManager mgr = new HttpConnectionManager();
private boolean strictMode = true;
private int timeoutConnection = 0;
private int timeoutRequest = 0;
--- 89,95 ----
// ----------------------------------------------------- Instance Variables
private HttpSharedState state = null;
! private HttpConnectionManager mgr = null;
private boolean strictMode = true;
private int timeoutConnection = 0;
private int timeoutRequest = 0;
***************
*** 100,105 ****
--- 104,110 ----
*/
public HttpMultiClient()
{
+ mgr = new HttpConnectionManager(getState());
}
/**
***************
*** 255,260 ****
--- 260,285 ----
}
/**
+ * Set the maximum number of connections allowed for a given host:port.
+ * Per RFC 2616 section 8.1.4, this value defaults to 2.
+ *
+ * @param maxConnections - number of connections allowed for each host:port
+ */
+ public void setMaxConnectionsPerHost(int maxConnections)
+ {
+ mgr.setMaxConnectionsPerHost(maxConnections);
+ }
+
+ /**
+ * Allows you to specify a new factory to be used as the default
+ * for creating SSL sockets. Setting the factory to null will
+ * reset it to using SSLSocketFactory.getDefault().
+ */
+ public void setSSLSocketFactory(SSLSocketFactory factory) {
+ mgr.setSSLSocketFactory(factory);
+ }
+
+ /**
*
* Execute the given {@link HttpUrlMethod} using my current
* {@link HttpConnection connection} and {@link HttpState}.
***************
*** 268,279 ****
--- 293,313 ----
*/
public int executeMethod(HttpUrlMethod method) throws IOException, HttpException
{
+ return executeMethod(method, 0);
+ }
+ protected int executeMethod(HttpUrlMethod method, int numberOfRedirects)
+ throws IOException, HttpException
+ {
if (null == method)
{
throw new NullPointerException("method parameter");
}
+ if(numberOfRedirects > 10)
+ {
+ throw new HttpException("Redirected more than 10 times.");
+ }
HttpConnection connection = mgr.getConnection(method.getUrl(), timeoutConnection);
connection.setSoTimeout(timeoutRequest);
***************
*** 298,305 ****
mgr.releaseConnection(connection);
}
! if (status == 301 || status == 302 ||
! status == 303 || status == 307)
{
Header header = method.getResponseHeader("Location");
String url = header.getValue();
--- 332,340 ----
mgr.releaseConnection(connection);
}
! if (method.getFollowRedirects() &&
! (status == 301 || status == 302 ||
! status == 303 || status == 307))
{
Header header = method.getResponseHeader("Location");
String url = header.getValue();
***************
*** 308,320 ****
log.error("HttpMultiClient.executeMethod: Received redirect without Location header.");
throw new HttpException("Received redirect without Location header.");
}
!
method.recycle();
! method.setUrl(url);
! return executeMethod(method);
}
return status;
}
-
}
--- 343,376 ----
log.error("HttpMultiClient.executeMethod: Received redirect without Location header.");
throw new HttpException("Received redirect without Location header.");
}
!
! log.debug("HttpMultiClient.executeMethod: Following redirect to: " + url);
!
! String oldUrlStr = method.getUrl();
! String oldRequestBody = null;
! if (method instanceof PostMethod)
! {
! oldRequestBody = ((PostMethod)method).getRequestBody();
! }
! URL oldUrl = null;
! try
! {
! oldUrl = new URL(oldUrlStr);
! } catch (MalformedURLException e)
! {
! // This means the original url was also malformed. But, if that
! // was the case we should never have gotten this far.
! log.debug("HttpMultiClient.executemethod: The original url was malformed: " + e);
! throw e;
! }
! URL newUrl = new java.net.URL(oldUrl, url);
method.recycle();
! method.setUrl(newUrl.toString());
! if (method instanceof PostMethod)
! ((PostMethod)method).setRequestBody(oldRequestBody);
! return executeMethod(method, numberOfRedirects++);
}
return status;
}
}
Index: src/java/org/apache/commons/httpclient/methods/PostMethod.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/methods/PostMethod.java,v
retrieving revision 1.9
diff -c -r1.9 PostMethod.java
*** src/java/org/apache/commons/httpclient/methods/PostMethod.java 24 Apr 2002 14:44:50 -0000 1.9
--- src/java/org/apache/commons/httpclient/methods/PostMethod.java 13 Jun 2002 14:22:26 -0000
***************
*** 236,241 ****
--- 236,248 ----
}
}
+ /**
+ * Returns the post data.
+ */
+ public String getRequestBody() {
+ return requestBody;
+ }
+
/**
* @throws IllegalStateException if request params have been added
*/
changes_evert.zip
Description: Zip archive
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
