vincent
vincent

Reputation: 1234

Spring rest template 401 error response

I have a rest controller answering on http://localhost:8080/documents. I should have an authorization header to call it.

So in my client code i have :

HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "myToken");
HttpEntity entity = new HttpEntity(null, headers);

restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

response = restTemplate.exchange("http://localhost:8080/documents", HttpMethod.GET, entity, Document[].class);

Everything works fine. After that i want to test the errors. So, i remove the authorization header.

When i test with a tool like postman, i receive the 401 response. But with my rest template, i only receive an IllegalArgumentException.

I alse have tested the ResponseErrorHandler.

public class MyErrorHandler implements ResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
        return false; //i've also tried return true
    }

    @Override
    public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
        String theString = IOUtils.toString(clientHttpResponse.getBody());
        FunctionalTestException exception = new FunctionalTestException();
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("code", clientHttpResponse.getStatusCode().toString());
        properties.put("body", theString);
        properties.put("header", clientHttpResponse.getHeaders());
        exception.setProperties(properties);
        throw exception;
    }
}

and in my client i have

restTemplate.setErrorHandler(new MyErrorHandler());

It didn't work.

So my question is how to find my 401 error response using the rest template.

Here is the exception :

java.lang.IllegalArgumentException: invalid start or end

and the stack trace :

sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1455)
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
sun.net.www.protocol.http.HttpURLConnection.getHeaderField(HttpURLConnection.java:2979)
java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:489)
org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:84)
org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:619)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:580)
org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:498)
org.boite.dq.steps.UnauthorizedUser.callListCategories(UnauthorizedUser.java:61)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.jbehave.core.steps.StepCreator$ParametrisedStep.perform(StepCreator.java:733)
org.jbehave.core.embedder.PerformableTree$FineSoFar.run(PerformableTree.java:346)
org.jbehave.core.embedder.PerformableTree$PerformableSteps.perform(PerformableTree.java:1088)
org.jbehave.core.embedder.PerformableTree$AbstractPerformableScenario.performRestartableSteps(PerformableTree.java:953)
org.jbehave.core.embedder.PerformableTree$NormalPerformableScenario.perform(PerformableTree.java:992)
org.jbehave.core.embedder.PerformableTree$PerformableScenario.perform(PerformableTree.java:902)
org.jbehave.core.embedder.PerformableTree$PerformableStory.performScenarios(PerformableTree.java:825)
org.jbehave.core.embedder.PerformableTree$PerformableStory.perform(PerformableTree.java:798)
org.jbehave.core.embedder.PerformableTree.performCancellable(PerformableTree.java:422)
org.jbehave.core.embedder.PerformableTree.perform(PerformableTree.java:393)
org.jbehave.core.embedder.StoryManager$EnqueuedStory.call(StoryManager.java:292)
org.jbehave.core.embedder.StoryManager$EnqueuedStory.call(StoryManager.java:266)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)

Upvotes: 0

Views: 3629

Answers (1)

jannis
jannis

Reputation: 5200

The crash is happening in HttpURLConnection::getHeaderField so I'd suspect that one of your response headers is malformed (not what HttpURLConnection expects it to be). Usually a 401 response comes with a WWW-Authenticate response header pointing the agent to the authentication methods supported by the service. I'd suspect that this header causes the crash.

A bug report in Jersey's issue-tracker shows that HttpURLConnection puts some constraints on the WWW-Authentication header format. In this particular case the value causing a similar crash is oauth_problem=token_rejected. A workaround proposed there is:

Workaround is to send valid header values (spec compliant) or using the ApacheConnector

Upvotes: 3

Related Questions