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.MethodNotSupportedException;
51  import org.apache.hc.core5.http.Method;
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() {
128             @Override
129             public void run() {
130                 server.close(CloseMode.GRACEFUL);
131             }
132         });
133         System.out.println("Listening on port " + port);
134 
135         server.awaitTermination(TimeValue.MAX_VALUE);
136 
137     }
138 
139     static class HttpFileHandler implements HttpRequestHandler  {
140 
141         private final String docRoot;
142 
143         public HttpFileHandler(final String docRoot) {
144             super();
145             this.docRoot = docRoot;
146         }
147 
148         @Override
149         public void handle(
150                 final ClassicHttpRequest request,
151                 final ClassicHttpResponse response,
152                 final HttpContext context) throws HttpException, IOException {
153 
154             final String method = request.getMethod();
155             if (!Method.GET.isSame(method) && !Method.HEAD.isSame(method) && !Method.POST.isSame(method)) {
156                 throw new MethodNotSupportedException(method + " method not supported");
157             }
158             final String path = request.getPath();
159 
160             final HttpEntity incomingEntity = request.getEntity();
161             if (incomingEntity != null) {
162                 final byte[] entityContent = EntityUtils.toByteArray(incomingEntity);
163                 System.out.println("Incoming incomingEntity content (bytes): " + entityContent.length);
164             }
165 
166             final File file = new File(this.docRoot, URLDecoder.decode(path, "UTF-8"));
167             if (!file.exists()) {
168 
169                 response.setCode(HttpStatus.SC_NOT_FOUND);
170                 final String msg = "File " + file.getPath() + " not found";
171                 final StringEntity outgoingEntity = new StringEntity(
172                         "<html><body><h1>" + msg + "</h1></body></html>",
173                         ContentType.create("text/html", "UTF-8"));
174                 response.setEntity(outgoingEntity);
175                 System.out.println(msg);
176 
177             } else if (!file.canRead() || file.isDirectory()) {
178 
179                 response.setCode(HttpStatus.SC_FORBIDDEN);
180                 final String msg = "Cannot read file " + file.getPath();
181                 final StringEntity outgoingEntity = new StringEntity(
182                         "<html><body><h1>" + msg + "</h1></body></html>",
183                         ContentType.create("text/html", "UTF-8"));
184                 response.setEntity(outgoingEntity);
185                 System.out.println(msg);
186 
187             } else {
188                 final HttpCoreContext coreContext = HttpCoreContext.adapt(context);
189                 final EndpointDetails endpoint = coreContext.getEndpointDetails();
190                 response.setCode(HttpStatus.SC_OK);
191                 final FileEntity body = new FileEntity(file, ContentType.create("text/html", (Charset) null));
192                 response.setEntity(body);
193                 System.out.println(endpoint + ": serving file " + file.getPath());
194             }
195         }
196 
197     }
198 
199 }