AdamC
AdamC

Reputation: 16273

Content-Length header already present

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?

Upvotes: 39

Views: 52195

Answers (7)

Walid Moustafa
Walid Moustafa

Reputation: 11

If you are adopting the XML configuration answer by John Rix, make sure to add a depends-on attribute to the httpClient bean so the RemoveSoapHeadersInterceptor interceptor is added to the ClientBuilder before the httpClient bean gets created. SOAP headers removal hasn't taken effect until I have done so.

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

Upvotes: 0

Alok
Alok

Reputation: 143

@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();

Upvotes: -1

Muhd
Muhd

Reputation: 25576

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();

Upvotes: 11

John Rix
John Rix

Reputation: 6693

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.

Upvotes: 46

igor.zh
igor.zh

Reputation: 2348

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());

Upvotes: 15

Prannay
Prannay

Reputation: 11

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.

Upvotes: 1

Stephen C
Stephen C

Reputation: 718906

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.

Upvotes: 37

Related Questions