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
28 package org.apache.hc.core5.http.examples;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.net.SocketTimeoutException;
33 import java.net.URL;
34 import java.net.URLDecoder;
35 import java.nio.charset.Charset;
36 import java.util.concurrent.TimeUnit;
37
38 import javax.net.ssl.SSLContext;
39
40 import org.apache.hc.core5.http.ClassicHttpRequest;
41 import org.apache.hc.core5.http.ClassicHttpResponse;
42 import org.apache.hc.core5.http.ConnectionClosedException;
43 import org.apache.hc.core5.http.ContentType;
44 import org.apache.hc.core5.http.EndpointDetails;
45 import org.apache.hc.core5.http.ExceptionListener;
46 import org.apache.hc.core5.http.HttpConnection;
47 import org.apache.hc.core5.http.HttpEntity;
48 import org.apache.hc.core5.http.HttpException;
49 import org.apache.hc.core5.http.HttpStatus;
50 import org.apache.hc.core5.http.Method;
51 import org.apache.hc.core5.http.MethodNotSupportedException;
52 import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
53 import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
54 import org.apache.hc.core5.http.io.HttpRequestHandler;
55 import org.apache.hc.core5.http.io.SocketConfig;
56 import org.apache.hc.core5.http.io.entity.EntityUtils;
57 import org.apache.hc.core5.http.io.entity.FileEntity;
58 import org.apache.hc.core5.http.io.entity.StringEntity;
59 import org.apache.hc.core5.http.protocol.HttpContext;
60 import org.apache.hc.core5.http.protocol.HttpCoreContext;
61 import org.apache.hc.core5.io.CloseMode;
62 import org.apache.hc.core5.ssl.SSLContexts;
63 import org.apache.hc.core5.util.TimeValue;
64
65
66
67
68 public class ClassicFileServerExample {
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 String docRoot = args[0];
77 int port = 8080;
78 if (args.length >= 2) {
79 port = Integer.parseInt(args[1]);
80 }
81
82 SSLContext sslContext = null;
83 if (port == 8443) {
84
85 final URL url = ClassicFileServerExample.class.getResource("/my.keystore");
86 if (url == null) {
87 System.out.println("Keystore not found");
88 System.exit(1);
89 }
90 sslContext = SSLContexts.custom()
91 .loadKeyMaterial(url, "secret".toCharArray(), "secret".toCharArray())
92 .build();
93 }
94
95 final SocketConfig socketConfig = SocketConfig.custom()
96 .setSoTimeout(15, TimeUnit.SECONDS)
97 .setTcpNoDelay(true)
98 .build();
99
100 final HttpServer server = ServerBootstrap.bootstrap()
101 .setListenerPort(port)
102 .setSocketConfig(socketConfig)
103 .setSslContext(sslContext)
104 .setExceptionListener(new ExceptionListener() {
105
106 @Override
107 public void onError(final Exception ex) {
108 ex.printStackTrace();
109 }
110
111 @Override
112 public void onError(final HttpConnection conn, final Exception ex) {
113 if (ex instanceof SocketTimeoutException) {
114 System.err.println("Connection timed out");
115 } else if (ex instanceof ConnectionClosedException) {
116 System.err.println(ex.getMessage());
117 } else {
118 ex.printStackTrace();
119 }
120 }
121
122 })
123 .register("*", new HttpFileHandler(docRoot))
124 .create();
125
126 server.start();
127 Runtime.getRuntime().addShutdownHook(new Thread(() -> server.close(CloseMode.GRACEFUL)));
128 System.out.println("Listening on port " + port);
129
130 server.awaitTermination(TimeValue.MAX_VALUE);
131
132 }
133
134 static class HttpFileHandler implements HttpRequestHandler {
135
136 private final String docRoot;
137
138 public HttpFileHandler(final String docRoot) {
139 super();
140 this.docRoot = docRoot;
141 }
142
143 @Override
144 public void handle(
145 final ClassicHttpRequest request,
146 final ClassicHttpResponse response,
147 final HttpContext context) throws HttpException, IOException {
148
149 final String method = request.getMethod();
150 if (!Method.GET.isSame(method) && !Method.HEAD.isSame(method) && !Method.POST.isSame(method)) {
151 throw new MethodNotSupportedException(method + " method not supported");
152 }
153 final String path = request.getPath();
154
155 final HttpEntity incomingEntity = request.getEntity();
156 if (incomingEntity != null) {
157 final byte[] entityContent = EntityUtils.toByteArray(incomingEntity);
158 System.out.println("Incoming incomingEntity content (bytes): " + entityContent.length);
159 }
160
161 final File file = new File(this.docRoot, URLDecoder.decode(path, "UTF-8"));
162 if (!file.exists()) {
163
164 response.setCode(HttpStatus.SC_NOT_FOUND);
165 final String msg = "File " + file.getPath() + " not found";
166 final StringEntity outgoingEntity = new StringEntity(
167 "<html><body><h1>" + msg + "</h1></body></html>",
168 ContentType.create("text/html", "UTF-8"));
169 response.setEntity(outgoingEntity);
170 System.out.println(msg);
171
172 } else if (!file.canRead() || file.isDirectory()) {
173
174 response.setCode(HttpStatus.SC_FORBIDDEN);
175 final String msg = "Cannot read file " + file.getPath();
176 final StringEntity outgoingEntity = new StringEntity(
177 "<html><body><h1>" + msg + "</h1></body></html>",
178 ContentType.create("text/html", "UTF-8"));
179 response.setEntity(outgoingEntity);
180 System.out.println(msg);
181
182 } else {
183 final HttpCoreContext coreContext = HttpCoreContext.adapt(context);
184 final EndpointDetails endpoint = coreContext.getEndpointDetails();
185 response.setCode(HttpStatus.SC_OK);
186 final FileEntity body = new FileEntity(file, ContentType.create("text/html", (Charset) null));
187 response.setEntity(body);
188 System.out.println(endpoint + ": serving file " + file.getPath());
189 }
190 }
191
192 }
193
194 }