View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
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   * Example of embedded HTTP/1.1 file server using classic I/O.
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          // Document root directory
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              // Initialize SSL context
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 }