diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java index 3e401d96960..9299c184e24 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpContent.java @@ -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. + *

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). + *

* */ 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); - } - } - } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java new file mode 100644 index 00000000000..f0b0a42973f --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java @@ -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}. + *

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

+ */ +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); + } +} \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java index d08b1032efd..f0cc7418c92 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceCache.java @@ -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 _cache; + private final ConcurrentMap _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(); + _cache=new ConcurrentHashMap(); _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 pathInContext, 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 sorted= new TreeSet( - new Comparator() + SortedSet sorted= new TreeSet( + new Comparator() { - public int compare(Content c1, Content c2) + public int compare(CachedHttpContent c1, CachedHttpContent c2) { if (c1._lastAccessed _directBuffer=new AtomicReference(); /* ------------------------------------------------------------ */ - Content(String pathInContext,Resource resource) + CachedHttpContent(String pathInContext,Resource resource) { _key=pathInContext; _resource=resource; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java index a01022f3991..60384420396 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResourceCacheTest.java @@ -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]); diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java index d3e14f29b54..211c45b7a58 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java @@ -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); }