minor cleanups of HttpContent
This commit is contained in:
parent
f2cbde13e2
commit
47a92e9608
|
@ -24,12 +24,17 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
import org.eclipse.jetty.http.MimeTypes.Type;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** HttpContent.
|
||||
*
|
||||
/** HttpContent interface.
|
||||
* <p>This information represents all the information about a
|
||||
* static resource that is needed to evaluate conditional headers
|
||||
* and to serve the content if need be. It can be implemented
|
||||
* either transiently (values and fields generated on demand) or
|
||||
* persistently (values and fields pre-generated in anticipation of
|
||||
* reuse in from a cache).
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public interface HttpContent
|
||||
|
@ -55,182 +60,4 @@ public interface HttpContent
|
|||
ReadableByteChannel getReadableByteChannel() throws IOException;
|
||||
void release();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
public class ResourceAsHttpContent implements HttpContent
|
||||
{
|
||||
final Resource _resource;
|
||||
final String _contentType;
|
||||
final int _maxBuffer;
|
||||
final String _etag;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String contentType)
|
||||
{
|
||||
this(resource,contentType,-1,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String contentType, int maxBuffer)
|
||||
{
|
||||
this(resource,contentType,maxBuffer,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String contentType, boolean etag)
|
||||
{
|
||||
this(resource,contentType,-1,etag);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceAsHttpContent(final Resource resource, final String contentType, int maxBuffer, boolean etag)
|
||||
{
|
||||
_resource=resource;
|
||||
_contentType=contentType;
|
||||
_maxBuffer=maxBuffer;
|
||||
_etag=etag?resource.getWeakETag():null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getContentTypeValue()
|
||||
{
|
||||
return _contentType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getContentType()
|
||||
{
|
||||
return _contentType==null?null:new HttpField(HttpHeader.CONTENT_TYPE,_contentType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
return _contentType==null?null:MimeTypes.getCharsetFromContentType(_contentType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Type getMimeType()
|
||||
{
|
||||
return _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getLastModified()
|
||||
{
|
||||
long lm = _resource.lastModified();
|
||||
return lm>=0?new HttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(lm)):null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getLastModifiedValue()
|
||||
{
|
||||
long lm = _resource.lastModified();
|
||||
return lm>=0?DateGenerator.formatDate(lm):null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ByteBuffer getDirectBuffer()
|
||||
{
|
||||
if (_resource.length()<=0 || _maxBuffer<_resource.length())
|
||||
return null;
|
||||
try
|
||||
{
|
||||
return BufferUtil.toBuffer(_resource,true);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getETag()
|
||||
{
|
||||
return _etag==null?null:new HttpField(HttpHeader.ETAG,_etag);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getETagValue()
|
||||
{
|
||||
return _etag;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ByteBuffer getIndirectBuffer()
|
||||
{
|
||||
if (_resource.length()<=0 || _maxBuffer<_resource.length())
|
||||
return null;
|
||||
try
|
||||
{
|
||||
return BufferUtil.toBuffer(_resource,false);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getContentLength()
|
||||
{
|
||||
long l=_resource.length();
|
||||
return l==-1?null:new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,_resource.length());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public long getContentLengthValue()
|
||||
{
|
||||
return _resource.length();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
return _resource.getInputStream();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return _resource.getReadableByteChannel();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Resource getResource()
|
||||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void release()
|
||||
{
|
||||
_resource.close();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{r=%s}",this.getClass().getSimpleName(),hashCode(),_resource);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 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.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
|
||||
import org.eclipse.jetty.http.MimeTypes.Type;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** HttpContent created from a {@link Resource}.
|
||||
* <p>The HttpContent is used to server static content that is not
|
||||
* cached. So fields and values are only generated as need be an not
|
||||
* kept for reuse</p>
|
||||
*/
|
||||
public class ResourceHttpContent implements HttpContent
|
||||
{
|
||||
final Resource _resource;
|
||||
final String _contentType;
|
||||
final int _maxBuffer;
|
||||
final String _etag;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceHttpContent(final Resource resource, final String contentType)
|
||||
{
|
||||
this(resource,contentType,-1,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer)
|
||||
{
|
||||
this(resource,contentType,maxBuffer,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceHttpContent(final Resource resource, final String contentType, boolean etag)
|
||||
{
|
||||
this(resource,contentType,-1,etag);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ResourceHttpContent(final Resource resource, final String contentType, int maxBuffer, boolean etag)
|
||||
{
|
||||
_resource=resource;
|
||||
_contentType=contentType;
|
||||
_maxBuffer=maxBuffer;
|
||||
_etag=etag?resource.getWeakETag():null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getContentTypeValue()
|
||||
{
|
||||
return _contentType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getContentType()
|
||||
{
|
||||
return _contentType==null?null:new HttpField(HttpHeader.CONTENT_TYPE,_contentType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
return _contentType==null?null:MimeTypes.getCharsetFromContentType(_contentType);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Type getMimeType()
|
||||
{
|
||||
return _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(_contentType));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getLastModified()
|
||||
{
|
||||
long lm = _resource.lastModified();
|
||||
return lm>=0?new HttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(lm)):null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getLastModifiedValue()
|
||||
{
|
||||
long lm = _resource.lastModified();
|
||||
return lm>=0?DateGenerator.formatDate(lm):null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ByteBuffer getDirectBuffer()
|
||||
{
|
||||
if (_resource.length()<=0 || _maxBuffer<_resource.length())
|
||||
return null;
|
||||
try
|
||||
{
|
||||
return BufferUtil.toBuffer(_resource,true);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getETag()
|
||||
{
|
||||
return _etag==null?null:new HttpField(HttpHeader.ETAG,_etag);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getETagValue()
|
||||
{
|
||||
return _etag;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ByteBuffer getIndirectBuffer()
|
||||
{
|
||||
if (_resource.length()<=0 || _maxBuffer<_resource.length())
|
||||
return null;
|
||||
try
|
||||
{
|
||||
return BufferUtil.toBuffer(_resource,false);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getContentLength()
|
||||
{
|
||||
long l=_resource.length();
|
||||
return l==-1?null:new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,_resource.length());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public long getContentLengthValue()
|
||||
{
|
||||
return _resource.length();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
return _resource.getInputStream();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return _resource.getReadableByteChannel();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Resource getResource()
|
||||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void release()
|
||||
{
|
||||
_resource.close();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{r=%s}",this.getClass().getSimpleName(),hashCode(),_resource);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http.MimeTypes.Type;
|
||||
import org.eclipse.jetty.http.ResourceHttpContent;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -53,7 +54,7 @@ public class ResourceCache
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(ResourceCache.class);
|
||||
|
||||
private final ConcurrentMap<String,Content> _cache;
|
||||
private final ConcurrentMap<String,CachedHttpContent> _cache;
|
||||
private final AtomicInteger _cachedSize;
|
||||
private final AtomicInteger _cachedFiles;
|
||||
private final ResourceFactory _factory;
|
||||
|
@ -73,7 +74,7 @@ public class ResourceCache
|
|||
public ResourceCache(ResourceCache parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags)
|
||||
{
|
||||
_factory = factory;
|
||||
_cache=new ConcurrentHashMap<String,Content>();
|
||||
_cache=new ConcurrentHashMap<String,CachedHttpContent>();
|
||||
_cachedSize=new AtomicInteger();
|
||||
_cachedFiles=new AtomicInteger();
|
||||
_mimeTypes=mimeTypes;
|
||||
|
@ -154,7 +155,7 @@ public class ResourceCache
|
|||
{
|
||||
for (String path : _cache.keySet())
|
||||
{
|
||||
Content content = _cache.remove(path);
|
||||
CachedHttpContent content = _cache.remove(path);
|
||||
if (content!=null)
|
||||
content.invalidate();
|
||||
}
|
||||
|
@ -169,7 +170,7 @@ public class ResourceCache
|
|||
* @param pathInContext The key into the cache
|
||||
* @return The entry matching <code>pathInContext</code>, or a new entry
|
||||
* if no matching entry was found. If the content exists but is not cachable,
|
||||
* then a {@link ResourceAsHttpContent} instance is return. If
|
||||
* then a {@link ResourceHttpContent} instance is return. If
|
||||
* the resource does not exist, then null is returned.
|
||||
* @throws IOException Problem loading the resource
|
||||
*/
|
||||
|
@ -177,7 +178,7 @@ public class ResourceCache
|
|||
throws IOException
|
||||
{
|
||||
// Is the content in this cache?
|
||||
Content content =_cache.get(pathInContext);
|
||||
CachedHttpContent content =_cache.get(pathInContext);
|
||||
if (content!=null && (content).isValid())
|
||||
return content;
|
||||
|
||||
|
@ -215,7 +216,7 @@ public class ResourceCache
|
|||
private HttpContent load(String pathInContext, Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
Content content=null;
|
||||
CachedHttpContent content=null;
|
||||
|
||||
if (resource==null || !resource.exists())
|
||||
return null;
|
||||
|
@ -224,13 +225,13 @@ public class ResourceCache
|
|||
if (!resource.isDirectory() && isCacheable(resource))
|
||||
{
|
||||
// Create the Content (to increment the cache sizes before adding the content
|
||||
content = new Content(pathInContext,resource);
|
||||
content = new CachedHttpContent(pathInContext,resource);
|
||||
|
||||
// reduce the cache to an acceptable size.
|
||||
shrinkCache();
|
||||
|
||||
// Add it to the cache.
|
||||
Content added = _cache.putIfAbsent(pathInContext,content);
|
||||
CachedHttpContent added = _cache.putIfAbsent(pathInContext,content);
|
||||
if (added!=null)
|
||||
{
|
||||
content.invalidate();
|
||||
|
@ -240,7 +241,7 @@ public class ResourceCache
|
|||
return content;
|
||||
}
|
||||
|
||||
return new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize(),_etagSupported);
|
||||
return new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize(),_etagSupported);
|
||||
|
||||
}
|
||||
|
||||
|
@ -251,10 +252,10 @@ public class ResourceCache
|
|||
while (_cache.size()>0 && (_cachedFiles.get()>_maxCachedFiles || _cachedSize.get()>_maxCacheSize))
|
||||
{
|
||||
// Scan the entire cache and generate an ordered list by last accessed time.
|
||||
SortedSet<Content> sorted= new TreeSet<Content>(
|
||||
new Comparator<Content>()
|
||||
SortedSet<CachedHttpContent> sorted= new TreeSet<CachedHttpContent>(
|
||||
new Comparator<CachedHttpContent>()
|
||||
{
|
||||
public int compare(Content c1, Content c2)
|
||||
public int compare(CachedHttpContent c1, CachedHttpContent c2)
|
||||
{
|
||||
if (c1._lastAccessed<c2._lastAccessed)
|
||||
return -1;
|
||||
|
@ -268,11 +269,11 @@ public class ResourceCache
|
|||
return c1._key.compareTo(c2._key);
|
||||
}
|
||||
});
|
||||
for (Content content : _cache.values())
|
||||
for (CachedHttpContent content : _cache.values())
|
||||
sorted.add(content);
|
||||
|
||||
// Invalidate least recently used first
|
||||
for (Content content : sorted)
|
||||
for (CachedHttpContent content : sorted)
|
||||
{
|
||||
if (_cachedFiles.get()<=_maxCachedFiles && _cachedSize.get()<=_maxCacheSize)
|
||||
break;
|
||||
|
@ -324,7 +325,7 @@ public class ResourceCache
|
|||
/* ------------------------------------------------------------ */
|
||||
/** MetaData associated with a context Resource.
|
||||
*/
|
||||
public class Content implements HttpContent
|
||||
public class CachedHttpContent implements HttpContent
|
||||
{
|
||||
final String _key;
|
||||
final Resource _resource;
|
||||
|
@ -342,7 +343,7 @@ public class ResourceCache
|
|||
AtomicReference<ByteBuffer> _directBuffer=new AtomicReference<ByteBuffer>();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
Content(String pathInContext,Resource resource)
|
||||
CachedHttpContent(String pathInContext,Resource resource)
|
||||
{
|
||||
_key=pathInContext;
|
||||
_resource=resource;
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.io.OutputStream;
|
|||
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.ResourceHttpContent;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
|
@ -136,7 +137,7 @@ public class ResourceCacheTest
|
|||
cache.setMaxCachedFiles(4);
|
||||
|
||||
assertTrue(cache.lookup("does not exist")==null);
|
||||
assertTrue(cache.lookup(names[9]) instanceof HttpContent.ResourceAsHttpContent);
|
||||
assertTrue(cache.lookup(names[9]) instanceof ResourceHttpContent);
|
||||
|
||||
HttpContent content;
|
||||
content=cache.lookup(names[8]);
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.http.PathMap.MappedEntry;
|
||||
import org.eclipse.jetty.http.ResourceHttpContent;
|
||||
import org.eclipse.jetty.io.WriterOutputStream;
|
||||
import org.eclipse.jetty.server.HttpOutput;
|
||||
import org.eclipse.jetty.server.InclusiveByteRange;
|
||||
|
@ -519,7 +520,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(),_etags);
|
||||
content=new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),response.getBufferSize(),_etags);
|
||||
|
||||
if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
|
||||
{
|
||||
|
@ -591,7 +592,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
}
|
||||
else
|
||||
{
|
||||
content=new HttpContent.ResourceAsHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),_etags);
|
||||
content=new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),_etags);
|
||||
if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
|
||||
sendDirectory(request,response,resource,pathInContext);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue