Commit f707e5f0 by Jettro Coenradie Committed by Spencer Gibb

Case insensitive Content-Encoding check

Fixes a problem with a header in the response containing content-encoding in lowercase letters. Uses HttpHeaders for case insensitve check. Also fixes an issue checking if a request is made for gzip content. If headers has more than gzip (ie gzip,deflate,sdch), checks if contains gzip instead of equals to. Fixes gh-662
parent a61c18c6
...@@ -43,6 +43,9 @@ import com.netflix.zuul.util.HTTPRequestUtils; ...@@ -43,6 +43,9 @@ import com.netflix.zuul.util.HTTPRequestUtils;
import lombok.extern.apachecommons.CommonsLog; import lombok.extern.apachecommons.CommonsLog;
import static org.springframework.http.HttpHeaders.CONTENT_ENCODING;
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
/** /**
* @author Dave Syer * @author Dave Syer
*/ */
...@@ -55,8 +58,6 @@ public class ProxyRequestHelper { ...@@ -55,8 +58,6 @@ public class ProxyRequestHelper {
*/ */
public static final String IGNORED_HEADERS = "ignoredHeaders"; public static final String IGNORED_HEADERS = "ignoredHeaders";
public static final String CONTENT_ENCODING = "Content-Encoding";
private TraceRepository traces; private TraceRepository traces;
public void setTraces(TraceRepository traces) { public void setTraces(TraceRepository traces) {
...@@ -122,15 +123,23 @@ public class ProxyRequestHelper { ...@@ -122,15 +123,23 @@ public class ProxyRequestHelper {
} }
public void setResponse(int status, InputStream entity, public void setResponse(int status, InputStream entity,
MultiValueMap<String, String> headers) throws IOException { MultiValueMap<String, String> headers) throws IOException {
RequestContext context = RequestContext.getCurrentContext(); RequestContext context = RequestContext.getCurrentContext();
RequestContext.getCurrentContext().setResponseStatusCode(status); context.setResponseStatusCode(status);
if (entity != null) { if (entity != null) {
RequestContext.getCurrentContext().setResponseDataStream(entity); context.setResponseDataStream(entity);
}
HttpHeaders httpHeaders = new HttpHeaders();
for (Entry<String, List<String>> header : headers.entrySet()) {
List<String> values = header.getValue();
for (String value : values) {
httpHeaders.add(header.getKey(), value);
}
} }
boolean isOriginResponseGzipped = false; boolean isOriginResponseGzipped = false;
if (headers.containsKey(CONTENT_ENCODING)) { if (httpHeaders.containsKey(CONTENT_ENCODING)) {
Collection<String> collection = headers.get(CONTENT_ENCODING); List<String> collection = httpHeaders.get(CONTENT_ENCODING);
for (String header : collection) { for (String header : collection) {
if (HTTPRequestUtils.getInstance().isGzipped(header)) { if (HTTPRequestUtils.getInstance().isGzipped(header)) {
isOriginResponseGzipped = true; isOriginResponseGzipped = true;
...@@ -139,16 +148,16 @@ public class ProxyRequestHelper { ...@@ -139,16 +148,16 @@ public class ProxyRequestHelper {
} }
} }
context.setResponseGZipped(isOriginResponseGzipped); context.setResponseGZipped(isOriginResponseGzipped);
for (Entry<String, List<String>> header : headers.entrySet()) { for (Entry<String, List<String>> header : headers.entrySet()) {
RequestContext ctx = RequestContext.getCurrentContext();
String name = header.getKey(); String name = header.getKey();
for (String value : header.getValue()) { for (String value : header.getValue()) {
ctx.addOriginResponseHeader(name, value); context.addOriginResponseHeader(name, value);
if (name.equalsIgnoreCase("content-length")) { if (name.equalsIgnoreCase(CONTENT_LENGTH)) {
ctx.setOriginContentLength(value); context.setOriginContentLength(value);
} }
if (isIncludedHeader(name)) { if (isIncludedHeader(name)) {
ctx.addZuulResponseHeader(name, value); context.addZuulResponseHeader(name, value);
} }
} }
} }
...@@ -176,21 +185,21 @@ public class ProxyRequestHelper { ...@@ -176,21 +185,21 @@ public class ProxyRequestHelper {
} }
} }
switch (name) { switch (name) {
case "host": case "host":
case "connection": case "connection":
case "content-length": case "content-length":
case "content-encoding": case "content-encoding":
case "server": case "server":
case "transfer-encoding": case "transfer-encoding":
return false; return false;
default: default:
return true; return true;
} }
} }
public Map<String, Object> debug(String verb, String uri, public Map<String, Object> debug(String verb, String uri,
MultiValueMap<String, String> headers, MultiValueMap<String, String> params, MultiValueMap<String, String> headers, MultiValueMap<String, String> params,
InputStream requestEntity) throws IOException { InputStream requestEntity) throws IOException {
Map<String, Object> info = new LinkedHashMap<String, Object>(); Map<String, Object> info = new LinkedHashMap<String, Object>();
if (this.traces != null) { if (this.traces != null) {
RequestContext context = RequestContext.getCurrentContext(); RequestContext context = RequestContext.getCurrentContext();
...@@ -233,7 +242,7 @@ public class ProxyRequestHelper { ...@@ -233,7 +242,7 @@ public class ProxyRequestHelper {
} }
public void appendDebug(Map<String, Object> info, int status, public void appendDebug(Map<String, Object> info, int status,
MultiValueMap<String, String> headers) { MultiValueMap<String, String> headers) {
if (this.traces != null) { if (this.traces != null) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, Object> trace = (Map<String, Object>) info.get("headers"); Map<String, Object> trace = (Map<String, Object>) info.get("headers");
...@@ -267,3 +276,4 @@ public class ProxyRequestHelper { ...@@ -267,3 +276,4 @@ public class ProxyRequestHelper {
} }
} }
...@@ -22,7 +22,6 @@ import java.io.InputStream; ...@@ -22,7 +22,6 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.List; import java.util.List;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
...@@ -35,10 +34,14 @@ import com.netflix.zuul.ZuulFilter; ...@@ -35,10 +34,14 @@ import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.constants.ZuulConstants; import com.netflix.zuul.constants.ZuulConstants;
import com.netflix.zuul.constants.ZuulHeaders; import com.netflix.zuul.constants.ZuulHeaders;
import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.util.HTTPRequestUtils;
import lombok.extern.apachecommons.CommonsLog;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
*/ */
@CommonsLog
public class SendResponseFilter extends ZuulFilter { public class SendResponseFilter extends ZuulFilter {
private static DynamicBooleanProperty INCLUDE_DEBUG_HEADER = DynamicPropertyFactory private static DynamicBooleanProperty INCLUDE_DEBUG_HEADER = DynamicPropertyFactory
...@@ -101,7 +104,9 @@ public class SendResponseFilter extends ZuulFilter { ...@@ -101,7 +104,9 @@ public class SendResponseFilter extends ZuulFilter {
boolean isGzipRequested = false; boolean isGzipRequested = false;
final String requestEncoding = context.getRequest().getHeader( final String requestEncoding = context.getRequest().getHeader(
ZuulHeaders.ACCEPT_ENCODING); ZuulHeaders.ACCEPT_ENCODING);
if (requestEncoding != null && requestEncoding.equals("gzip")) {
if (requestEncoding != null
&& HTTPRequestUtils.getInstance().isGzipped(requestEncoding)) {
isGzipRequested = true; isGzipRequested = true;
} }
is = context.getResponseDataStream(); is = context.getResponseDataStream();
...@@ -117,8 +122,8 @@ public class SendResponseFilter extends ZuulFilter { ...@@ -117,8 +122,8 @@ public class SendResponseFilter extends ZuulFilter {
inputStream = new GZIPInputStream(is); inputStream = new GZIPInputStream(is);
} }
catch (java.util.zip.ZipException ex) { catch (java.util.zip.ZipException ex) {
System.out.println("gzip expected but not " log.debug("gzip expected but not "
+ "received assuming unencoded response" + "received assuming unencoded response "
+ RequestContext.getCurrentContext().getRequest() + RequestContext.getCurrentContext().getRequest()
.getRequestURL().toString()); .getRequestURL().toString());
inputStream = is; inputStream = is;
......
...@@ -16,15 +16,7 @@ ...@@ -16,15 +16,7 @@
package org.springframework.cloud.netflix.zuul.filters; package org.springframework.cloud.netflix.zuul.filters;
import static org.hamcrest.Matchers.contains; import java.io.IOException;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.List; import java.util.List;
import org.junit.Before; import org.junit.Before;
...@@ -33,12 +25,24 @@ import org.mockito.Mock; ...@@ -33,12 +25,24 @@ import org.mockito.Mock;
import org.springframework.boot.actuate.trace.InMemoryTraceRepository; import org.springframework.boot.actuate.trace.InMemoryTraceRepository;
import org.springframework.boot.actuate.trace.Trace; import org.springframework.boot.actuate.trace.Trace;
import org.springframework.boot.actuate.trace.TraceRepository; import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.context.RequestContext;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.MockitoAnnotations.initMocks;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
*/ */
...@@ -71,7 +75,7 @@ public class ProxyRequestHelperTests { ...@@ -71,7 +75,7 @@ public class ProxyRequestHelperTests {
new LinkedMultiValueMap<String, String>(), request.getInputStream()); new LinkedMultiValueMap<String, String>(), request.getInputStream());
Trace actual = this.traceRepository.findAll().get(0); Trace actual = this.traceRepository.findAll().get(0);
System.err.println(actual.getInfo()); System.err.println(actual.getInfo());
assertThat((String)actual.getInfo().get("body"), equalTo("{}")); assertThat((String) actual.getInfo().get("body"), equalTo("{}"));
} }
...@@ -112,4 +116,45 @@ public class ProxyRequestHelperTests { ...@@ -112,4 +116,45 @@ public class ProxyRequestHelperTests {
assertThat(acceptEncodings, contains("gzip")); assertThat(acceptEncodings, contains("gzip"));
} }
@Test
public void setResponseLowercase() throws IOException {
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
RequestContext context = RequestContext.getCurrentContext();
context.setRequest(request);
context.setResponse(response);
ProxyRequestHelper helper = new ProxyRequestHelper();
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_ENCODING.toLowerCase(), "gzip");
helper.setResponse(
200,
request.getInputStream(),
headers);
assertTrue(context.getResponseGZipped());
}
@Test
public void setResponseUppercase() throws IOException {
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
RequestContext context = RequestContext.getCurrentContext();
context.setRequest(request);
context.setResponse(response);
ProxyRequestHelper helper = new ProxyRequestHelper();
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_ENCODING, "gzip");
helper.setResponse(
200,
request.getInputStream(),
headers);
assertTrue(context.getResponseGZipped());
}
} }
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