Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UNDERTOW-1950] Fix NullPointerException in PreCompressedResourceSupplier #1248

Merged
merged 2 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,19 @@ public PreCompressedResourceSupplier(ResourceManager resourceManager) {

@Override
public Resource getResource(HttpServerExchange exchange, String path) throws IOException {
Resource originalResource = resourceManager.getResource(path);
if(exchange.getRequestHeaders().contains(Headers.RANGE)) {
//we don't use serve pre compressed resources for range requests
return originalResource;
return resourceManager.getResource(path);
}
Resource resource = getEncodedResource(exchange, path, originalResource);
Resource resource = getEncodedResource(exchange, path);
if(resource == null) {
return originalResource;
return resourceManager.getResource(path);
}
return resource;
}


private Resource getEncodedResource(final HttpServerExchange exchange, String path, Resource originalResource) throws IOException {
private Resource getEncodedResource(final HttpServerExchange exchange, String path) throws IOException {
final List<String> res = exchange.getRequestHeaders().get(Headers.ACCEPT_ENCODING);
if (res == null || res.isEmpty()) {
return null;
Expand Down Expand Up @@ -118,7 +117,13 @@ public List<Resource> list() {

@Override
public String getContentType(MimeMappings mimeMappings) {
return originalResource.getContentType(mimeMappings);
String fileName = resource.getName();
String originalFileName = fileName.substring(0, fileName.length() - extension.length());
int index = originalFileName.lastIndexOf('.');
if (index != -1 && index != originalFileName.length() - 1) {
return mimeMappings.getMimeType(originalFileName.substring(index + 1));
}
return null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,72 @@ public void testContentEncodedResource() throws IOException, URISyntaxException
generatePreCompressedResource("gz");

//assert compressed response that was pre compressed
assertResponse(compClient.execute(get), true, plainResponse, "gz");
assertResponse(compClient.execute(get), true, plainResponse, "gz", "text/html");

} finally {
client.getConnectionManager().shutdown();
}
}

@Test
public void testContentEncodedJsonResource() throws IOException, URISyntaxException {
HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/path/data1.json");
TestHttpClient client = new TestHttpClient();
Path rootPath = Paths.get(getClass().getResource("data1.json").toURI()).getParent();

try (CloseableHttpClient compClient = HttpClientBuilder.create().build()){
DefaultServer.setRootHandler(new CanonicalPathHandler()
.setNext(new PathHandler()
.addPrefixPath("/path", new ResourceHandler(new PreCompressedResourceSupplier(new PathResourceManager(rootPath, 10485760)).addEncoding("gzip", ".gz"))
.setDirectoryListingEnabled(true))));

//assert response without compression
final String plainResponse = assertResponse(client.execute(get), false, null, "web", "application/json");

//assert compressed response, that doesn't exists, so returns plain
assertResponse(compClient.execute(get), false, plainResponse, "web", "application/json");

//generate compressed resource with extension .gz
Path json = rootPath.resolve("data1.json");
generateGZipFile(json, rootPath.resolve("data1.json.gz"));

//assert compressed response that was pre compressed
assertResponse(compClient.execute(get), true, plainResponse, "gz", "application/json");

} finally {
client.getConnectionManager().shutdown();
}
}

@Test
public void testContentEncodedJsonResourceWithoutUncompressed() throws IOException, URISyntaxException {
HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/path/data3.json");
TestHttpClient client = new TestHttpClient();
Path rootPath = Paths.get(getClass().getResource("data2.json").toURI()).getParent();

try (CloseableHttpClient compClient = HttpClientBuilder.create().build()){
DefaultServer.setRootHandler(new CanonicalPathHandler()
.setNext(new PathHandler()
.addPrefixPath("/path", new ResourceHandler(new PreCompressedResourceSupplier(new PathResourceManager(rootPath, 10485760)).addEncoding("gzip", ".gz"))
.setDirectoryListingEnabled(true))));

//generate compressed resource with extension .gz and delete the uncompressed
Path json = rootPath.resolve("data2.json");
Path jsonFileToBeZippedAndDeleted = rootPath.resolve("data3.json");
Files.copy(json, jsonFileToBeZippedAndDeleted);
// data3.json.gz has no corresponding data3.json in the filesystem (UNDERTOW-1950)
generateGZipFile(jsonFileToBeZippedAndDeleted, rootPath.resolve("data3.json.gz"));
Files.delete(jsonFileToBeZippedAndDeleted);

//assert compressed response even with missing uncompressed
assertResponse(compClient.execute(get), true, null, "gz", "application/json");

} finally {
client.getConnectionManager().shutdown();
}
}


@Test
public void testCorrectResourceSelected() throws IOException, URISyntaxException {
HttpGet get = new HttpGet(DefaultServer.getDefaultServerURL() + "/path/page.html");
Expand Down Expand Up @@ -136,7 +195,7 @@ public void testCorrectResourceSelected() throws IOException, URISyntaxException
generatePreCompressedResource("gzip.nonsense");

//assert compressed response that was pre compressed
assertResponse(compClient.execute(get), true, plainResponse, "gzip");
assertResponse(compClient.execute(get), true, plainResponse, "gzip", "text/html");

} finally {
client.getConnectionManager().shutdown();
Expand Down Expand Up @@ -166,21 +225,21 @@ private void replaceStringInFile(Path file, String original, String replacement)
}

private String assertResponse(HttpResponse response, boolean encoding) throws IOException {
return assertResponse(response, encoding, null, null);
return assertResponse(response, encoding, null, null, "text/html");
}

private String assertResponse(HttpResponse response, boolean encoding, String compareWith) throws IOException {
return assertResponse(response, encoding, compareWith, "web");
return assertResponse(response, encoding, compareWith, "web", "text/html");
}

/**
* Series of assertions checking response code, headers and response content
*/
private String assertResponse(HttpResponse response, boolean encoding, String compareWith, String extension) throws IOException {
private String assertResponse(HttpResponse response, boolean encoding, String compareWith, String extension, String contentType) throws IOException {
Assert.assertEquals(StatusCodes.OK, response.getStatusLine().getStatusCode());
String body = HttpClientUtils.readResponse(response);
Header[] headers = response.getHeaders(Headers.CONTENT_TYPE_STRING);
Assert.assertEquals("text/html", headers[0].getValue());
Assert.assertEquals(contentType, headers[0].getValue());

if (encoding) {
assert response.getEntity() instanceof DecompressingEntity; //no other nice way to be sure we get back gzipped content
Expand Down
21 changes: 21 additions & 0 deletions core/src/test/java/io/undertow/server/handlers/file/data1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"undertow": {
"title": "compressed resource",
"subtype": {
"method": "test json compressed resource",
"listInfo": {
"test": {
"json": "js",
"compressed": "c",
"resource": "this file",
"type": "data",
"def": {
"thisFile": "Test purposes",
"seeAlso": ["data2", "json"]
},
"See": "compression"
}
}
}
}
}
21 changes: 21 additions & 0 deletions core/src/test/java/io/undertow/server/handlers/file/data2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"undertow": {
"title": "compressed resource",
"subtype": {
"method": "test json compressed resource",
"listInfo": {
"test": {
"json": "js",
"compressed": "c",
"resource": "this file",
"type": "data",
"def": {
"thisFile": "Test purposes",
"seeAlso": ["data1", "json"]
},
"See": "compression"
}
}
}
}
}