Set entity contentLength for HttpClientRibbonCommand.

If the content length isn't set on the entity, when http client determines which header to set, it sets transfer-encoding to chunked rather than content-length. This fixes a missing content-length issue when using `HttpClientRibbonCommandFactory`. See gh-1042
parent ca67265c
......@@ -37,6 +37,7 @@ import lombok.Getter;
public class RibbonApacheHttpRequest extends ClientRequest implements Cloneable {
private final String method;
private Long contentLength;
private final MultiValueMap<String, String> headers;
......@@ -45,10 +46,17 @@ public class RibbonApacheHttpRequest extends ClientRequest implements Cloneable
private final InputStream requestEntity;
public RibbonApacheHttpRequest(final String method, final URI uri,
final Boolean retryable, final MultiValueMap<String, String> headers,
final MultiValueMap<String, String> params, final InputStream requestEntity) {
this(method, uri, retryable, headers, params, requestEntity, null);
}
public RibbonApacheHttpRequest(final String method, final URI uri,
final Boolean retryable, final MultiValueMap<String, String> headers,
final MultiValueMap<String, String> params, final InputStream requestEntity) {
final MultiValueMap<String, String> params, final InputStream requestEntity, Long contentLength) {
this.method = method;
this.contentLength = contentLength;
this.uri = uri;
this.isRetriable = retryable;
this.headers = headers;
......@@ -77,6 +85,11 @@ public class RibbonApacheHttpRequest extends ClientRequest implements Cloneable
final BasicHttpEntity entity;
entity = new BasicHttpEntity();
entity.setContent(this.requestEntity);
// if the entity contentLength isn't set, transfer-encoding will be set
// to chunked in org.apache.http.protocol.RequestContent. See gh-1042
if (contentLength != null) {
entity.setContentLength(this.contentLength);
}
builder.setEntity(entity);
}
......
......@@ -35,6 +35,7 @@ import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.zuul.constants.ZuulConstants;
import com.netflix.zuul.context.RequestContext;
import org.springframework.util.StringUtils;
/**
* @author Christian Lohmann
......@@ -100,10 +101,15 @@ public class HttpClientRibbonCommand extends HystrixCommand<ClientHttpResponse>
protected ClientHttpResponse forward() throws Exception {
final RequestContext context = RequestContext.getCurrentContext();
Long contentLength = null;
String contentLengthHeader = context.getRequest().getHeader("Content-Length");
if (StringUtils.hasText(contentLengthHeader)) {
contentLength = new Long(contentLengthHeader);
}
URI uriInstance = new URI(this.uri);
RibbonApacheHttpRequest request = new RibbonApacheHttpRequest(this.method,
uriInstance, this.retryable, this.headers, this.params,
this.requestEntity);
this.requestEntity, contentLength);
final RibbonApacheHttpResponse response = this.client
.executeWithLoadBalancer(request);
context.set("ribbonResponse", response);
......
/*
* Copyright 2013-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.springframework.cloud.netflix.ribbon.apache;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.nio.charset.Charset;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.junit.Test;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.StreamUtils;
/**
* @author Spencer Gibb
*/
public class RibbonApacheHttpRequestTests {
@Test
public void testNullEntity() throws Exception {
URI uri = URI.create("http://example.com");
LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("my-header", "my-value");
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("myparam", "myparamval");
RibbonApacheHttpRequest httpRequest = new RibbonApacheHttpRequest("GET", uri, false,
headers, params, null);
HttpUriRequest request = httpRequest.toRequest(RequestConfig.custom().build());
assertThat("request is wrong type", request, is(not(instanceOf(HttpEntityEnclosingRequest.class))));
assertThat("uri is wrong", request.getURI().toString(), startsWith(uri.toString()));
assertThat("my-header is missing", request.getFirstHeader("my-header"), is(notNullValue()));
assertThat("my-header is wrong", request.getFirstHeader("my-header").getValue(), is(equalTo("my-value")));
assertThat("myparam is missing", request.getURI().getQuery(), is(equalTo("myparam=myparamval")));
}
@Test
public void testNotNullEntity() throws Exception {
URI uri = URI.create("http://example.com");
LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Content-Length", "4");
String entityValue = "abcd";
RibbonApacheHttpRequest httpRequest = new RibbonApacheHttpRequest("POST", uri, false,
headers, new LinkedMultiValueMap<String, String>(), new ByteArrayInputStream(entityValue.getBytes()),
(long) entityValue.length());
HttpUriRequest request = httpRequest.toRequest(RequestConfig.custom().build());
assertThat("request is wrong type", request, is(instanceOf(HttpEntityEnclosingRequest.class)));
assertThat("uri is wrong", request.getURI().toString(), startsWith(uri.toString()));
assertThat("Content-Length is missing", request.getFirstHeader("Content-Length"), is(notNullValue()));
assertThat("Content-Length is wrong", request.getFirstHeader("Content-Length").getValue(), is(equalTo("4")));
HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) request;
assertThat("entity is missing", entityRequest.getEntity(), is(notNullValue()));
HttpEntity entity = entityRequest.getEntity();
assertThat("contentLength is wrong", entity.getContentLength(), is(equalTo(4L)));
assertThat("content is missing", entity.getContent(), is(notNullValue()));
String string = StreamUtils.copyToString(entity.getContent(), Charset.forName("UTF-8"));
assertThat("content is wrong", string, is(equalTo(entityValue)));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment