Skip to content

Commit

Permalink
Backport of issue #2560 fixes to jetty-9.3.x
Browse files Browse the repository at this point in the history
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
  • Loading branch information
joakime committed May 31, 2018
1 parent 519d36a commit 53e8bc2
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.eclipse.jetty.server;

import java.io.IOException;
import java.nio.file.InvalidPathException;

import org.eclipse.jetty.http.HttpContent;
import org.eclipse.jetty.http.HttpContent.Factory;
Expand All @@ -29,7 +30,7 @@


/**
* A HttpContent.Factory for transient content. The HttpContent's created by
* A HttpContent.Factory for transient content. The HttpContent's created by
* this factory are not intended to be cached, so memory limits for individual
* HttpOutput streams are enforced.
*/
Expand All @@ -52,10 +53,18 @@ public ResourceContentFactory(ResourceFactory factory, MimeTypes mimeTypes, bool
public HttpContent getContent(String pathInContext,int maxBufferSize)
throws IOException
{
// try loading the content from our factory.
Resource resource=_factory.getResource(pathInContext);
HttpContent loaded = load(pathInContext,resource,maxBufferSize);
return loaded;
try
{
// try loading the content from our factory.
Resource resource = _factory.getResource(pathInContext);
HttpContent loaded = load(pathInContext, resource, maxBufferSize);
return loaded;
}
catch (Throwable t)
{
// Any error has potential to reveal fully qualified path
throw (InvalidPathException) new InvalidPathException(pathInContext, "Invalid PathInContext").initCause(t);
}
}


Expand All @@ -68,19 +77,19 @@ private HttpContent load(String pathInContext, Resource resource, int maxBufferS

if (resource.isDirectory())
return new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),maxBufferSize);

// Look for a gzip resource or content
String mt = _mimeTypes.getMimeByExtension(pathInContext);
if (_gzip)
{
// Is there a gzip resource?
// Is there a gzip resource?
String pathInContextGz=pathInContext+".gz";
Resource resourceGz=_factory.getResource(pathInContextGz);
if (resourceGz.exists() && resourceGz.lastModified()>=resource.lastModified() && resourceGz.length()<resource.length())
return new ResourceHttpContent(resource,mt,maxBufferSize,
new ResourceHttpContent(resourceGz,_mimeTypes.getMimeByExtension(pathInContextGz),maxBufferSize));
}

return new ResourceHttpContent(resource,mt,maxBufferSize);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.file.InvalidPathException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
Expand Down Expand Up @@ -419,6 +420,11 @@ else if (_servletContext instanceof ContextHandler.Context)
{
LOG.ignore(e);
}
catch (Throwable t)
{
// Any error has potential to reveal fully qualified path
throw (InvalidPathException) new InvalidPathException(pathInContext, "Invalid PathInContext").initCause(t);
}

if((r==null || !r.exists()) && pathInContext.endsWith("/jetty-dir.css"))
r=_stylesheet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@

package org.eclipse.jetty.servlet;

import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.io.File;
Expand All @@ -37,9 +42,11 @@
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.http.DateGenerator;
import org.eclipse.jetty.http.HttpContent;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.ResourceContentFactory;
Expand Down Expand Up @@ -365,7 +372,7 @@ public void testWelcome() throws Exception
response = connector.getResponses("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("403", response);
}

@Test
public void testWelcomeRedirect() throws Exception
{
Expand Down Expand Up @@ -437,7 +444,7 @@ public void testWelcomeDirWithQuestion() throws Exception
response = connector.getResponse("GET /context/dir%3F/ HTTP/1.0\r\n\r\n");
assertResponseContains("Location: http://0.0.0.0/context/dir%3F/index.html", response);
}


@Test
public void testWelcomeServlet() throws Exception
Expand Down Expand Up @@ -730,7 +737,7 @@ public void testRangeRequests() throws Exception

response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n"+
"Connection: close\r\n"+
"\r\n");
assertResponseContains("200 OK", response);
assertResponseContains("Accept-Ranges: bytes", response);
Expand All @@ -749,7 +756,7 @@ public void testRangeRequests() throws Exception

response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n"+
"Connection: close\r\n"+
"Range: bytes=0-9,20-29,40-49\r\n" +
"\r\n");
start = response.indexOf("--jetty");
Expand All @@ -766,7 +773,7 @@ public void testRangeRequests() throws Exception

response = connector.getResponses("GET /context/nofilesuffix HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n"+
"Connection: close\r\n"+
"Range: bytes=0-9,20-29,40-49,60-60,70-79\r\n" +
"\r\n");
start = response.indexOf("--jetty");
Expand Down Expand Up @@ -885,7 +892,7 @@ public void testGzip() throws Exception
assertResponseNotContains("Vary: Accept-Encoding",response);
assertResponseNotContains("Content-Encoding: gzip",response);
assertResponseNotContains("ETag: "+etag_gzip,response);
assertResponseContains("ETag: ",response);
assertResponseContains("ETag: ",response);

response = connector.getResponses("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:gzip\r\nIf-None-Match: "+etag_gzip+"\r\n\r\n");
assertResponseContains("304 Not Modified", response);
Expand All @@ -909,7 +916,7 @@ public void testGzip() throws Exception
public void testCachedGzip() throws Exception
{
testdir.ensureEmpty();
File resBase = testdir.getPathFile("docroot").toFile();
File resBase = testdir.getPathFile("docroot").toFile();
FS.ensureDirExists(resBase);
File file0 = new File(resBase, "data0.txt");
createFile(file0, "Hello Text 0");
Expand Down Expand Up @@ -974,6 +981,22 @@ public void testCachedGzip() throws Exception
assertResponseContains("ETag: "+etag,response);
}

@Test
public void testControlCharacter() throws Exception
{
testdir.ensureEmpty();
File docRoot = testdir.getPathFile("docroot").toFile();
FS.ensureDirExists(docRoot);
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
defholder.setInitParameter("resourceBase", docRoot.getAbsolutePath());

String rawResponse = connector.getResponse("GET /context/%0a HTTP/1.1\r\nHost: local\r\nConnection: close\r\n\r\n");
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
System.out.println(response + "\n" + response.getContent());
assertThat("Response.status", response.getStatus(), anyOf(is(HttpServletResponse.SC_NOT_FOUND), is(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)));
assertThat("Response.content", response.getContent(), is(not(containsString(docRoot.toString()))));
}

@Test
public void testIfModifiedSmall() throws Exception
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,16 +204,16 @@ public PathResource(Path path)
* @param parent the parent path resource
* @param childPath the child sub path
*/
private PathResource(PathResource parent, String childPath) throws MalformedURLException
private PathResource(PathResource parent, String childPath)
{
// Calculate the URI and the path separately, so that any aliasing done by
// FileSystem.getPath(path,childPath) is visiable as a difference to the URI
// FileSystem.getPath(path,childPath) is visible as a difference to the URI
// obtained via URIUtil.addDecodedPath(uri,childPath)

this.path = parent.path.getFileSystem().getPath(parent.path.toString(), childPath);
if (isDirectory() &&!childPath.endsWith("/"))
childPath+="/";
this.uri = URIUtil.addPath(parent.uri,childPath);
if (isDirectory() && !childPath.endsWith("/"))
childPath += "/";
this.uri = URIUtil.addPath(parent.uri, childPath);
this.alias = checkAliasPath();
}

Expand Down Expand Up @@ -242,10 +242,6 @@ public PathResource(URI uri) throws IOException
{
path = Paths.get(uri);
}
catch (InvalidPathException e)
{
throw e;
}
catch (IllegalArgumentException e)
{
throw e;
Expand Down Expand Up @@ -286,7 +282,7 @@ public PathResource(URL url) throws IOException, URISyntaxException
}

@Override
public Resource addPath(final String subpath) throws IOException, MalformedURLException
public Resource addPath(final String subpath) throws IOException
{
String cpath = URIUtil.canonicalPath(subpath);

Expand Down

0 comments on commit 53e8bc2

Please sign in to comment.