From 76d4859eda56dde318448741559671e54c78d7c9 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 16 May 2013 09:26:37 +1000 Subject: [PATCH] 398467 Servlet 3.1 Non Blocking IO Improved sendContent API and javadoc. Added FastFileServer example --- .../jetty/embedded/FastFileServer.java | 181 ++++++++++++++++++ .../org/eclipse/jetty/server/HttpOutput.java | 114 ++++++++++- .../jetty/server/handler/ResourceHandler.java | 26 ++- .../org/eclipse/jetty/util/BufferUtil.java | 7 +- 4 files changed, 315 insertions(+), 13 deletions(-) create mode 100644 examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java new file mode 100644 index 00000000000..dd819acdf7b --- /dev/null +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FastFileServer.java @@ -0,0 +1,181 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 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.embedded; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.StandardOpenOption; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpOutput; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.handler.HandlerList; +import org.eclipse.jetty.server.handler.ResourceHandler; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.URIUtil; +import org.eclipse.jetty.util.resource.Resource; + +/* ------------------------------------------------------------ */ +/** Fast FileServer. + * + *

This example shows how to use the Jetty APIs for sending static + * as fast as possible using various strategies for small, medium and + * large content.

+ *

The Jetty {@link DefaultServlet} does all this and more, and to + * a lesser extent so does the {@link ResourceHandler}, so unless you + * have exceptional circumstances it is best to use those classes for + * static content

+ */ +public class FastFileServer +{ + public static void main(String[] args) throws Exception + { + Server server = new Server(8080); + + HandlerList handlers = new HandlerList(); + handlers.setHandlers(new Handler[] { new FastFileHandler(new File(".")), new DefaultHandler() }); + server.setHandler(handlers); + + server.start(); + server.join(); + } + + static class FastFileHandler extends AbstractHandler + { + private final MimeTypes _mimeTypes = new MimeTypes(); + private final File _dir; + + FastFileHandler(File dir) + { + _dir=dir; + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + // define small medium and large. + // This should be turned for your content, JVM and OS, but we will huge HTTP response buffer size as a measure + final int SMALL=response.getBufferSize(); + final int MEDIUM=8*SMALL; + + + // What file to serve? + final File file = new File(_dir,request.getPathInfo()); + + // Only handle existing files + if (!file.exists()) + return; + + // we will handle this request + baseRequest.setHandled(true); + + // Handle directories + if (file.isDirectory()) + { + if (!request.getPathInfo().endsWith(URIUtil.SLASH)) + { + response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH))); + return; + } + String listing = Resource.newResource(file).getListHTML(request.getRequestURI(),request.getPathInfo().lastIndexOf("/") > 0); + response.setContentType("text/html; charset=UTF-8"); + response.getWriter().println(listing); + return; + } + + // Set some content headers + // Jetty DefaultServlet will cache formatted date strings, but we will reformat for each request here + response.setDateHeader("Last-Modified",file.lastModified()); + response.setDateHeader("Content-Length",file.length()); + response.setContentType(_mimeTypes.getMimeByExtension(file.getName())); + + + + // send "small" files blocking directly from an input stream + if (file.length()0) + response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),last_modified); - if (out instanceof HttpOutput) + if (out instanceof HttpOutput && request.isAsyncSupported()) { - ((HttpOutput)out).sendContent(resource); + final AsyncContext async = request.startAsync(); + ((HttpOutput)out).sendContent(resource.getReadableByteChannel(),new Callback() + { + @Override + public void succeeded() + { + async.complete(); + } + + @Override + public void failed(Throwable x) + { + async.complete(); + } + }); } else { - if (last_modified>0) - response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),last_modified); - // Write content normally resource.writeTo(out,0,resource.length()); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index 1a7f8a334cb..0a1bc96534c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -731,9 +731,10 @@ public class BufferUtil public static ByteBuffer toBuffer(File file) throws IOException { - RandomAccessFile raf = new RandomAccessFile(file,"r"); - MappedByteBuffer buffer=raf.getChannel().map(MapMode.READ_ONLY,0,raf.length()); - return buffer; + try(RandomAccessFile raf = new RandomAccessFile(file,"r");) + { + return raf.getChannel().map(MapMode.READ_ONLY,0,raf.length()); + } } public static String toSummaryString(ByteBuffer buffer)