[ 
https://issues.apache.org/jira/browse/HTTPCORE-242?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12934457#action_12934457
 ] 

Oleg Kalnichevski commented on HTTPCORE-242:
--------------------------------------------

Hi Michael

Many thanks for the wire log! It helped a great deal.

Based on what I am seeing in the log, unfortunately, the behaviour of IIS/7.5 
appears silly and utterly illogical. The server responds early while the client 
is still busy writing out the request body and nonetheless blissfully expects 
the client to keep the connection alive somehow. The upshot of this silliness 
is that the client must either stop sending data and switch to processing the 
response potentially leaving the connection in a inconsistent, non-reusable 
state or continue writing request out under assumption that the server is still 
reading the data (which begs the question what was the f..king point of sending 
the response early)

I see two possibilities to deal with the problem, none of which is ideal.

(1) If the server sends a response early, out of usual request/response 
sequence, the client should stop writing out the request body, deal with the 
response, and then drop the connection as non-reusable (which is basically the 
case). This, however, is very likely to interfere with the NTLM authentication 
protocol, which is stateful by design and therefore cannot work with 
non-persistent connections.

(2) Apply your patch and accept the risks of causing compatibility issues with 
those servers that tend to respond early to POST requests but at least do not 
expect the client to keep the connection alive.

My personal preference would be the first option given that the whole mess is a 
direct result of IIS brokenness. In this case you will have to change your code 
to execute a GET request for each new connection in order to force the NTLM 
authentication with the server. At any rate it is massively more efficient to 
use an extra GET request for NTLM authentication instead of a POST, which would 
require the same request body to be resent three times for no good reason.

Do you think you could live with the first option?

Oleg


> NullPointerException in AsyncNHttpClientHandler  when server sends reply 
> before request is fully written.
> ---------------------------------------------------------------------------------------------------------
>
>                 Key: HTTPCORE-242
>                 URL: https://issues.apache.org/jira/browse/HTTPCORE-242
>             Project: HttpComponents HttpCore
>          Issue Type: Bug
>          Components: HttpCore NIO
>    Affects Versions: 4.1
>         Environment: Server:  IIS/7.5 with NTLM authentication.
>            Reporter: Michael Poindexter
>         Attachments: httcore-quickresponse.pcap, HTTPCORE-242.patch, 
> httpcore-connection-reuse-bug-fixed2.zip, httpcore.log
>
>
> I'm seeing a problem with AsyncNHttpClientHandler in v4.1 of HttpCore.  When 
> I submit a number of requests simultaneously or a single POST with a large 
> body to a server using NTLM authentication, I get this exception:
> Caused by: java.lang.NullPointerException
> at 
> org.apache.http.nio.protocol.AsyncNHttpClientHandler.outputReady(AsyncNHttpClientHandler.java:268)
> at 
> org.apache.http.nio.protocol.BufferingHttpClientHandler.outputReady(BufferingHttpClientHandler.java:118)
> at 
> org.apache.http.impl.nio.DefaultNHttpClientConnection.produceOutput(DefaultNHttpClientConnection.java:207)
> at 
> org.apache.http.impl.nio.ssl.SSLClientIOEventDispatch.outputReady(SSLClientIOEventDispatch.java:245)
> at 
> com.qumu.cxf.rt.transport.ahttp.MultiProtocolIOEventDispatch.outputReady(MultiProtocolIOEventDispatch.java:49)
> at 
> org.apache.http.impl.nio.reactor.BaseIOReactor.writable(BaseIOReactor.java:185)
> at 
> org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:338)
> at 
> org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
> at 
> org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:275)
> at 
> org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
> at 
> org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:542)
> at java.lang.Thread.run(Thread.java:680)
> The server I am connecting to is IIS/7.5. I am using NTLM authentication 
> (with JCIFS), so I need to keep the connection alive through several round 
> trips as the NTLM message exchange occurs.
> I dug into the HttpCore code, and here is my analysis of what is occurring:
> 1.) AsyncNHttpClientHandler.connect calls requestReady to send the initial 
> request.  This sets the request on the connection, and the connection starts 
> writing the request line in response to write events.
> 2.) The server receives the request line and responds immediately with a 401 
> Unauthorized.  At this point the POST body has not been fully sent to the 
> server.
> 3.) AsyncNHttpClientHandler.inputReady is called with the response from the 
> server.  At this point processResponse is called, and my code executes.  I 
> detect that the request needs authentication and I need to retransmit my 
> request with an auth header, so my ConnectionReuseStrategy says to keep the 
> connection alive.
> 4.) When control returns from my code, the code in processResponse calls 
> connState.resetOutput, clearing the entity and request in connState.  There 
> is still output from the POST body pending.
> 5.)  processResponse calls conn.requestOutput to reenable write events since 
> the connection is not to be closed.
> 6.)  A write event happens, and DefaultNHttpClientConnection.produceOutput is 
> called.  Since the output from the initial request never finished, 
> contentEncoder is not null and so AsyncNHttpClientHandler.outputReady is 
> called instead of requestReady.  Since connState was reset, the entity is 
> null and this NPE happens.
> I copied the code of AsyncNHttpClientHandler and added a conn.suspendInput() 
> call in requestReady:
>            if (entityReq != null && entityReq.expectContinue()) {
>                .....
>            } else {
>            conn.suspendInput();
>            }
> and a conn.requestInput call in outputReady:
>            entity.produceContent(encoder, conn);
>            if(encoder.isCompleted()) {
>            conn.requestInput();
>            }
> and this seemed to resolve the issue by not allowing the request and response 
> to overlap, but I'm not sure this is the best way to fix it.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to