1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.core5.http.examples;
28
29 import java.io.File;
30 import java.io.IOException;
31 import java.net.InetSocketAddress;
32 import java.net.URI;
33 import java.net.URISyntaxException;
34 import java.util.Locale;
35 import java.util.concurrent.Future;
36 import java.util.concurrent.TimeUnit;
37
38 import org.apache.hc.core5.http.ContentType;
39 import org.apache.hc.core5.http.EndpointDetails;
40 import org.apache.hc.core5.http.EntityDetails;
41 import org.apache.hc.core5.http.HttpException;
42 import org.apache.hc.core5.http.HttpRequest;
43 import org.apache.hc.core5.http.HttpStatus;
44 import org.apache.hc.core5.http.Message;
45 import org.apache.hc.core5.http.ProtocolException;
46 import org.apache.hc.core5.http.impl.bootstrap.AsyncServerBootstrap;
47 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
48 import org.apache.hc.core5.http.nio.AsyncRequestConsumer;
49 import org.apache.hc.core5.http.nio.AsyncServerRequestHandler;
50 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
51 import org.apache.hc.core5.http.nio.entity.NoopEntityConsumer;
52 import org.apache.hc.core5.http.nio.support.AsyncResponseBuilder;
53 import org.apache.hc.core5.http.nio.support.BasicRequestConsumer;
54 import org.apache.hc.core5.http.protocol.HttpContext;
55 import org.apache.hc.core5.http.protocol.HttpCoreContext;
56 import org.apache.hc.core5.http.protocol.HttpDateGenerator;
57 import org.apache.hc.core5.io.CloseMode;
58 import org.apache.hc.core5.reactor.IOReactorConfig;
59 import org.apache.hc.core5.reactor.ListenerEndpoint;
60 import org.apache.hc.core5.util.TimeValue;
61
62
63
64
65 public class AsyncFileServerExample {
66
67
68
69
70 public static void main(final String[] args) throws Exception {
71 if (args.length < 1) {
72 System.err.println("Please specify document root directory");
73 System.exit(1);
74 }
75
76 final File docRoot = new File(args[0]);
77 int port = 8080;
78 if (args.length >= 2) {
79 port = Integer.parseInt(args[1]);
80 }
81
82 final IOReactorConfig config = IOReactorConfig.custom()
83 .setSoTimeout(15, TimeUnit.SECONDS)
84 .setTcpNoDelay(true)
85 .build();
86
87 final HttpAsyncServer server = AsyncServerBootstrap.bootstrap()
88 .setIOReactorConfig(config)
89 .register("*", new AsyncServerRequestHandler<Message<HttpRequest, Void>>() {
90
91 @Override
92 public AsyncRequestConsumer<Message<HttpRequest, Void>> prepare(
93 final HttpRequest request,
94 final EntityDetails entityDetails,
95 final HttpContext context) throws HttpException {
96 return new BasicRequestConsumer<>(entityDetails != null ? new NoopEntityConsumer() : null);
97 }
98
99 @Override
100 public void handle(
101 final Message<HttpRequest, Void> message,
102 final ResponseTrigger responseTrigger,
103 final HttpContext context) throws HttpException, IOException {
104 final HttpRequest request = message.getHead();
105 final URI requestUri;
106 try {
107 requestUri = request.getUri();
108 } catch (final URISyntaxException ex) {
109 throw new ProtocolException(ex.getMessage(), ex);
110 }
111 final String path = requestUri.getPath();
112 final File file = new File(docRoot, path);
113 if (!file.exists()) {
114
115 final String msg = "File " + file.getPath() + " not found";
116 println(msg);
117 responseTrigger.submitResponse(
118 AsyncResponseBuilder.create(HttpStatus.SC_NOT_FOUND)
119 .setEntity("<html><body><h1>" + msg + "</h1></body></html>", ContentType.TEXT_HTML)
120 .build(),
121 context);
122
123 } else if (!file.canRead() || file.isDirectory()) {
124
125 final String msg = "Cannot read file " + file.getPath();
126 println(msg);
127 responseTrigger.submitResponse(AsyncResponseBuilder.create(HttpStatus.SC_FORBIDDEN)
128 .setEntity("<html><body><h1>" + msg + "</h1></body></html>", ContentType.TEXT_HTML)
129 .build(),
130 context);
131
132 } else {
133
134 final ContentType contentType;
135 final String filename = file.getName().toLowerCase(Locale.ROOT);
136 if (filename.endsWith(".txt")) {
137 contentType = ContentType.TEXT_PLAIN;
138 } else if (filename.endsWith(".html") || filename.endsWith(".htm")) {
139 contentType = ContentType.TEXT_HTML;
140 } else if (filename.endsWith(".xml")) {
141 contentType = ContentType.TEXT_XML;
142 } else {
143 contentType = ContentType.DEFAULT_BINARY;
144 }
145
146 final HttpCoreContext coreContext = HttpCoreContext.adapt(context);
147 final EndpointDetails endpoint = coreContext.getEndpointDetails();
148
149 println(endpoint + " | serving file " + file.getPath());
150
151 responseTrigger.submitResponse(
152 AsyncResponseBuilder.create(HttpStatus.SC_OK)
153 .setEntity(AsyncEntityProducers.create(file, contentType))
154 .build(),
155 context);
156 }
157 }
158
159 })
160 .create();
161
162 Runtime.getRuntime().addShutdownHook(new Thread() {
163 @Override
164 public void run() {
165 println("HTTP server shutting down");
166 server.close(CloseMode.GRACEFUL);
167 }
168 });
169
170 server.start();
171 final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(port));
172 final ListenerEndpoint listenerEndpoint = future.get();
173 println("Listening on " + listenerEndpoint.getAddress());
174 server.awaitShutdown(TimeValue.MAX_VALUE);
175 }
176
177 static final void println(final String msg) {
178 System.out.println(HttpDateGenerator.INSTANCE.getCurrentDate() + " | " + msg);
179 }
180
181 }