Commit 406e112a by Bertrand Renuart Committed by Ryan Baxter

Always forward Content-Length header from origin when set (#2833)

* Always forward Content-Length from origin when set unless response is compressed and client does not support it Fix for #2832 * Add test cases to assert behaviour with regards to the Content-Length header
parent 2118d5b4
......@@ -240,18 +240,14 @@ public class SendResponseFilter extends ZuulFilter {
servletResponse.addHeader(it.first(), it.second());
}
}
// Only inserts Content-Length if origin provides it and origin response is not
// gzipped
if (this.zuulProperties.isSetContentLength()) {
if (includeContentLengthHeader(context)) {
Long contentLength = context.getOriginContentLength();
if ( contentLength != null && !context.getResponseGZipped()) {
if(useServlet31) {
servletResponse.setContentLengthLong(contentLength);
} else {
//Try and set some kind of content length if we can safely convert the Long to an int
if (isLongSafe(contentLength)) {
servletResponse.setContentLength(contentLength.intValue());
}
if(useServlet31) {
servletResponse.setContentLengthLong(contentLength);
} else {
//Try and set some kind of content length if we can safely convert the Long to an int
if (isLongSafe(contentLength)) {
servletResponse.setContentLength(contentLength.intValue());
}
}
}
......@@ -261,4 +257,23 @@ public class SendResponseFilter extends ZuulFilter {
return value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE;
}
protected boolean includeContentLengthHeader(RequestContext context) {
// Not configured to forward the header
if (!this.zuulProperties.isSetContentLength()) {
return false;
}
// Only if Content-Length is provided
if (context.getOriginContentLength() == null) {
return false;
}
// If response is compressed, include header only if we are not about to decompress it
if (context.getResponseGZipped()) {
return context.isGzipRequested();
}
// Forward it in all other cases
return true;
}
}
......@@ -36,6 +36,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.util.WebUtils;
import com.netflix.zuul.constants.ZuulHeaders;
import com.netflix.zuul.context.Debug;
import com.netflix.zuul.context.RequestContext;
......@@ -61,6 +62,7 @@ public class SendResponseFilterTests {
@Before
public void setTestRequestcontext() {
RequestContext context = new RequestContext();
context.setResponseGZipped(false);
RequestContext.testSetCurrentContext(context);
}
......@@ -102,6 +104,9 @@ public class SendResponseFilterTests {
assertThat("wrong debug header", debugHeader, equalTo("[[[test]]]"));
}
/*
* GZip NOT requested and NOT a GZip response -> Content-Length forwarded asis
*/
@Test
public void runWithOriginContentLength() throws Exception {
ZuulProperties properties = new ZuulProperties();
......@@ -117,6 +122,42 @@ public class SendResponseFilterTests {
assertThat("wrong origin content length", contentLength, equalTo("6"));
}
/*
* GZip requested and GZip response -> Content-Length forwarded asis
*/
@Test
public void runWithOriginContentLength_gzipRequested_gzipResponse() throws Exception {
ZuulProperties properties = new ZuulProperties();
properties.setSetContentLength(true);
SendResponseFilter filter = createFilter(properties, "hello", "UTF-8", new MockHttpServletResponse(), true);
RequestContext.getCurrentContext().setOriginContentLength(6L); // for test
RequestContext.getCurrentContext().setResponseGZipped(true);
((MockHttpServletRequest) RequestContext.getCurrentContext().getRequest()).addHeader(ZuulHeaders.ACCEPT_ENCODING, "gzip");
filter.run();
String contentLength = RequestContext.getCurrentContext().getResponse().getHeader("Content-Length");
assertThat("wrong origin content length", contentLength, equalTo("6"));
}
/*
* GZip NOT requested and GZip response -> Content-Length discarded
*/
@Test
public void runWithOriginContentLength_gzipNotRequested_gzipResponse() throws Exception {
ZuulProperties properties = new ZuulProperties();
properties.setSetContentLength(true);
SendResponseFilter filter = createFilter(properties, "hello", "UTF-8", new MockHttpServletResponse(), true);
RequestContext.getCurrentContext().setOriginContentLength(6L); // for test
RequestContext.getCurrentContext().setResponseGZipped(true);
filter.run();
assertThat(RequestContext.getCurrentContext().getResponse().getHeader("Content-Length")).isNull();
}
@Test
public void closeResponseOutputStreamError() throws Exception {
HttpServletResponse response = mock(HttpServletResponse.class);
......@@ -126,6 +167,7 @@ public class SendResponseFilterTests {
context.setRequest(new MockHttpServletRequest());
context.setResponse(response);
context.setResponseDataStream(mockStream);
context.setResponseGZipped(false);
Closeable zuulResponse = mock(Closeable.class);
context.set("zuulResponse", zuulResponse);
RequestContext.testSetCurrentContext(context);
......@@ -156,6 +198,7 @@ public class SendResponseFilterTests {
context.setRequest(new MockHttpServletRequest());
context.setResponse(response);
context.setResponseDataStream(mockStream);
context.setResponseGZipped(false);
Closeable zuulResponse = mock(Closeable.class);
context.set("zuulResponse", zuulResponse);
RequestContext.testSetCurrentContext(context);
......@@ -200,8 +243,7 @@ public class SendResponseFilterTests {
context.setResponseBody(content);
}
context.addZuulResponseHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(content.length()));
context.setResponseGZipped(false);
context.set("error.status_code", HttpStatus.NOT_FOUND.value());
RequestContext.testSetCurrentContext(context);
SendResponseFilter filter = new SendResponseFilter(properties);
......
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