Adrian,

I'm looking into to this and I agree it is quite strange. The part I don't understand is why the second attempt to write to the socket fails. The socket is not being closed on the HttpClient side until after the failure occurs. Any thoughts on how the connection is being closed?

Mike

On Thursday, June 19, 2003, at 08:50 PM, Adrian Sutton wrote:

Howdy all,
I'm having some trouble pinpointing the exact cause of an exception I'm getting from HttpClient, it seems to be related to connection management with MultiThreadedConnectionManager so I thought I'd draw on the expertise here. :)


Essentially, we have an invalid HTTP server (Stellent CMS actually and we will file a bug with them), which is returning headers like:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic "Secure Realm"
Connection: keep-alive

Which is clearly missing the Content-Length header. Now, previously HttpClient handled this perfectly by reading until the end of the connection (ie: treating it like it was a Connection: close), however for some reason a socket exception is being thrown and the invalid connection is added back into the connection pool and then every connection to the server after that thows an exception.

I haven't been able to work out a good way to create a test case for this yet, but I can provide a simple set of steps to reproduce:

1. Get something like netcat which will let you "pretend" to be a HTTP server (ie: it will listen on a port and send back whatever you type)

2. Start it listening on port 8080 (for netcat use: nc -l -p 8080)

3. Compile the program below and run it.

4. Enter the following into you netcat window (followed by a blank line to indicate the end of the headers):

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic "realm"
Connection: keep-alive

You'll see HttpClient throws an exception (listed below the code). Note that netcat did not close the connection, HttpClient did. Also, note that it doesn't make any difference if you set netcat up to immediately start listening for another connection after the connection is closed (ie: netcat -l -p 8080 && netcat -l -p 8080).

It looks like HttpClient is closing the connection but not telling itself that the connection is closed so it then tries to reuse the connection and fails. The same thing happens if you perform two GET requests and the server returns 200 OK with connection: keep-alive but no content length to the first request.

Any help tracking down this would be greatly appreciated, even if it's just a hint as to where to start making changes. :)

CODE: -------------------------
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.contrib.ssl.*;
import org.apache.commons.httpclient.protocol.*;


public class Test {


public static void main(String[] args) throws Exception {
//String url = "https://basil/stellent/groups/secure/documents/adsales/> testimage.jpg";
String url = "http://localhost:8080/test.gif";;
HttpClient client = new HttpClient(new MultiThreadedHttpConnectionManager());
client.getState().setCredentials(null, null, new UsernamePasswordCredentials("sysadmin", "idc"));
GetMethod get = new GetMethod(url);
int result = client.executeMethod(get);
System.err.println("Result: " + result);
System.err.println(get.getResponseBody());
}
}
----------------------------------
Resulting exception:
Exception in thread "main" java.net.SocketException: Socket closed
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:99)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at org.apache.commons.httpclient.HttpConnection$WrappedOutputStream.write( HttpConnection.java:1347)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:69)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:127)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(H ttpConnection.java:782)
at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpCo nnectionAdapter.flushRequestOutputStream(MultiThreadedHttpConnectionMan ager.java:1046)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBas e.java:2174)
at org.apache.commons.httpclient.HttpMethodBase.processRequest(HttpMethodB ase.java:2529)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.jav a:1066)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java: 638)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java: 500)
at Test.main(Test.java:15)



The wire trace is:


[DEBUG] HttpClient - -Java version: 1.4.1_01
[DEBUG] HttpClient - -Java vendor: Apple Computer, Inc.
[DEBUG] HttpClient - -Java class path: commons-httpclient-2.0-beta1.jar:commons-logging-1.0.2.jar:.
[DEBUG] HttpClient - -Operating system name: Mac OS X
[DEBUG] HttpClient - -Operating system architecture: ppc
[DEBUG] HttpClient - -Operating system version: 10.2.6
[DEBUG] HttpClient - -SUN 1.2: SUN (DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; PKIX CertPathBuilder; LDAP, Collection CertStores)
[DEBUG] HttpClient - -SunJSSE 1.41: Sun JSSE provider(implements RSA Signatures, PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)
[DEBUG] HttpClient - -SunRsaSign 1.0: SUN's provider for RSA signatures
[DEBUG] HttpClient - -SunJCE 1.4: SunJCE Provider (implements DES, Triple DES, Blowfish, PBE, Diffie-Hellman, HMAC-MD5, HMAC-SHA1)
[DEBUG] HttpClient - -SunJGSS 1.0: Sun (Kerberos v5)
[DEBUG] MultiThreadedHttpConnectionManager - -HttpConnectionManager.getConnection: config = [EMAIL PROTECTED], timeout = 0
[DEBUG] HttpConnection - -Creating connection for localhost using protocol http:80
[DEBUG] HttpConnection - -Creating connection for localhost using protocol http:80
[DEBUG] HttpConnection - -HttpConnection.setSoTimeout(0)
[DEBUG] HttpMethod - -Execute loop try 1
[DEBUG] wire - ->> "GET /test.gif HTTP/1.1[\r][\n]"
[DEBUG] HttpMethod - -Adding Host request header
[DEBUG] wire - ->> "User-Agent: Jakarta Commons-HttpClient/2.0beta1[\r][\n]"
[DEBUG] wire - ->> "Host: localhost:8080[\r][\n]"
[DEBUG] wire - ->> "[\r][\n]"
[DEBUG] wire - -<< "HTTP/1.1 401 Unauthorized[\r][\n]"
[DEBUG] wire - -<< "WWW-Authenticate: Basic "realm"[\r][\n]"
[DEBUG] wire - -<< "Connection: keep-alive[\r][\n]"
[DEBUG] HttpMethod - -Authorization required
[DEBUG] HttpAuthenticator - -Using 'localhost:8080' authentication realm
[DEBUG] HttpMethod - -HttpMethodBase.execute(): Server demanded authentication credentials, will try again.
[DEBUG] HttpMethod - -Should NOT close connection in response to Connection: keep-alive


[DEBUG] HttpMethod - -Execute loop try 2
[DEBUG] wire - ->> "GET /test.gif HTTP/1.1[\r][\n]"
[DEBUG] HttpMethod - -Request to add Host header ignored: header already added
[DEBUG] wire - ->> "User-Agent: Jakarta Commons-HttpClient/2.0beta1[\r][\n]"
[DEBUG] wire - ->> "Host: localhost:8080[\r][\n]"
[DEBUG] wire - ->> "Authorization: Basic c3lzYWRtaW46aWRj[\r][\n]"
[DEBUG] MultiThreadedHttpConnectionManager - -Freeing connection: [EMAIL PROTECTED]
[DEBUG] MultiThreadedHttpConnectionManager - -Notifying no-one, there are no waiting threads
Exception in thread "main" java.net.SocketException: Socket closed
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:99)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at org.apache.commons.httpclient.HttpConnection$WrappedOutputStream.write( HttpConnection.java:1347)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:69)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:127)
at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(H ttpConnection.java:782)
at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpCo nnectionAdapter.flushRequestOutputStream(MultiThreadedHttpConnectionMan ager.java:1046)
at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBas e.java:2174)
at org.apache.commons.httpclient.HttpMethodBase.processRequest(HttpMethodB ase.java:2529)
at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.jav a:1066)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java: 638)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java: 500)
at Test.main(Test.java:15)



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to