1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.embedded;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.RandomAccessFile;
24 import java.nio.ByteBuffer;
25 import java.nio.channels.FileChannel;
26 import java.nio.channels.FileChannel.MapMode;
27 import java.nio.file.StandardOpenOption;
28
29 import javax.servlet.AsyncContext;
30 import javax.servlet.ServletException;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33
34 import org.eclipse.jetty.http.MimeTypes;
35 import org.eclipse.jetty.server.Handler;
36 import org.eclipse.jetty.server.HttpOutput;
37 import org.eclipse.jetty.server.Request;
38 import org.eclipse.jetty.server.Server;
39 import org.eclipse.jetty.server.handler.AbstractHandler;
40 import org.eclipse.jetty.server.handler.DefaultHandler;
41 import org.eclipse.jetty.server.handler.HandlerList;
42 import org.eclipse.jetty.util.Callback;
43 import org.eclipse.jetty.util.URIUtil;
44 import org.eclipse.jetty.util.resource.Resource;
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class FastFileServer
59 {
60 public static void main( String[] args ) throws Exception
61 {
62 Server server = new Server(8080);
63
64 HandlerList handlers = new HandlerList();
65 handlers.setHandlers(new Handler[] {
66 new FastFileHandler(new File(System.getProperty("user.dir"))),
67 new DefaultHandler() });
68 server.setHandler(handlers);
69
70 server.start();
71 server.join();
72 }
73
74 static class FastFileHandler extends AbstractHandler
75 {
76 private final MimeTypes mimeTypes = new MimeTypes();
77 private final File dir;
78
79 private FastFileHandler( File dir )
80 {
81 this.dir = dir;
82 }
83
84 @Override
85 public void handle( String target,
86 Request baseRequest,
87 HttpServletRequest request,
88 HttpServletResponse response ) throws IOException,
89 ServletException
90 {
91
92
93
94 final int SMALL = response.getBufferSize();
95 final int MEDIUM = 8 * SMALL;
96
97
98 final File file = new File(this.dir, request.getPathInfo());
99
100
101 if (!file.exists())
102 return;
103
104
105 baseRequest.setHandled(true);
106
107
108 if (file.isDirectory())
109 {
110 if (!request.getPathInfo().endsWith(URIUtil.SLASH))
111 {
112 response.sendRedirect(response.encodeRedirectURL(URIUtil
113 .addPaths(request.getRequestURI(), URIUtil.SLASH)));
114 return;
115 }
116 String listing = Resource.newResource(file).getListHTML(
117 request.getRequestURI(),
118 request.getPathInfo().lastIndexOf("/") > 0);
119 response.setContentType("text/html; charset=utf-8");
120 response.getWriter().println(listing);
121 return;
122 }
123
124
125
126
127
128 response.setDateHeader("Last-Modified", file.lastModified());
129 response.setDateHeader("Content-Length", file.length());
130 response.setContentType(mimeTypes.getMimeByExtension(file.getName()));
131
132
133 if (file.length() < SMALL)
134 {
135
136 ((HttpOutput) response.getOutputStream())
137 .sendContent(FileChannel.open(file.toPath(),
138 StandardOpenOption.READ));
139 return;
140 }
141
142
143
144 final AsyncContext async = request.startAsync();
145 Callback completionCB = new Callback()
146 {
147 @Override
148 public void succeeded()
149 {
150
151 async.complete();
152 }
153
154 @Override
155 public void failed( Throwable x )
156 {
157
158 x.printStackTrace();
159 async.complete();
160 }
161 };
162
163
164 if (file.length() < MEDIUM)
165 {
166
167 ((HttpOutput) response.getOutputStream())
168 .sendContent(FileChannel.open(file.toPath(),
169 StandardOpenOption.READ), completionCB);
170 return;
171 }
172
173
174
175
176
177 ByteBuffer buffer;
178 try ( RandomAccessFile raf = new RandomAccessFile(file, "r"); )
179 {
180 buffer = raf.getChannel().map(MapMode.READ_ONLY, 0,
181 raf.length());
182 }
183
184
185
186 buffer = buffer.asReadOnlyBuffer();
187
188
189
190 ((HttpOutput) response.getOutputStream()).sendContent(buffer,
191 completionCB);
192 }
193 }
194 }