eclipse-ee4j / eclipse-ee4j/jersey
Jersey client does not check response status code if no response type has been specified
- Dominant language
- Java
- Stars
- 730
- Forks
- 382
- PR merge metrics
- No merged PRs in 30d
Description
Consider a request to delete a resource as follows:
client.target("https://myrestapi.com/widgets/1234").delete();
If the server requires authentication for this request and none has been provided, i.e. no authorization header is present then the response will be 401 unauthorized. In this case I would expect an exception to be thrown however this did not happen. In fact the jersey api has a NotAuthorizedException which is documented to be thrown in such cases.
Looking at the code org.glassfish.jersey.client.JerseyInvocation I see these two methods:
@Override
public Future submit() {
final SettableFuture responseFuture = SettableFuture.create();
request().getClientRuntime().submit(requestContext, new ResponseCallback() {
@Override
public void completed(final ClientResponse response, final RequestScope scope) {
if (!responseFuture.isCancelled())
{ responseFuture.set(new InboundJaxrsResponse(response, scope)); }
else
{ response.close(); }
}
@Override
public void failed(final ProcessingException error) {
if (!responseFuture.isCancelled())
{ responseFuture.setException(error); }
}
});
return responseFuture;
}
@Override
public Future submit(final Class responseType) {
if (responseType == null) { throw new IllegalArgumentException(LocalizationMessages.RESPONSE_TYPE_IS_NULL()); }
final SettableFuture responseFuture = SettableFuture.create();
request().getClientRuntime().submit(requestContext, new ResponseCallback() {
@Override
public void completed(final ClientResponse response, final RequestScope scope) {
if (responseFuture.isCancelled()) { response.close(); return; }
try { responseFuture.set(translate(response, scope, responseType)); } catch (final ProcessingException ex) { failed(ex); }
}
@Override
public void failed(final ProcessingException error) {
if (responseFuture.isCancelled()) { return; }
if (error.getCause() instanceof WebApplicationException) { responseFuture.setException(error.getCause()); } else { responseFuture.setException(error); }
}
});
return responseFuture;
}
The former method is called if no response type class has been specified. If this method is called then no check of the response status code is made and therefore no exception is thrown. In the latter method, the call to translate does check the status code and throws an exception as expected.
IMHO this behaviour is surprising. Jersey 1.x always checked the response status code and threw an exception on a server error response unless the response type was set to "Response.class" (ClientResponse.class in Jersey 1.x).
#### Affected Versions
[2.22.1]
Contributor guide
Assessment
This issue has not been assessed yet.