Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly wait for entire result in JettyClientCall #1101

Open
wants to merge 1 commit into
base: 2.3
Choose a base branch
from

Conversation

cgatesman
Copy link

JettyClientCall.sendRequest() is randomly reporting error status code responses (e.g. HTTP 401) as 1001 Communication Error.

This is occurring, because it is using org.eclipse.jetty.client.util.InputStreamResponseListener.get() which is documented to only wait for the header response and not the entire content. InputStreamResponseListener.await() is documented to wait for the whole request/response cycle to be finished.

Using InputStreamResponseListener.get() means that it may or may not get the failure information which is handled by a separate thread and latch. In addition to this problem, JettyClientCall is incorrectly returning a 1001 error when it catches ExecutionException. InputStreamResponseListener.get() is throwing this exception even if there is simply an HTTP error (300+ HTTP status codes). It could be argued that this is incorrect behavior on Jetty's part. It just so happens that since InputStreamResponseListener.get() is used, on an HTTP error code case, many times the code beats the resultLatch in getting the header response and the exception is not thrown. In some cases, the failure gets recorded in time (in a separate thread) resulting in the InputStreamResponseListener.get() to throw ExecutionException.

In summary, anytime there is a failure HTTP status code on a call, there is a random chance for this to fail with 1001 Communication Error instead of the correct HTTP status code.

The fix includes using InputStreamResponseListener.await() instead of InputStreamResponseListener.get() to properly wait for the entire request/response cycle, and remove the catch for ExecutionException which was incorrectly setting the Status to 1001 in these cases. Note, InputStreamResponseListener.await() does not throw ExecutionException.

NOTE: I did not see any Jetty extension related unit tests to contribute to. If there are, and I just missed them, please point them out to me.

`JettyClientCall.sendRequest()` is randomly reporting error status code responses (e.g. HTTP 401) as 1001 Communication Error.

This is occurring, because it is using `org.eclipse.jetty.client.util.InputStreamResponseListener.get()` which is documented to only wait for the header response and not the entire content.  `InputStreamResponseListener.await()` is documented to wait for the whole request/response cycle to be finished.

Using `InputStreamResponseListener.get()` means that it may or may not get the failure information which is handled by a separate thread and latch.  In addition to this problem, `JettyClientCall` is incorrectly returning a 1001 error when it catches `ExecutionException`.  `InputStreamResponseListener.get()` is throwing this exception even if there is simply an HTTP error (300+ HTTP status codes).  It could be argued that this is incorrect behavior on Jetty's part.  It just so happens that since `InputStreamResponseListener.get()` is used, on an HTTP error code case, many times the code beats the resultLatch in getting the header response and the exception is not thrown.  In some cases, the failure gets recorded in time (in a separate thread) resulting in the `InputStreamResponseListener.get()` to throw `ExecutionException`.

In summary, anytime there is a failure HTTP status code on a call, there is a random chance for this to fail with 1001 Communication Error instead of the correct HTTP status code.

The fix includes using `InputStreamResponseListener.await()` instead of `InputStreamResponseListener.get()` to properly wait for the entire request/response cycle, and remove the catch for `ExecutionException` which was incorrectly setting the `Status` to 1001 in these cases.  Note, `InputStreamResponseListener.await()` does not throw `ExecutionException`.
@thboileau thboileau self-assigned this Jul 17, 2015
@thboileau
Copy link
Contributor

Hi @cgatesman, thanks a lot for your contribution!

Do you mind send us the signed Joint Copyright Assignement?

@thboileau
Copy link
Contributor

Hi @cgatesman, we received the signed JCA, thanks.

@thboileau
Copy link
Contributor

Hi @cgatesman, I've made some test with a client that downloads a file that weights 20kb, and it seems to lock.
I wonder if the await command reads the content entirely.

@cgatesman
Copy link
Author

Sorry. I have been away on vacation...

This is interesting, @thboileau. I'm not sure. I was going by Jetty's InputStreamResponseListener documentation.

This original issue came up in our unit tests which were using the client to drive our REST API. We were originally unaware that the default client had changed from Apache HttpClient to Jetty's HttpClient after upgrading Restlet. Making this fix seemed to fix our particular issue in our unit tests.

After submitting this fix, we switched back to the Apache HttpClient implementation which we had been using with the older version of Restlet, and decided we would look into possibly using the new Jetty's HttpClient implementation down the road when we upgrade Restlet again. So, I can't say if there is other issues around this client implementation as we haven't been using it after we ran into this initial problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants