Jetty-12 : Testing for ResourceHandler / ResourceService (#8327)

* Overhaul of ResourceHandlerTest
* Making ResourceHandlerTest more flexible for testing
  + Each test has it's own docroot
  + Each test decides what it's docroot contents are
* Support QuotedQualityCSV(List<String>)
This commit is contained in:
Joakim Erdfelt 2022-07-21 15:12:19 -05:00 committed by GitHub
parent 769bd5edd6
commit 131fd00285
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 3576 additions and 787 deletions

View File

@ -88,6 +88,28 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
});
}
/**
* Sorts values with equal quality according to given order.
*
* @param preferredOrder Array indicating the preferred order of known values
*/
public QuotedQualityCSV(List<String> preferredOrder)
{
this((s) ->
{
for (int i = 0; i < preferredOrder.size(); ++i)
{
if (preferredOrder.get(i).equals(s))
return preferredOrder.size() - i;
}
if ("*".equals(s))
return preferredOrder.size();
return 0;
});
}
/**
* Orders values with equal quality with the given function.
*

View File

@ -16,7 +16,9 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.nio.file.InvalidPathException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.HttpContent;
@ -36,10 +38,11 @@ public class ResourceContentFactory implements ContentFactory
{
private final ResourceFactory _factory;
private final MimeTypes _mimeTypes;
private final CompressedContentFormat[] _precompressedFormats;
private final List<CompressedContentFormat> _precompressedFormats;
public ResourceContentFactory(ResourceFactory factory, MimeTypes mimeTypes, CompressedContentFormat[] precompressedFormats)
public ResourceContentFactory(ResourceFactory factory, MimeTypes mimeTypes, List<CompressedContentFormat> precompressedFormats)
{
Objects.requireNonNull(mimeTypes, "MimeTypes cannot be null");
_factory = factory;
_mimeTypes = mimeTypes;
_precompressedFormats = precompressedFormats;
@ -80,10 +83,10 @@ public class ResourceContentFactory implements ContentFactory
// Look for a precompressed resource or content
String mt = _mimeTypes.getMimeByExtension(pathInContext);
if (_precompressedFormats.length > 0)
if (_precompressedFormats.size() > 0)
{
// Is there a compressed resource?
Map<CompressedContentFormat, HttpContent> compressedContents = new HashMap<>(_precompressedFormats.length);
Map<CompressedContentFormat, HttpContent> compressedContents = new HashMap<>(_precompressedFormats.size());
for (CompressedContentFormat format : _precompressedFormats)
{
String compressedPathInContext = pathInContext + format.getExtension();

View File

@ -19,6 +19,7 @@ import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
@ -45,8 +46,6 @@ import org.eclipse.jetty.util.URIUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.util.Arrays.stream;
/**
* Resource service, used by DefaultServlet and ResourceHandler
*/
@ -59,14 +58,14 @@ public class ResourceService
// TODO: see if we can set this to private eventually
public static final int USE_KNOWN_CONTENT_LENGTH = -2;
private CompressedContentFormat[] _precompressedFormats = new CompressedContentFormat[0];
private List<CompressedContentFormat> _precompressedFormats = new ArrayList<>();
private WelcomeFactory _welcomeFactory;
private boolean _redirectWelcome = false;
private boolean _etags = false;
private List<String> _gzipEquivalentFileExtensions;
private HttpContent.ContentFactory _contentFactory;
private final Map<String, List<String>> _preferredEncodingOrderCache = new ConcurrentHashMap<>();
private String[] _preferredEncodingOrder = new String[0];
private List<String> _preferredEncodingOrder = new ArrayList<>();
private int _encodingCacheSize = 100;
private boolean _dirAllowed = true;
private boolean _acceptRanges = true;
@ -118,7 +117,7 @@ public class ResourceService
reqRanges = null;
boolean endsWithSlash = pathInContext.endsWith(URIUtil.SLASH);
boolean checkPrecompressedVariants = _precompressedFormats.length > 0 && !endsWithSlash && reqRanges == null;
boolean checkPrecompressedVariants = _precompressedFormats.size() > 0 && !endsWithSlash && reqRanges == null;
try
{
@ -535,7 +534,7 @@ public class ResourceService
putHeaders(response, content, USE_KNOWN_CONTENT_LENGTH);
response.getHeaders().put(HttpHeader.CONTENT_RANGE,
InclusiveByteRange.to416HeaderRangeString(contentLength));
sendStatus(416, response, callback);
writeHttpError(request, response, callback, HttpStatus.RANGE_NOT_SATISFIABLE_416);
return true;
}
@ -551,7 +550,7 @@ public class ResourceService
response.getHeaders().addDateField(HttpHeader.DATE.asString(), System.currentTimeMillis());
response.getHeaders().put(HttpHeader.CONTENT_RANGE,
singleSatisfiableRange.toHeaderRangeString(contentLength));
writeContent(content, out, singleSatisfiableRange.getFirst(), singleLength);
writeHttpPartialContent(request, response, callback, content, singleSatisfiableRange);
return true;
}
@ -614,11 +613,21 @@ public class ResourceService
}
multi.close();
*/
*/
}
return true;
}
protected void writeHttpPartialContent(Request request, Response response, Callback callback, HttpContent content, InclusiveByteRange singleSatisfiableRange)
{
// TODO: implement this
}
protected void writeHttpError(Request request, Response response, Callback callback, int statusCode)
{
Response.writeError(request, response, callback, statusCode);
}
protected void writeHttpContent(Request request, Response response, Callback callback, HttpContent content)
{
try
@ -720,7 +729,7 @@ public class ResourceService
/**
* @return Precompressed resources formats that can be used to serve compressed variant of resources.
*/
public CompressedContentFormat[] getPrecompressedFormats()
public List<CompressedContentFormat> getPrecompressedFormats()
{
return _precompressedFormats;
}
@ -782,10 +791,12 @@ public class ResourceService
* @param precompressedFormats The list of precompresed formats to serve in encoded format if matching resource found.
* For example serve gzip encoded file if ".gz" suffixed resource is found.
*/
public void setPrecompressedFormats(CompressedContentFormat[] precompressedFormats)
public void setPrecompressedFormats(List<CompressedContentFormat> precompressedFormats)
{
_precompressedFormats = precompressedFormats;
_preferredEncodingOrder = stream(_precompressedFormats).map(CompressedContentFormat::getEncoding).toArray(String[]::new);
_precompressedFormats.clear();
_precompressedFormats.addAll(precompressedFormats);
_preferredEncodingOrder.clear();
_preferredEncodingOrder.addAll(_precompressedFormats.stream().map(CompressedContentFormat::getEncoding).toList());
}
public void setEncodingCacheSize(int encodingCacheSize)

View File

@ -199,7 +199,7 @@ public class ResourceHandler extends Handler.Wrapper
/**
* @return Precompressed resources formats that can be used to serve compressed variant of resources.
*/
public CompressedContentFormat[] getPrecompressedFormats()
public List<CompressedContentFormat> getPrecompressedFormats()
{
return _resourceService.getPrecompressedFormats();
}
@ -227,7 +227,6 @@ public class ResourceHandler extends Handler.Wrapper
public void setBaseResource(Resource base)
{
_resourceBase = base;
setupContentFactory();
}
/**
@ -266,7 +265,16 @@ public class ResourceHandler extends Handler.Wrapper
* @param precompressedFormats The list of precompresed formats to serve in encoded format if matching resource found.
* For example serve gzip encoded file if ".gz" suffixed resource is found.
*/
public void setPrecompressedFormats(CompressedContentFormat[] precompressedFormats)
public void setPrecompressedFormats(CompressedContentFormat... precompressedFormats)
{
setPrecompressedFormats(List.of(precompressedFormats));
}
/**
* @param precompressedFormats The list of precompresed formats to serve in encoded format if matching resource found.
* For example serve gzip encoded file if ".gz" suffixed resource is found.
*/
public void setPrecompressedFormats(List<CompressedContentFormat> precompressedFormats)
{
_resourceService.setPrecompressedFormats(precompressedFormats);
setupContentFactory();
@ -307,6 +315,11 @@ public class ResourceHandler extends Handler.Wrapper
// TODO
}
public void setWelcomeFiles(String... welcomeFiles)
{
setWelcomeFiles(List.of(welcomeFiles));
}
public void setWelcomeFiles(List<String> welcomeFiles)
{
_welcomes = welcomeFiles;

View File

@ -115,7 +115,7 @@ public class DefaultServlet extends HttpServlet
// TODO: should this come from context?
MimeTypes mimeTypes = new MimeTypes();
// TODO: this is configured further down below - see _resourceService.setPrecompressedFormats
CompressedContentFormat[] precompressedFormats = new CompressedContentFormat[0];
List<CompressedContentFormat> precompressedFormats = List.of();
_useFileMappedBuffer = getInitBoolean("useFileMappedBuffer", _useFileMappedBuffer);
ResourceContentFactory resourceContentFactory = new ResourceContentFactory(_baseResource, mimeTypes, precompressedFormats);
@ -237,7 +237,7 @@ public class DefaultServlet extends HttpServlet
IO.close(_resourceBaseMount);
}
private CompressedContentFormat[] parsePrecompressedFormats(String precompressed, Boolean gzip, CompressedContentFormat[] dft)
private List<CompressedContentFormat> parsePrecompressedFormats(String precompressed, Boolean gzip, List<CompressedContentFormat> dft)
{
if (precompressed == null && gzip == null)
{
@ -269,7 +269,7 @@ public class DefaultServlet extends HttpServlet
// gzip handling is for backwards compatibility with older Jetty
ret.add(CompressedContentFormat.GZIP);
}
return ret.toArray(new CompressedContentFormat[ret.size()]);
return ret;
}
private Boolean getInitBoolean(String name)

View File

@ -2688,11 +2688,11 @@ public class DefaultServletTest
Files.writeString(docRoot.resolve("data0.txt.bz2"), "fake bzip2", UTF_8);
ResourceService resourceService = new ResourceService();
resourceService.setPrecompressedFormats(new CompressedContentFormat[]{
resourceService.setPrecompressedFormats(List.of(
new CompressedContentFormat("bzip2", ".bz2"),
new CompressedContentFormat("gzip", ".gz"),
new CompressedContentFormat("br", ".br")
});
));
ServletHolder defholder = new ServletHolder(new DefaultServlet()); // TODO: how to integrate resource service / precompressed format
context.addServlet(defholder, "/");
defholder.setInitParameter("resourceBase", docRoot.toString());