Merge remote-tracking branch 'origin/jetty-8'
Conflicts: jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/TemplateContext.java jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/AbstractCompressedStream.java jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/CompressedResponseWrapper.java
This commit is contained in:
commit
8ff291d223
|
@ -36,6 +36,7 @@ public interface HttpContent
|
|||
String getLastModified();
|
||||
ByteBuffer getIndirectBuffer();
|
||||
ByteBuffer getDirectBuffer();
|
||||
String getETag();
|
||||
Resource getResource();
|
||||
long getContentLength();
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
@ -50,19 +51,33 @@ public interface HttpContent
|
|||
final Resource _resource;
|
||||
final String _mimeType;
|
||||
final int _maxBuffer;
|
||||
final String _etag;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType)
|
||||
{
|
||||
_resource=resource;
|
||||
_mimeType=mimeType;
|
||||
_maxBuffer=-1;
|
||||
this(resource,mimeType,-1,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType, int maxBuffer)
|
||||
{
|
||||
this(resource,mimeType,maxBuffer,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType, boolean etag)
|
||||
{
|
||||
this(resource,mimeType,-1,etag);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String mimeType, int maxBuffer, boolean etag)
|
||||
{
|
||||
_resource=resource;
|
||||
_mimeType=mimeType;
|
||||
_maxBuffer=maxBuffer;
|
||||
_etag=etag?resource.getWeakETag():null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -85,6 +100,13 @@ public interface HttpContent
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getETag()
|
||||
{
|
||||
return _etag;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
|
|
|
@ -237,6 +237,10 @@ public class HttpOutput extends ServletOutputStream
|
|||
response.getHttpFields().putDateField(HttpHeader.LAST_MODIFIED, lml);
|
||||
}
|
||||
|
||||
String etag=httpContent.getETag();
|
||||
if (etag!=null)
|
||||
response.getHttpFields().put(HttpHeader.ETAG,etag);
|
||||
|
||||
content = httpContent.getDirectBuffer();
|
||||
if (content == null)
|
||||
content = httpContent.getIndirectBuffer();
|
||||
|
|
|
@ -56,24 +56,18 @@ public class ResourceCache
|
|||
private final ResourceFactory _factory;
|
||||
private final ResourceCache _parent;
|
||||
private final MimeTypes _mimeTypes;
|
||||
private final boolean _etagSupported;
|
||||
|
||||
private boolean _useFileMappedBuffer=true;
|
||||
private int _maxCachedFileSize =4*1024*1024;
|
||||
private int _maxCachedFiles=2048;
|
||||
private int _maxCacheSize =32*1024*1024;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer)
|
||||
{
|
||||
this(parent,factory,mimeTypes);
|
||||
setUseFileMappedBuffer(useFileMappedBuffer);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param mimeTypes Mimetype to use for meta data
|
||||
*/
|
||||
public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes)
|
||||
public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags)
|
||||
{
|
||||
_factory = factory;
|
||||
_cache=new ConcurrentHashMap<String,Content>();
|
||||
|
@ -81,6 +75,7 @@ public class ResourceCache
|
|||
_cachedFiles=new AtomicInteger();
|
||||
_mimeTypes=mimeTypes;
|
||||
_parent=parent;
|
||||
_etagSupported=etags;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -247,7 +242,7 @@ public class ResourceCache
|
|||
return content;
|
||||
}
|
||||
|
||||
return new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize());
|
||||
return new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize(),_etagSupported);
|
||||
|
||||
}
|
||||
|
||||
|
@ -375,6 +370,7 @@ public class ResourceCache
|
|||
final long _lastModified;
|
||||
final ByteBuffer _lastModifiedBytes;
|
||||
final ByteBuffer _contentType;
|
||||
final String _etag;
|
||||
|
||||
volatile long _lastAccessed;
|
||||
AtomicReference<ByteBuffer> _indirectBuffer=new AtomicReference<ByteBuffer>();
|
||||
|
@ -395,6 +391,8 @@ public class ResourceCache
|
|||
_cachedSize.addAndGet(_length);
|
||||
_cachedFiles.incrementAndGet();
|
||||
_lastAccessed=System.currentTimeMillis();
|
||||
|
||||
_etag=ResourceCache.this._etagSupported?resource.getWeakETag():null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -422,11 +420,18 @@ public class ResourceCache
|
|||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getETag()
|
||||
{
|
||||
return _etag;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
boolean isValid()
|
||||
{
|
||||
if (_lastModified==_resource.lastModified())
|
||||
if (_lastModified==_resource.lastModified() && _length==_resource.length())
|
||||
{
|
||||
_lastAccessed=System.currentTimeMillis();
|
||||
return true;
|
||||
|
|
|
@ -66,6 +66,7 @@ public class ResourceHandler extends HandlerWrapper
|
|||
String _cacheControl;
|
||||
boolean _aliases;
|
||||
boolean _directory;
|
||||
boolean _etags;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceHandler()
|
||||
|
@ -125,6 +126,24 @@ public class ResourceHandler extends HandlerWrapper
|
|||
_directory = directory;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if ETag processing is done
|
||||
*/
|
||||
public boolean isEtags()
|
||||
{
|
||||
return _etags;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param etags True if ETag processing is done
|
||||
*/
|
||||
public void setEtags(boolean etags)
|
||||
{
|
||||
_etags = etags;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void doStart()
|
||||
|
@ -417,6 +436,21 @@ public class ResourceHandler extends HandlerWrapper
|
|||
|
||||
// set some headers
|
||||
long last_modified=resource.lastModified();
|
||||
String etag=null;
|
||||
if (_etags)
|
||||
{
|
||||
// simple handling of only a single etag
|
||||
String ifnm = request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
|
||||
etag=resource.getWeakETag();
|
||||
if (ifnm!=null && resource!=null && ifnm.equals(etag))
|
||||
{
|
||||
response.setStatus(HttpStatus.NOT_MODIFIED_304);
|
||||
baseRequest.getResponse().getHttpFields().put(HttpHeader.ETAG,etag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (last_modified>0)
|
||||
{
|
||||
long if_modified=request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
|
||||
|
@ -434,6 +468,9 @@ public class ResourceHandler extends HandlerWrapper
|
|||
// set the headers
|
||||
doResponseHeaders(response,resource,mime!=null?mime.toString():null);
|
||||
response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),last_modified);
|
||||
if (_etags)
|
||||
baseRequest.getResponse().getHttpFields().put(HttpHeader.ETAG,etag);
|
||||
|
||||
if(skipContentBody)
|
||||
return;
|
||||
// Send the content
|
||||
|
|
|
@ -47,9 +47,9 @@ public class ResourceCacheTest
|
|||
Resource[] r = rc.getResources();
|
||||
MimeTypes mime = new MimeTypes();
|
||||
|
||||
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false);
|
||||
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false);
|
||||
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false);
|
||||
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false);
|
||||
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false);
|
||||
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false);
|
||||
|
||||
assertEquals("1 - one", getContent(rc1, "1.txt"));
|
||||
assertEquals("2 - two", getContent(rc1, "2.txt"));
|
||||
|
@ -77,8 +77,8 @@ public class ResourceCacheTest
|
|||
Resource[] r = rc.getResources();
|
||||
MimeTypes mime = new MimeTypes();
|
||||
|
||||
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false);
|
||||
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false)
|
||||
ResourceCache rc3 = new ResourceCache(null,r[2],mime,false,false);
|
||||
ResourceCache rc2 = new ResourceCache(rc3,r[1],mime,false,false)
|
||||
{
|
||||
@Override
|
||||
public boolean isCacheable(Resource resource)
|
||||
|
@ -87,7 +87,7 @@ public class ResourceCacheTest
|
|||
}
|
||||
};
|
||||
|
||||
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false);
|
||||
ResourceCache rc1 = new ResourceCache(rc2,r[0],mime,false,false);
|
||||
|
||||
assertEquals("1 - one", getContent(rc1, "1.txt"));
|
||||
assertEquals("2 - two", getContent(rc1, "2.txt"));
|
||||
|
@ -127,7 +127,7 @@ public class ResourceCacheTest
|
|||
directory=Resource.newResource(files[0].getParentFile().getAbsolutePath());
|
||||
|
||||
|
||||
cache=new ResourceCache(null,directory,new MimeTypes(),false);
|
||||
cache=new ResourceCache(null,directory,new MimeTypes(),false,false);
|
||||
|
||||
cache.setMaxCacheSize(95);
|
||||
cache.setMaxCachedFileSize(85);
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.io.OutputStream;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -53,6 +52,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.MultiPartOutputStream;
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -111,6 +111,8 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
|
|||
*
|
||||
* aliases If True, aliases of resources are allowed (eg. symbolic
|
||||
* links and caps variations). May bypass security constraints.
|
||||
*
|
||||
* etags If True, weak etags will be generated and handled.
|
||||
*
|
||||
* maxCacheSize The maximum total size of the cache or 0 for no cache.
|
||||
* maxCachedFileSize The maximum size of a file to cache
|
||||
|
@ -147,6 +149,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
private boolean _redirectWelcome=false;
|
||||
private boolean _gzip=true;
|
||||
private boolean _pathInfoOnly=false;
|
||||
private boolean _etags=false;
|
||||
|
||||
private Resource _resourceBase;
|
||||
private ResourceCache _cache;
|
||||
|
@ -255,11 +258,13 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
LOG.debug("Cache {}={}",resourceCache,_cache);
|
||||
}
|
||||
|
||||
_etags = getInitBoolean("etags",_etags);
|
||||
|
||||
try
|
||||
{
|
||||
if (_cache==null && max_cached_files>0)
|
||||
{
|
||||
_cache= new ResourceCache(null,this,_mimeTypes,_useFileMappedBuffer);
|
||||
_cache= new ResourceCache(null,this,_mimeTypes,_useFileMappedBuffer,_etags);
|
||||
|
||||
if (max_cache_size>0)
|
||||
_cache.setMaxCacheSize(max_cache_size);
|
||||
|
@ -280,6 +285,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
if (h.getServletInstance()==this)
|
||||
_defaultHolder=h;
|
||||
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("resource base = "+_resourceBase);
|
||||
}
|
||||
|
@ -492,7 +498,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
{
|
||||
// ensure we have content
|
||||
if (content==null)
|
||||
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),response.getBufferSize());
|
||||
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),response.getBufferSize(),_etags);
|
||||
|
||||
if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
|
||||
{
|
||||
|
@ -563,7 +569,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
}
|
||||
else
|
||||
{
|
||||
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()));
|
||||
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),_etags);
|
||||
if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
|
||||
sendDirectory(request,response,resource,pathInContext);
|
||||
}
|
||||
|
@ -665,6 +671,77 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
{
|
||||
if (!HttpMethod.HEAD.is(request.getMethod()))
|
||||
{
|
||||
if (_etags)
|
||||
{
|
||||
String ifm=request.getHeader(HttpHeader.IF_MATCH.asString());
|
||||
if (ifm!=null)
|
||||
{
|
||||
boolean match=false;
|
||||
if (content!=null && content.getETag()!=null)
|
||||
{
|
||||
QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifm,", ",false,true);
|
||||
while (!match && quoted.hasMoreTokens())
|
||||
{
|
||||
String tag = quoted.nextToken();
|
||||
if (content.getETag().toString().equals(tag))
|
||||
match=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
{
|
||||
Response r = Response.getResponse(response);
|
||||
r.reset(true);
|
||||
r.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String ifnm=request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
|
||||
if (ifnm!=null && content!=null && content.getETag()!=null)
|
||||
{
|
||||
// Look for GzipFiltered version of etag
|
||||
if (content.getETag().toString().equals(request.getAttribute("o.e.j.s.GzipFilter.ETag")))
|
||||
{
|
||||
Response r = Response.getResponse(response);
|
||||
r.reset(true);
|
||||
r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
r.getHttpFields().put(HttpHeader.ETAG,ifnm);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Handle special case of exact match.
|
||||
if (content.getETag().toString().equals(ifnm))
|
||||
{
|
||||
Response r = Response.getResponse(response);
|
||||
r.reset(true);
|
||||
r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
r.getHttpFields().put(HttpHeader.ETAG,content.getETag());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle list of tags
|
||||
QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifnm,", ",false,true);
|
||||
while (quoted.hasMoreTokens())
|
||||
{
|
||||
String tag = quoted.nextToken();
|
||||
if (content.getETag().toString().equals(tag))
|
||||
{
|
||||
Response r = Response.getResponse(response);
|
||||
r.reset(true);
|
||||
r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
r.getHttpFields().put(HttpHeader.ETAG,content.getETag());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If etag requires content to be served, then do not check if-modified-since
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle if modified since
|
||||
String ifms=request.getHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
|
||||
if (ifms!=null)
|
||||
{
|
||||
|
@ -964,7 +1041,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
/* ------------------------------------------------------------ */
|
||||
protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
|
||||
throws IOException
|
||||
{
|
||||
{
|
||||
if (content.getContentType()!=null && response.getContentType()==null)
|
||||
response.setContentType(content.getContentType().toString());
|
||||
|
||||
|
@ -986,6 +1063,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
r.setLongContentLength(count);
|
||||
|
||||
writeOptionHeaders(fields);
|
||||
|
||||
if (_etags)
|
||||
fields.put(HttpHeader.ETAG,content.getETag());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1002,11 +1082,14 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
}
|
||||
|
||||
writeOptionHeaders(response);
|
||||
|
||||
if (_etags)
|
||||
response.setHeader(HttpHeader.ETAG.asString(),content.getETag().toString());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void writeOptionHeaders(HttpFields fields) throws IOException
|
||||
protected void writeOptionHeaders(HttpFields fields)
|
||||
{
|
||||
if (_acceptRanges)
|
||||
fields.put(HttpHeader.ACCEPT_RANGES,"bytes");
|
||||
|
@ -1016,7 +1099,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void writeOptionHeaders(HttpServletResponse response) throws IOException
|
||||
protected void writeOptionHeaders(HttpServletResponse response)
|
||||
{
|
||||
if (_acceptRanges)
|
||||
response.setHeader(HttpHeader.ACCEPT_RANGES.asString(),"bytes");
|
||||
|
@ -1024,8 +1107,6 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
if (_cacheControl!=null)
|
||||
response.setHeader(HttpHeader.CACHE_CONTROL.asString(),_cacheControl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
|
|
|
@ -23,6 +23,8 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import javax.servlet.DispatcherType;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
@ -30,12 +32,14 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.OS;
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.eclipse.jetty.util.DateCache;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
|
@ -495,6 +499,123 @@ public class DefaultServletTest
|
|||
assertResponseNotContains("Content-Length: 12", response);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIfModifiedSmall() throws Exception
|
||||
{
|
||||
testIfModified("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfModifiedLarge() throws Exception
|
||||
{
|
||||
testIfModified("Now is the time for all good men to come to the aid of the party");
|
||||
}
|
||||
|
||||
public void testIfModified(String content) throws Exception
|
||||
{
|
||||
testdir.ensureEmpty();
|
||||
File resBase = testdir.getFile("docroot");
|
||||
FS.ensureDirExists(resBase);
|
||||
File file = new File(resBase, "file.txt");
|
||||
|
||||
String resBasePath = resBase.getAbsolutePath();
|
||||
|
||||
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
|
||||
defholder.setInitParameter("resourceBase", resBasePath);
|
||||
defholder.setInitParameter("maxCacheSize", "4096");
|
||||
defholder.setInitParameter("maxCachedFileSize", "25");
|
||||
defholder.setInitParameter("maxCachedFiles", "100");
|
||||
|
||||
String response = connector.getResponses("GET /context/file.txt HTTP/1.0\r\n\r\n");
|
||||
assertResponseContains("404", response);
|
||||
|
||||
createFile(file, content);
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\n\r\n");
|
||||
|
||||
assertResponseContains("200", response);
|
||||
assertResponseContains("Last-Modified", response);
|
||||
String last_modified = getHeaderValue("Last-Modified",response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Modified-Since: "+last_modified+"\r\n\r\n");
|
||||
assertResponseContains("304", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Modified-Since: "+HttpFields.formatDate(System.currentTimeMillis()-10000)+"\r\n\r\n");
|
||||
assertResponseContains("200", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Modified-Since: "+HttpFields.formatDate(System.currentTimeMillis()+10000)+"\r\n\r\n");
|
||||
assertResponseContains("304", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Unmodified-Since: "+HttpFields.formatDate(System.currentTimeMillis()+10000)+"\r\n\r\n");
|
||||
assertResponseContains("200", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Unmodified-Since: "+HttpFields.formatDate(System.currentTimeMillis()-10000)+"\r\n\r\n");
|
||||
assertResponseContains("412", response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfETagSmall() throws Exception
|
||||
{
|
||||
testIfETag("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfETagLarge() throws Exception
|
||||
{
|
||||
testIfETag("Now is the time for all good men to come to the aid of the party");
|
||||
}
|
||||
|
||||
public void testIfETag(String content) throws Exception
|
||||
{
|
||||
testdir.ensureEmpty();
|
||||
File resBase = testdir.getFile("docroot");
|
||||
FS.ensureDirExists(resBase);
|
||||
File file = new File(resBase, "file.txt");
|
||||
|
||||
String resBasePath = resBase.getAbsolutePath();
|
||||
|
||||
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
|
||||
defholder.setInitParameter("resourceBase", resBasePath);
|
||||
defholder.setInitParameter("maxCacheSize", "4096");
|
||||
defholder.setInitParameter("maxCachedFileSize", "25");
|
||||
defholder.setInitParameter("maxCachedFiles", "100");
|
||||
defholder.setInitParameter("etags", "true");
|
||||
|
||||
String response;
|
||||
|
||||
createFile(file, content);
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\n\r\n");
|
||||
|
||||
assertResponseContains("200", response);
|
||||
assertResponseContains("ETag", response);
|
||||
String etag = getHeaderValue("ETag",response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: "+etag+"\r\n\r\n");
|
||||
assertResponseContains("304", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: wibble,"+etag+",wobble\r\n\r\n");
|
||||
assertResponseContains("304", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: wibble\r\n\r\n");
|
||||
assertResponseContains("200", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-None-Match: wibble, wobble\r\n\r\n");
|
||||
assertResponseContains("200", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: "+etag+"\r\n\r\n");
|
||||
assertResponseContains("200", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: wibble,"+etag+",wobble\r\n\r\n");
|
||||
assertResponseContains("200", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: wibble\r\n\r\n");
|
||||
assertResponseContains("412", response);
|
||||
|
||||
response = connector.getResponses("GET /context/file.txt HTTP/1.1\r\nHost:test\r\nConnection:close\r\nIf-Match: wibble, wobble\r\n\r\n");
|
||||
assertResponseContains("412", response);
|
||||
|
||||
}
|
||||
|
||||
public static class OutputFilter implements Filter
|
||||
{
|
||||
@Override
|
||||
|
@ -583,4 +704,13 @@ public class DefaultServletTest
|
|||
Assert.assertTrue("Deleting: " + file.getName(), file.delete());
|
||||
}
|
||||
}
|
||||
|
||||
private String getHeaderValue(String header, String response)
|
||||
{
|
||||
Pattern pattern=Pattern.compile("[\\r\\n]"+header+"\\s*:\\s*(.*?)\\s*[\\r\\n]");
|
||||
Matcher matcher = pattern.matcher(response);
|
||||
if (matcher.find())
|
||||
return matcher.group(1);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,8 +105,10 @@ public class GzipFilter extends UserAgentFilter
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(GzipFilter.class);
|
||||
public final static String GZIP="gzip";
|
||||
public final static String ETAG_GZIP="-gzip\"";
|
||||
public final static String DEFLATE="deflate";
|
||||
|
||||
public final static String ETAG_DEFLATE="-deflate\"";
|
||||
public final static String ETAG="o.e.j.s.GzipFilter.ETag";
|
||||
|
||||
protected Set<String> _mimeTypes;
|
||||
protected int _bufferSize=8192;
|
||||
|
@ -234,6 +236,16 @@ public class GzipFilter extends UserAgentFilter
|
|||
return;
|
||||
}
|
||||
|
||||
// Special handling for etags
|
||||
String etag = request.getHeader("If-None-Match");
|
||||
if (etag!=null)
|
||||
{
|
||||
if (etag.endsWith(ETAG_GZIP))
|
||||
request.setAttribute(ETAG,etag.substring(0,etag.length()-ETAG_GZIP.length())+'"');
|
||||
else if (etag.endsWith(ETAG_DEFLATE))
|
||||
request.setAttribute(ETAG,etag.substring(0,etag.length()-ETAG_DEFLATE.length())+'"');
|
||||
}
|
||||
|
||||
CompressedResponseWrapper wrappedResponse = createWrappedResponse(request,response,compressionType);
|
||||
|
||||
boolean exceptional=true;
|
||||
|
@ -361,9 +373,9 @@ public class GzipFilter extends UserAgentFilter
|
|||
wrappedResponse = new CompressedResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
return new AbstractCompressedStream(compressionType,request,this)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
|
@ -379,9 +391,9 @@ public class GzipFilter extends UserAgentFilter
|
|||
wrappedResponse = new CompressedResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
return new AbstractCompressedStream(compressionType,request,this)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
|
@ -416,6 +428,7 @@ public class GzipFilter extends UserAgentFilter
|
|||
this.wrappedResponse = wrappedResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(Continuation continuation)
|
||||
{
|
||||
try
|
||||
|
@ -428,6 +441,7 @@ public class GzipFilter extends UserAgentFilter
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout(Continuation continuation)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -74,9 +74,9 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
wrappedResponse = new IncludableResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
return new AbstractCompressedStream(compressionType,request,this)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
|
@ -101,9 +101,9 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
wrappedResponse = new IncludableResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
return new AbstractCompressedStream(compressionType,request,this)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
|
|
|
@ -39,43 +39,26 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
|||
public abstract class AbstractCompressedStream extends ServletOutputStream
|
||||
{
|
||||
private final String _encoding;
|
||||
protected HttpServletRequest _request;
|
||||
protected HttpServletResponse _response;
|
||||
protected final CompressedResponseWrapper _wrapper;
|
||||
protected final HttpServletResponse _response;
|
||||
protected OutputStream _out;
|
||||
protected ByteArrayOutputStream2 _bOut;
|
||||
protected DeflaterOutputStream _compressedOutputStream;
|
||||
protected boolean _closed;
|
||||
protected int _bufferSize;
|
||||
protected int _minCompressSize;
|
||||
protected long _contentLength;
|
||||
protected boolean _doNotCompress;
|
||||
|
||||
/**
|
||||
* Instantiates a new compressed stream.
|
||||
*
|
||||
* @param request
|
||||
* the request
|
||||
* @param response
|
||||
* the response
|
||||
* @param contentLength
|
||||
* the content length
|
||||
* @param bufferSize
|
||||
* the buffer size
|
||||
* @param minCompressSize
|
||||
* the min compress size
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public AbstractCompressedStream(String encoding,HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minCompressSize)
|
||||
public AbstractCompressedStream(String encoding,HttpServletRequest request, CompressedResponseWrapper wrapper)
|
||||
throws IOException
|
||||
{
|
||||
_encoding=encoding;
|
||||
_request = request;
|
||||
_response = response;
|
||||
_contentLength = contentLength;
|
||||
_bufferSize = bufferSize;
|
||||
_minCompressSize = minCompressSize;
|
||||
if (minCompressSize == 0)
|
||||
_wrapper = wrapper;
|
||||
_response = (HttpServletResponse)wrapper.getResponse();
|
||||
|
||||
if (_wrapper.getMinCompressSize()==0)
|
||||
doCompress();
|
||||
}
|
||||
|
||||
|
@ -95,21 +78,19 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
_doNotCompress = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content length.
|
||||
*
|
||||
* @param length
|
||||
* the new content length
|
||||
*/
|
||||
public void setContentLength(long length)
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setContentLength()
|
||||
{
|
||||
_contentLength = length;
|
||||
if (_doNotCompress && length >= 0)
|
||||
if (_doNotCompress)
|
||||
{
|
||||
if (_contentLength < Integer.MAX_VALUE)
|
||||
_response.setContentLength((int)_contentLength);
|
||||
else
|
||||
_response.setHeader("Content-Length",Long.toString(_contentLength));
|
||||
long length=_wrapper.getContentLength();
|
||||
if (length>=0)
|
||||
{
|
||||
if (length < Integer.MAX_VALUE)
|
||||
_response.setContentLength((int)length);
|
||||
else
|
||||
_response.setHeader("Content-Length",Long.toString(length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +103,8 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
{
|
||||
if (_out == null || _bOut != null)
|
||||
{
|
||||
if (_contentLength > 0 && _contentLength < _minCompressSize)
|
||||
long length=_wrapper.getContentLength();
|
||||
if (length > 0 && length < _wrapper.getMinCompressSize())
|
||||
doNotCompress();
|
||||
else
|
||||
doCompress();
|
||||
|
@ -141,15 +123,19 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
if (_closed)
|
||||
return;
|
||||
|
||||
if (_request.getAttribute("javax.servlet.include.request_uri") != null)
|
||||
if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null)
|
||||
flush();
|
||||
else
|
||||
{
|
||||
if (_bOut != null)
|
||||
{
|
||||
if (_contentLength < 0)
|
||||
_contentLength = _bOut.getCount();
|
||||
if (_contentLength < _minCompressSize)
|
||||
long length=_wrapper.getContentLength();
|
||||
if (length < 0)
|
||||
{
|
||||
length = _bOut.getCount();
|
||||
_wrapper.setContentLength(length);
|
||||
}
|
||||
if (length < _wrapper.getMinCompressSize())
|
||||
doNotCompress();
|
||||
else
|
||||
doCompress();
|
||||
|
@ -179,7 +165,8 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
{
|
||||
if (_out == null || _bOut != null)
|
||||
{
|
||||
if (_contentLength > 0 && _contentLength < _minCompressSize)
|
||||
long length=_wrapper.getContentLength();
|
||||
if (length > 0 && length < _wrapper.getMinCompressSize())
|
||||
doNotCompress();
|
||||
else
|
||||
doCompress();
|
||||
|
@ -248,6 +235,10 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
_out.write(_bOut.getBuf(),0,_bOut.getCount());
|
||||
_bOut=null;
|
||||
}
|
||||
|
||||
String etag=_wrapper.getETag();
|
||||
if (etag!=null)
|
||||
setHeader("ETag",etag.substring(0,etag.length()-1)+'-'+_encoding+'"');
|
||||
}
|
||||
else
|
||||
doNotCompress();
|
||||
|
@ -266,10 +257,13 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
throw new IllegalStateException("Compressed output stream is already assigned.");
|
||||
if (_out == null || _bOut != null)
|
||||
{
|
||||
if (_wrapper.getETag()!=null)
|
||||
setHeader("ETag",_wrapper.getETag());
|
||||
|
||||
_doNotCompress = true;
|
||||
|
||||
_out = _response.getOutputStream();
|
||||
setContentLength(_contentLength);
|
||||
setContentLength();
|
||||
|
||||
if (_bOut != null)
|
||||
_out.write(_bOut.getBuf(),0,_bOut.getCount());
|
||||
|
@ -280,30 +274,32 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
/**
|
||||
* Check out.
|
||||
*
|
||||
* @param length
|
||||
* @param lengthToWrite
|
||||
* the length
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
private void checkOut(int length) throws IOException
|
||||
private void checkOut(int lengthToWrite) throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new IOException("CLOSED");
|
||||
|
||||
if (_out == null)
|
||||
{
|
||||
if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
|
||||
long length=_wrapper.getContentLength();
|
||||
if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
|
||||
doNotCompress();
|
||||
else if (length > _minCompressSize)
|
||||
else if (lengthToWrite > _wrapper.getMinCompressSize())
|
||||
doCompress();
|
||||
else
|
||||
_out = _bOut = new ByteArrayOutputStream2(_bufferSize);
|
||||
_out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize());
|
||||
}
|
||||
else if (_bOut != null)
|
||||
{
|
||||
if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
|
||||
long length=_wrapper.getContentLength();
|
||||
if (_response.isCommitted() || (length >= 0 && length < _wrapper.getMinCompressSize()))
|
||||
doNotCompress();
|
||||
else if (length >= (_bOut.getBuf().length - _bOut.getCount()))
|
||||
else if (lengthToWrite >= (_bOut.getBuf().length - _bOut.getCount()))
|
||||
doCompress();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,15 +47,48 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
|
||||
private PrintWriter _writer;
|
||||
private AbstractCompressedStream _compressedStream;
|
||||
private String _etag;
|
||||
private long _contentLength=-1;
|
||||
private boolean _noCompression;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public CompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
super(response);
|
||||
_request = request;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public long getContentLength()
|
||||
{
|
||||
return _contentLength;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getBufferSize()
|
||||
{
|
||||
return _bufferSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMinCompressSize()
|
||||
{
|
||||
return _minCompressSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getETag()
|
||||
{
|
||||
return _etag;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpServletRequest getRequest()
|
||||
{
|
||||
return _request;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#setMimeTypes(java.util.Set)
|
||||
|
@ -147,7 +180,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
{
|
||||
_contentLength=length;
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.setContentLength(length);
|
||||
_compressedStream.setContentLength();
|
||||
else if (_noCompression && _contentLength>=0)
|
||||
{
|
||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
||||
|
@ -161,7 +194,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#addHeader(java.lang.String, java.lang.String)
|
||||
|
@ -173,7 +206,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
{
|
||||
_contentLength=Long.parseLong(value);
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.setContentLength(_contentLength);
|
||||
_compressedStream.setContentLength();
|
||||
}
|
||||
else if ("content-type".equalsIgnoreCase(name))
|
||||
{
|
||||
|
@ -187,6 +220,8 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
noCompression();
|
||||
}
|
||||
}
|
||||
else if ("etag".equalsIgnoreCase(name))
|
||||
_etag=value;
|
||||
else
|
||||
super.addHeader(name,value);
|
||||
}
|
||||
|
@ -324,10 +359,21 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
noCompression();
|
||||
}
|
||||
}
|
||||
else if ("etag".equalsIgnoreCase(name))
|
||||
_etag=value;
|
||||
else
|
||||
super.setHeader(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public boolean containsHeader(String name)
|
||||
{
|
||||
if ("etag".equalsIgnoreCase(name) && _etag!=null)
|
||||
return true;
|
||||
return super.containsHeader(name);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper#getOutputStream()
|
||||
|
@ -343,7 +389,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
return getResponse().getOutputStream();
|
||||
}
|
||||
|
||||
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
|
||||
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
|
||||
}
|
||||
else if (_writer!=null)
|
||||
throw new IllegalStateException("getWriter() called");
|
||||
|
@ -369,7 +415,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
return getResponse().getWriter();
|
||||
}
|
||||
|
||||
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
|
||||
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
|
||||
_writer=newWriter(_compressedStream,getCharacterEncoding());
|
||||
}
|
||||
return _writer;
|
||||
|
@ -386,7 +432,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
{
|
||||
_contentLength=value;
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.setContentLength(_contentLength);
|
||||
_compressedStream.setContentLength();
|
||||
}
|
||||
else
|
||||
super.setIntHeader(name,value);
|
||||
|
@ -410,6 +456,6 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
|
|||
/**
|
||||
*@return the underlying CompressedStream implementation
|
||||
*/
|
||||
protected abstract AbstractCompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response, long _contentLength2, int _bufferSize2, int _minCompressedSize2) throws IOException;
|
||||
protected abstract AbstractCompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response) throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -293,9 +293,9 @@ public class GzipHandler extends HandlerWrapper
|
|||
}
|
||||
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream("gzip",request,response,contentLength,bufferSize,minCompressSize)
|
||||
return new AbstractCompressedStream("gzip",request,this)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
|
||||
|
@ -33,8 +34,8 @@ import java.io.UnsupportedEncodingException;
|
|||
public class B64Code
|
||||
{
|
||||
// ------------------------------------------------------------------
|
||||
static final char pad='=';
|
||||
static final char[] rfc1421alphabet=
|
||||
static final char __pad='=';
|
||||
static final char[] __rfc1421alphabet=
|
||||
{
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||
|
@ -42,16 +43,16 @@ public class B64Code
|
|||
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
|
||||
};
|
||||
|
||||
static final byte[] rfc1421nibbles;
|
||||
static final byte[] __rfc1421nibbles;
|
||||
|
||||
static
|
||||
{
|
||||
rfc1421nibbles=new byte[256];
|
||||
__rfc1421nibbles=new byte[256];
|
||||
for (int i=0;i<256;i++)
|
||||
rfc1421nibbles[i]=-1;
|
||||
__rfc1421nibbles[i]=-1;
|
||||
for (byte b=0;b<64;b++)
|
||||
rfc1421nibbles[(byte)rfc1421alphabet[b]]=b;
|
||||
rfc1421nibbles[(byte)pad]=0;
|
||||
__rfc1421nibbles[(byte)__rfc1421alphabet[b]]=b;
|
||||
__rfc1421nibbles[(byte)__pad]=0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
@ -104,7 +105,54 @@ public class B64Code
|
|||
*/
|
||||
static public char[] encode(byte[] b)
|
||||
{
|
||||
return encode(b,false);
|
||||
if (b==null)
|
||||
return null;
|
||||
|
||||
int bLen=b.length;
|
||||
int cLen=((bLen+2)/3)*4;
|
||||
char c[]=new char[cLen];
|
||||
int ci=0;
|
||||
int bi=0;
|
||||
byte b0, b1, b2;
|
||||
int stop=(bLen/3)*3;
|
||||
while (bi<stop)
|
||||
{
|
||||
b0=b[bi++];
|
||||
b1=b[bi++];
|
||||
b2=b[bi++];
|
||||
c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
|
||||
c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03];
|
||||
c[ci++]=__rfc1421alphabet[b2&077];
|
||||
}
|
||||
|
||||
if (bLen!=bi)
|
||||
{
|
||||
switch (bLen%3)
|
||||
{
|
||||
case 2:
|
||||
b0=b[bi++];
|
||||
b1=b[bi++];
|
||||
c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
|
||||
c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f];
|
||||
c[ci++]=__pad;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
b0=b[bi++];
|
||||
c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f];
|
||||
c[ci++]=__pad;
|
||||
c[ci++]=__pad;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
@ -120,11 +168,12 @@ public class B64Code
|
|||
{
|
||||
if (b==null)
|
||||
return null;
|
||||
if (!rfc2045)
|
||||
return encode(b);
|
||||
|
||||
int bLen=b.length;
|
||||
int cLen=((bLen+2)/3)*4;
|
||||
if (rfc2045)
|
||||
cLen+=2+2*cLen/76;
|
||||
cLen+=2+2*(cLen/76);
|
||||
char c[]=new char[cLen];
|
||||
int ci=0;
|
||||
int bi=0;
|
||||
|
@ -136,12 +185,12 @@ public class B64Code
|
|||
b0=b[bi++];
|
||||
b1=b[bi++];
|
||||
b2=b[bi++];
|
||||
c[ci++]=rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
|
||||
c[ci++]=rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03];
|
||||
c[ci++]=rfc1421alphabet[b2&077];
|
||||
c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
|
||||
c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f|(b2>>>6)&0x03];
|
||||
c[ci++]=__rfc1421alphabet[b2&077];
|
||||
l+=4;
|
||||
if (rfc2045 && l%76==0)
|
||||
if (l%76==0)
|
||||
{
|
||||
c[ci++]=13;
|
||||
c[ci++]=10;
|
||||
|
@ -155,18 +204,18 @@ public class B64Code
|
|||
case 2:
|
||||
b0=b[bi++];
|
||||
b1=b[bi++];
|
||||
c[ci++]=rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
|
||||
c[ci++]=rfc1421alphabet[(b1<<2)&0x3f];
|
||||
c[ci++]=pad;
|
||||
c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f|(b1>>>4)&0x0f];
|
||||
c[ci++]=__rfc1421alphabet[(b1<<2)&0x3f];
|
||||
c[ci++]=__pad;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
b0=b[bi++];
|
||||
c[ci++]=rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=rfc1421alphabet[(b0<<4)&0x3f];
|
||||
c[ci++]=pad;
|
||||
c[ci++]=pad;
|
||||
c[ci++]=__rfc1421alphabet[(b0>>>2)&0x3f];
|
||||
c[ci++]=__rfc1421alphabet[(b0<<4)&0x3f];
|
||||
c[ci++]=__pad;
|
||||
c[ci++]=__pad;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -174,11 +223,8 @@ public class B64Code
|
|||
}
|
||||
}
|
||||
|
||||
if (rfc2045)
|
||||
{
|
||||
c[ci++]=13;
|
||||
c[ci++]=10;
|
||||
}
|
||||
c[ci++]=13;
|
||||
c[ci++]=10;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -226,7 +272,7 @@ public class B64Code
|
|||
throw new IllegalArgumentException("Input block size is not 4");
|
||||
|
||||
int li=bLen-1;
|
||||
while (li>=0 && b[li]==(byte)pad)
|
||||
while (li>=0 && b[li]==(byte)__pad)
|
||||
li--;
|
||||
|
||||
if (li<0)
|
||||
|
@ -243,10 +289,10 @@ public class B64Code
|
|||
{
|
||||
while (ri<stop)
|
||||
{
|
||||
b0=rfc1421nibbles[b[bi++]];
|
||||
b1=rfc1421nibbles[b[bi++]];
|
||||
b2=rfc1421nibbles[b[bi++]];
|
||||
b3=rfc1421nibbles[b[bi++]];
|
||||
b0=__rfc1421nibbles[b[bi++]];
|
||||
b1=__rfc1421nibbles[b[bi++]];
|
||||
b2=__rfc1421nibbles[b[bi++]];
|
||||
b3=__rfc1421nibbles[b[bi++]];
|
||||
if (b0<0 || b1<0 || b2<0 || b3<0)
|
||||
throw new IllegalArgumentException("Not B64 encoded");
|
||||
|
||||
|
@ -260,9 +306,9 @@ public class B64Code
|
|||
switch (rLen%3)
|
||||
{
|
||||
case 2:
|
||||
b0=rfc1421nibbles[b[bi++]];
|
||||
b1=rfc1421nibbles[b[bi++]];
|
||||
b2=rfc1421nibbles[b[bi++]];
|
||||
b0=__rfc1421nibbles[b[bi++]];
|
||||
b1=__rfc1421nibbles[b[bi++]];
|
||||
b2=__rfc1421nibbles[b[bi++]];
|
||||
if (b0<0 || b1<0 || b2<0)
|
||||
throw new IllegalArgumentException("Not B64 encoded");
|
||||
r[ri++]=(byte)(b0<<2|b1>>>4);
|
||||
|
@ -270,8 +316,8 @@ public class B64Code
|
|||
break;
|
||||
|
||||
case 1:
|
||||
b0=rfc1421nibbles[b[bi++]];
|
||||
b1=rfc1421nibbles[b[bi++]];
|
||||
b0=__rfc1421nibbles[b[bi++]];
|
||||
b1=__rfc1421nibbles[b[bi++]];
|
||||
if (b0<0 || b1<0)
|
||||
throw new IllegalArgumentException("Not B64 encoded");
|
||||
r[ri++]=(byte)(b0<<2|b1>>>4);
|
||||
|
@ -314,17 +360,17 @@ public class B64Code
|
|||
{
|
||||
char c=encoded.charAt(ci++);
|
||||
|
||||
if (c==pad)
|
||||
if (c==__pad)
|
||||
break;
|
||||
|
||||
if (Character.isWhitespace(c))
|
||||
continue;
|
||||
|
||||
byte nibble=rfc1421nibbles[c];
|
||||
byte nibble=__rfc1421nibbles[c];
|
||||
if (nibble<0)
|
||||
throw new IllegalArgumentException("Not B64 encoded");
|
||||
|
||||
nibbles[s++]=rfc1421nibbles[c];
|
||||
nibbles[s++]=__rfc1421nibbles[c];
|
||||
|
||||
switch(s)
|
||||
{
|
||||
|
@ -346,4 +392,36 @@ public class B64Code
|
|||
|
||||
return bout.toByteArray();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void encode(int value,Appendable buf) throws IOException
|
||||
{
|
||||
buf.append(__rfc1421alphabet[0x3f&((0xFC000000&value)>>26)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x03F00000&value)>>20)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x000FC000&value)>>14)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x00003F00&value)>>8)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x000000FC&value)>>2)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x00000003&value)<<4)]);
|
||||
buf.append('=');
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void encode(long lvalue,Appendable buf) throws IOException
|
||||
{
|
||||
int value=(int)(0xFFFFFFFC&(lvalue>>32));
|
||||
buf.append(__rfc1421alphabet[0x3f&((0xFC000000&value)>>26)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x03F00000&value)>>20)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x000FC000&value)>>14)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x00003F00&value)>>8)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x000000FC&value)>>2)]);
|
||||
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x00000003&value)<<4) + (0xf&(int)(lvalue>>28))]);
|
||||
|
||||
value=0x0FFFFFFF&(int)lvalue;
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x0FC00000&value)>>22)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x003F0000&value)>>16)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x0000FC00&value)>>10)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x000003F0&value)>>4)]);
|
||||
buf.append(__rfc1421alphabet[0x3f&((0x0000000F&value)<<2)]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -369,15 +369,10 @@ public class TypeUtil
|
|||
{
|
||||
try
|
||||
{
|
||||
int bi=0xff&b;
|
||||
int c='0'+(bi/16)%16;
|
||||
if (c>'9')
|
||||
c= 'A'+(c-'0'-10);
|
||||
buf.append((char)c);
|
||||
c='0'+bi%16;
|
||||
if (c>'9')
|
||||
c= 'A'+(c-'0'-10);
|
||||
buf.append((char)c);
|
||||
int d=0xf&((0xF0&b)>>4);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&b;
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
|
@ -385,6 +380,37 @@ public class TypeUtil
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void toHex(int value,Appendable buf) throws IOException
|
||||
{
|
||||
int d=0xf&((0xF0000000&value)>>28);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&((0x0F000000&value)>>24);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&((0x00F00000&value)>>20);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&((0x000F0000&value)>>16);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&((0x0000F000&value)>>12);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&((0x00000F00&value)>>8);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&((0x000000F0&value)>>4);
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
d=0xf&value;
|
||||
buf.append((char)((d>9?('A'-10):'0')+d));
|
||||
|
||||
Integer.toString(0,36);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void toHex(long value,Appendable buf) throws IOException
|
||||
{
|
||||
toHex((int)(value>>32),buf);
|
||||
toHex((int)value,buf);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static String toHexString(byte b)
|
||||
{
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.text.DateFormat;
|
|||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -49,7 +50,8 @@ public abstract class Resource implements ResourceFactory
|
|||
private static final Logger LOG = Log.getLogger(Resource.class);
|
||||
public static boolean __defaultUseCaches = true;
|
||||
volatile Object _associate;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Change the default setting for url connection caches.
|
||||
* Subsequent URLConnections will use this default.
|
||||
|
@ -670,6 +672,31 @@ public abstract class Resource implements ResourceFactory
|
|||
writeTo(new FileOutputStream(destination),0,-1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getWeakETag()
|
||||
{
|
||||
try
|
||||
{
|
||||
StringBuilder b = new StringBuilder(32);
|
||||
b.append("W/\"");
|
||||
|
||||
String name=getName();
|
||||
int length=name.length();
|
||||
long lhash=0;
|
||||
for (int i=0; i<length;i++)
|
||||
lhash=31*lhash+name.charAt(i);
|
||||
|
||||
B64Code.encode(lastModified()^lhash,b);
|
||||
B64Code.encode(length()^lhash,b);
|
||||
b.append('"');
|
||||
return b.toString();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Generate a properly encoded URL from a {@link File} instance.
|
||||
* @param file Target file.
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class B64CodeTest
|
||||
{
|
||||
String text = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";
|
||||
|
||||
@Test
|
||||
public void testRFC1421() throws Exception
|
||||
{
|
||||
String b64 = B64Code.encode(text,StringUtil.__ISO_8859_1);
|
||||
Assert.assertEquals("TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"+
|
||||
"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"+
|
||||
"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu"+
|
||||
"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"+
|
||||
"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=",b64);
|
||||
|
||||
char[] chars = B64Code.encode(text.getBytes(StringUtil.__ISO_8859_1),false);
|
||||
b64 = new String(chars,0,chars.length);
|
||||
Assert.assertEquals("TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"+
|
||||
"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"+
|
||||
"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu"+
|
||||
"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"+
|
||||
"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=",b64);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRFC2045() throws Exception
|
||||
{
|
||||
char[] chars = B64Code.encode(text.getBytes(StringUtil.__ISO_8859_1),true);
|
||||
String b64 = new String(chars,0,chars.length);
|
||||
Assert.assertEquals("TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz\r\n"+
|
||||
"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg\r\n"+
|
||||
"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu\r\n"+
|
||||
"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo\r\n"+
|
||||
"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=\r\n",b64);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInteger() throws Exception
|
||||
{
|
||||
byte[] bytes = text.getBytes(StringUtil.__ISO_8859_1);
|
||||
int value=(bytes[0]<<24)+(bytes[1]<<16)+(bytes[2]<<8)+(bytes[3]);
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
B64Code.encode(value,b);
|
||||
Assert.assertEquals("TWFuIA=",b.toString());
|
||||
}
|
||||
@Test
|
||||
public void testLong() throws Exception
|
||||
{
|
||||
byte[] bytes = text.getBytes(StringUtil.__ISO_8859_1);
|
||||
long value=((0xffL&bytes[0])<<56)+((0xffL&bytes[1])<<48)+((0xffL&bytes[2])<<40)+((0xffL&bytes[3])<<32)+
|
||||
((0xffL&bytes[4])<<24)+((0xffL&bytes[5])<<16)+((0xffL&bytes[6])<<8)+(0xffL&bytes[7]);
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
B64Code.encode(value,b);
|
||||
Assert.assertEquals("TWFuIGlzIGQ",b.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TypeUtilTest
|
||||
{
|
||||
|
||||
@Test
|
||||
public void testToHexInt() throws Exception
|
||||
{
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex((int)0,b);
|
||||
Assert.assertEquals("00000000",b.toString());
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex(Integer.MAX_VALUE,b);
|
||||
Assert.assertEquals("7FFFFFFF",b.toString());
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex(Integer.MIN_VALUE,b);
|
||||
Assert.assertEquals("80000000",b.toString());
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex(0x12345678,b);
|
||||
Assert.assertEquals("12345678",b.toString());
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex(0x9abcdef0,b);
|
||||
Assert.assertEquals("9ABCDEF0",b.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToHexLong() throws Exception
|
||||
{
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex((long)0,b);
|
||||
Assert.assertEquals("0000000000000000",b.toString());
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex(Long.MAX_VALUE,b);
|
||||
Assert.assertEquals("7FFFFFFFFFFFFFFF",b.toString());
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex(Long.MIN_VALUE,b);
|
||||
Assert.assertEquals("8000000000000000",b.toString());
|
||||
|
||||
b.setLength(0);
|
||||
TypeUtil.toHex(0x123456789abcdef0L,b);
|
||||
Assert.assertEquals("123456789ABCDEF0",b.toString());
|
||||
}
|
||||
|
||||
}
|
|
@ -51,9 +51,19 @@
|
|||
<!-- Context params to control Session Cookies -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!--
|
||||
UNCOMMENT TO ACTIVATE <context-param> <param-name>org.eclipse.jetty.servlet.SessionDomain</param-name> <param-value>127.0.0.1</param-value> </context-param> <context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.SessionPath</param-name> <param-value>/</param-value> </context-param> <context-param> <param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
|
||||
<param-value>-1</param-value> </context-param>
|
||||
UNCOMMENT TO ACTIVATE
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.SessionDomain</param-name>
|
||||
<param-value>127.0.0.1</param-value>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.SessionPath</param-name>
|
||||
<param-value>/</param-value>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>org.eclipse.jetty.servlet.MaxAge</param-name>
|
||||
<param-value>-1</param-value>
|
||||
</context-param>
|
||||
-->
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
|
@ -87,16 +97,23 @@
|
|||
*
|
||||
* resourceBase Set to replace the context resource base
|
||||
*
|
||||
* resourceCache If set, this is a context attribute name, which the servlet
|
||||
* will use to look for a shared ResourceCache instance.
|
||||
*
|
||||
* resourceCache If set, this is a context attribute name, which the servlet
|
||||
* will use to look for a shared ResourceCache instance.
|
||||
*
|
||||
* relativeResourceBase
|
||||
* Set with a pathname relative to the base of the
|
||||
* servlet context root. Useful for only serving static content out
|
||||
* of only specific subdirectories.
|
||||
*
|
||||
* pathInfoOnly If true, only the path info will be applied to the resourceBase
|
||||
*
|
||||
* stylesheet Set with the location of an optional stylesheet that will be used
|
||||
* to decorate the directory listing html.
|
||||
*
|
||||
* aliases If True, aliases of resources are allowed (eg. symbolic
|
||||
* links and caps variations). May bypass security constraints.
|
||||
*
|
||||
* etags If True, weak etags will be generated and handled.
|
||||
*
|
||||
* maxCacheSize The maximum total size of the cache or 0 for no cache.
|
||||
* maxCachedFileSize The maximum size of a file to cache
|
||||
|
@ -110,6 +127,7 @@
|
|||
*
|
||||
* cacheControl If set, all static content will have this value set as the cache-control
|
||||
* header.
|
||||
*
|
||||
-->
|
||||
|
||||
|
||||
|
@ -153,6 +171,10 @@
|
|||
<param-name>gzip</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>etags</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>useFileMappedBuffer</param-name>
|
||||
<param-value>true</param-value>
|
||||
|
@ -301,33 +323,6 @@
|
|||
<url-pattern>*.XSP</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<!-- Dynamic Servlet Invoker. -->
|
||||
<!-- This servlet invokes anonymous servlets that have not been defined -->
|
||||
<!-- in the web.xml or by other means. The first element of the pathInfo -->
|
||||
<!-- of a request passed to the envoker is treated as a servlet name for -->
|
||||
<!-- an existing servlet, or as a class name of a new servlet. -->
|
||||
<!-- This servlet is normally mapped to /servlet/* -->
|
||||
<!-- This servlet support the following initParams: -->
|
||||
<!-- -->
|
||||
<!-- nonContextServlets If false, the invoker can only load -->
|
||||
<!-- servlets from the contexts classloader. -->
|
||||
<!-- This is false by default and setting this -->
|
||||
<!-- to true may have security implications. -->
|
||||
<!-- -->
|
||||
<!-- verbose If true, log dynamic loads -->
|
||||
<!-- -->
|
||||
<!-- * All other parameters are copied to the -->
|
||||
<!-- each dynamic servlet as init parameters -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!--
|
||||
Uncomment for dynamic invocation <servlet> <servlet-name>invoker</servlet-name> <servlet-class>org.eclipse.jetty.servlet.Invoker</servlet-class> <init-param> <param-name>verbose</param-name>
|
||||
<param-value>false</param-value> </init-param> <init-param> <param-name>nonContextServlets</param-name> <param-value>false</param-value> </init-param> <init-param>
|
||||
<param-name>dynamicParam</param-name> <param-value>anyValue</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>invoker</servlet-name>
|
||||
<url-pattern>/servlet/*</url-pattern> </servlet-mapping>
|
||||
-->
|
||||
|
||||
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<session-config>
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
<filter-mapping>
|
||||
<filter-name>GzipFilter</filter-name>
|
||||
<url-pattern>/dump/gzip/*</url-pattern>
|
||||
<url-pattern>*.txt</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue