Use weak ETags in VersionResourceResolver

Prior to this commit, the `VersionResourceResolver` implementations
would write a strong ETag HTTP response header with the resolved version
of the resource (the actual value depending on the chosen strategy).

This approach doesn't work well when combined with HTTP compression.
Web servers disable HTTP response copression in the presence of strong
ETags since mutating the response body would break the contract.

This commit changes this semantic and ensures that weak ETags are used
instead.

Closes gh-24898
This commit is contained in:
Brian Clozel 2020-05-11 21:25:54 +02:00
parent e4cb25f365
commit b883aad1f1
6 changed files with 10 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -317,7 +317,7 @@ public class VersionResourceResolver extends AbstractResourceResolver {
public HttpHeaders getResponseHeaders() { public HttpHeaders getResponseHeaders() {
HttpHeaders headers = (this.original instanceof HttpResource ? HttpHeaders headers = (this.original instanceof HttpResource ?
((HttpResource) this.original).getResponseHeaders() : new HttpHeaders()); ((HttpResource) this.original).getResponseHeaders() : new HttpHeaders());
headers.setETag("\"" + this.version + "\""); headers.setETag("W/\"" + this.version + "\"");
return headers; return headers;
} }
} }

View File

@ -165,7 +165,7 @@ public class ResourceWebHandlerTests {
setPathWithinHandlerMapping(exchange, "versionString/foo.css"); setPathWithinHandlerMapping(exchange, "versionString/foo.css");
this.handler.handle(exchange).block(TIMEOUT); this.handler.handle(exchange).block(TIMEOUT);
assertThat(exchange.getResponse().getHeaders().getETag()).isEqualTo("\"versionString\""); assertThat(exchange.getResponse().getHeaders().getETag()).isEqualTo("W/\"versionString\"");
assertThat(exchange.getResponse().getHeaders().getFirst("Accept-Ranges")).isEqualTo("bytes"); assertThat(exchange.getResponse().getHeaders().getFirst("Accept-Ranges")).isEqualTo("bytes");
assertThat(exchange.getResponse().getHeaders().get("Accept-Ranges").size()).isEqualTo(1); assertThat(exchange.getResponse().getHeaders().get("Accept-Ranges").size()).isEqualTo(1);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -175,7 +175,7 @@ public class VersionResourceResolverTests {
assertThat(actual.getFilename()).isEqualTo(expected.getFilename()); assertThat(actual.getFilename()).isEqualTo(expected.getFilename());
verify(this.versionStrategy, times(1)).getResourceVersion(expected); verify(this.versionStrategy, times(1)).getResourceVersion(expected);
assertThat(actual).isInstanceOf(HttpResource.class); assertThat(actual).isInstanceOf(HttpResource.class);
assertThat(((HttpResource) actual).getResponseHeaders().getETag()).isEqualTo(("\"" + version + "\"")); assertThat(((HttpResource) actual).getResponseHeaders().getETag()).isEqualTo(("W/\"" + version + "\""));
} }
@Test @Test

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -313,7 +313,7 @@ public class VersionResourceResolver extends AbstractResourceResolver {
public HttpHeaders getResponseHeaders() { public HttpHeaders getResponseHeaders() {
HttpHeaders headers = (this.original instanceof HttpResource ? HttpHeaders headers = (this.original instanceof HttpResource ?
((HttpResource) this.original).getResponseHeaders() : new HttpHeaders()); ((HttpResource) this.original).getResponseHeaders() : new HttpHeaders());
headers.setETag("\"" + this.version + "\""); headers.setETag("W/\"" + this.version + "\"");
return headers; return headers;
} }
} }

View File

@ -152,7 +152,7 @@ public class ResourceHttpRequestHandlerTests {
this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "versionString/foo.css"); this.request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "versionString/foo.css");
this.handler.handleRequest(this.request, this.response); this.handler.handleRequest(this.request, this.response);
assertThat(this.response.getHeader("ETag")).isEqualTo("\"versionString\""); assertThat(this.response.getHeader("ETag")).isEqualTo("W/\"versionString\"");
assertThat(this.response.getHeader("Accept-Ranges")).isEqualTo("bytes"); assertThat(this.response.getHeader("Accept-Ranges")).isEqualTo("bytes");
assertThat(this.response.getHeaders("Accept-Ranges").size()).isEqualTo(1); assertThat(this.response.getHeaders("Accept-Ranges").size()).isEqualTo(1);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -153,7 +153,7 @@ public class VersionResourceResolverTests {
assertThat(actual.getFilename()).isEqualTo(expected.getFilename()); assertThat(actual.getFilename()).isEqualTo(expected.getFilename());
verify(this.versionStrategy, times(1)).getResourceVersion(expected); verify(this.versionStrategy, times(1)).getResourceVersion(expected);
assertThat(actual).isInstanceOf(HttpResource.class); assertThat(actual).isInstanceOf(HttpResource.class);
assertThat(((HttpResource)actual).getResponseHeaders().getETag()).isEqualTo("\"" + version + "\""); assertThat(((HttpResource)actual).getResponseHeaders().getETag()).isEqualTo("W/\"" + version + "\"");
} }
@Test @Test