Home » Android » java – Content-Length header already present

java – Content-Length header already present

Posted by: admin April 23, 2020 Leave a comment

Questions:

I am using the Apache HttpClient (4.1) included in Android to execute a HttpPut. I have verified that I only have 1 content-length header. However, every time I send the request, I get a protocol exception about the Content-Length header already specified.

HttpClient client = new DefaultHttpClient();
putMethod = new HttpPut(url + encodedFileName);
putMethod.addHeader(..)  //<-once for each header
putMethod.setEntity(new ByteArrayEntity(data));
client.execute(putMethod);  //throws Exception

Caused by: org.apache.http.ProtocolException: Content-Length header already present
at org.apache.http.protocol.RequestContent.process(RequestContent.java:70)
at org.apache.http.protocol.BasicHttpProcessor.process(BasicHttpProcessor.java:290)

Any ideas?

How to&Answers:

I’ve not used HttpClient myself, but I suspect that the problem is that putMethod.setEntity(...) is implicitly supplying a content length and you are also setting it explicitly via one of the putMethod.addHeader(...) calls.

Answer:

As pointed out by igor.zh, this problem can occur if using Spring’s HttpComponentsMessageSender class. To be more precise though, this is only a problem if you are passing your own instance of HttpClient into the HttpComponentsMessageSender constructor – the issue is handled automatically otherwise.

As of spring-ws 2.1.4, the HttpComponentsMessageSender.RemoveSoapHeadersInterceptor subclass that is used in the default constructor was made public to address this issue (see https://jira.spring.io/browse/SWS-835) and so can be used in your own HttpClient instances instead of writing your own class to do it. It also clears the HTTP.TRANSFER_ENCODING header.

Use the HttpClientBuilder.addInterceptorFirst method to inject this interceptor into your own HttpClient instance. Example below using XML bean wiring. If anybody knows a more concise way of constructing the HttpClient instance (aside from writing a factory bean class), I’m all ears!

<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create"/>

<bean id="interceptedHttpClientBuilder" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="httpClientBuilder" />
    <property name="targetMethod" value="addInterceptorFirst"> </property>
    <property name="arguments">
        <list>
            <bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender.RemoveSoapHeadersInterceptor"/>
        </list>
    </property>
</bean>

<bean id="httpClient" factory-bean="interceptedHttpClientBuilder" factory-method="build" />

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
    <constructor-arg ref="messageFactory"/>
    <property name="messageSender">
        <bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
            <property name="httpClient" ref="httpClient"/>
        </bean>
    </property>
</bean>

Alternatively, if you can, just allow HttpComponentsMessageSender to construct its own HttpClient instance rather than passing one to it. Minor note on this: as of spring-ws 2.2.0-RELEASE, the default constructor for HttpComponentsMessageSender continues to use the DefaultHttpClient class, which is now deprecated. Hopefully this will be addressed in a future release.

Answer:

That happens to me when I used http://docs.spring.io/spring-ws/site/apidocs/org/springframework/ws/transport/http/HttpComponentsMessageSender.html as a Spring WebService Message Sender. In that case the stuff like HttpPut or HttpRequest are not easily accessible, so, building HttpClient with HttpClientBuilder, I ended up inserting a HttpRequestInterceptor in front of the culprit RequestContent :

private static class ContentLengthHeaderRemover implements HttpRequestInterceptor{
    @Override
    public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
        request.removeHeaders(HTTP.CONTENT_LEN);// fighting org.apache.http.protocol.RequestContent's ProtocolException("Content-Length header already present");
    }
}
...
    HttpClientBuilder httpClientBuilder = HttpClients.custom();
    httpClientBuilder.addInterceptorFirst(new CcontentLengthHeaderRemover());

Answer:

John Rix’s answer has the right idea. Here’s how you do it with plain java:

HttpClient client = HttpClients.custom()
    .addInterceptorFirst(new RemoveSoapHeadersInterceptor())
    .build();

Answer:

If you checkout http://docjar.org/docs/api/org/apache/http/protocol/RequestContent.html you’ll notice that it throws that exception if you’ve set it yourself. Therefore, the internal working set the content length automatically. This also means, to set it to “0”, you need to set the entity to null.

Answer:

@John Rix’s answer
This code helped solved the problem

    private static class ContentLengthHeaderRemover implements HttpRequestInterceptor{
            @Override
            public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
                request.removeHeaders(HTTP.CONTENT_LEN);// fighting org.apache.http.protocol.RequestContent's ProtocolException("Content-Length header already present");
            }
        }
HttpClient client = HttpClients.custom()
                .addInterceptorFirst(new ContentLengthHeaderRemover())
                .build();