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
11 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * ====================================================================
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/>.
29 import java
.io
.IOException
;
30 import java
.io
.InterruptedIOException
;
31 import java
.io
.OutputStream
;
32 import java
.io
.OutputStreamWriter
;
33 import java
.net
.ServerSocket
;
34 import java
.net
.Socket
;
35 import java
.net
.URLDecoder
;
36 import java
.util
.Locale
;
38 import org
.apache
.http
.ConnectionClosedException
;
39 import org
.apache
.http
.HttpEntity
;
40 import org
.apache
.http
.HttpEntityEnclosingRequest
;
41 import org
.apache
.http
.HttpException
;
42 import org
.apache
.http
.HttpRequest
;
43 import org
.apache
.http
.HttpResponse
;
44 import org
.apache
.http
.HttpServerConnection
;
45 import org
.apache
.http
.HttpStatus
;
46 import org
.apache
.http
.MethodNotSupportedException
;
47 import org
.apache
.http
.entity
.ContentProducer
;
48 import org
.apache
.http
.entity
.EntityTemplate
;
49 import org
.apache
.http
.entity
.FileEntity
;
50 import org
.apache
.http
.impl
.DefaultHttpResponseFactory
;
51 import org
.apache
.http
.impl
.DefaultHttpServerConnection
;
52 import org
.apache
.http
.impl
.NoConnectionReuseStrategy
;
53 import org
.apache
.http
.params
.BasicHttpParams
;
54 import org
.apache
.http
.params
.CoreConnectionPNames
;
55 import org
.apache
.http
.params
.CoreProtocolPNames
;
56 import org
.apache
.http
.params
.HttpParams
;
57 import org
.apache
.http
.protocol
.BasicHttpContext
;
58 import org
.apache
.http
.protocol
.BasicHttpProcessor
;
59 import org
.apache
.http
.protocol
.HttpContext
;
60 import org
.apache
.http
.protocol
.HttpProcessor
;
61 import org
.apache
.http
.protocol
.HttpRequestHandler
;
62 import org
.apache
.http
.protocol
.HttpRequestHandlerRegistry
;
63 import org
.apache
.http
.protocol
.HttpService
;
64 import org
.apache
.http
.util
.EntityUtils
;
65 import org
.apache
.thrift
.TProcessor
;
66 import org
.apache
.thrift
.protocol
.TJSONProtocol
;
67 import org
.apache
.thrift
.protocol
.TProtocol
;
68 import org
.apache
.thrift
.transport
.TMemoryBuffer
;
74 import java
.util
.HashMap
;
77 * Basic, yet fully functional and spec compliant, HTTP/1.1 file server.
79 * Please note the purpose of this application is demonstrate the usage of
80 * HttpCore APIs. It is NOT intended to demonstrate the most efficient way of
81 * building an HTTP file server.
87 public static void main(String
[] args
) throws Exception
{
88 if (args
.length
< 1) {
89 System
.err
.println("Please specify document root directory");
92 Thread t
= new RequestListenerThread(8088, args
[0]);
97 static class HttpFileHandler
implements HttpRequestHandler
{
99 private final String docRoot
;
101 public HttpFileHandler(final String docRoot
) {
103 this.docRoot
= docRoot
;
106 public void handle(final HttpRequest request
, final HttpResponse response
, final HttpContext context
) throws HttpException
, IOException
{
108 String method
= request
.getRequestLine().getMethod().toUpperCase(Locale
.ENGLISH
);
109 if (!method
.equals("GET") && !method
.equals("HEAD") && !method
.equals("POST")) {
110 throw new MethodNotSupportedException(method
+ " method not supported");
112 String target
= request
.getRequestLine().getUri();
114 if (request
instanceof HttpEntityEnclosingRequest
&& target
.equals("/thrift/service/tutorial/")) {
115 HttpEntity entity
= ((HttpEntityEnclosingRequest
) request
).getEntity();
116 byte[] entityContent
= EntityUtils
.toByteArray(entity
);
117 System
.out
.println("Incoming content: " + new String(entityContent
));
119 final String output
= this.thriftRequest(entityContent
);
121 System
.out
.println("Outgoing content: "+output
);
123 EntityTemplate body
= new EntityTemplate(new ContentProducer() {
125 public void writeTo(final OutputStream outstream
) throws IOException
{
126 OutputStreamWriter writer
= new OutputStreamWriter(outstream
, "UTF-8");
127 writer
.write(output
);
132 body
.setContentType("text/html; charset=UTF-8");
133 response
.setEntity(body
);
135 final File file
= new File(this.docRoot
, URLDecoder
.decode(target
, "UTF-8"));
136 if (!file
.exists()) {
138 response
.setStatusCode(HttpStatus
.SC_NOT_FOUND
);
139 EntityTemplate body
= new EntityTemplate(new ContentProducer() {
141 public void writeTo(final OutputStream outstream
) throws IOException
{
142 OutputStreamWriter writer
= new OutputStreamWriter(outstream
, "UTF-8");
143 writer
.write("<html><body><h1>");
144 writer
.write("File ");
145 writer
.write(file
.getPath());
146 writer
.write(" not found");
147 writer
.write("</h1></body></html>");
152 body
.setContentType("text/html; charset=UTF-8");
153 response
.setEntity(body
);
154 System
.out
.println("File " + file
.getPath() + " not found");
156 } else if (!file
.canRead() || file
.isDirectory()) {
158 response
.setStatusCode(HttpStatus
.SC_FORBIDDEN
);
159 EntityTemplate body
= new EntityTemplate(new ContentProducer() {
161 public void writeTo(final OutputStream outstream
) throws IOException
{
162 OutputStreamWriter writer
= new OutputStreamWriter(outstream
, "UTF-8");
163 writer
.write("<html><body><h1>");
164 writer
.write("Access denied");
165 writer
.write("</h1></body></html>");
170 body
.setContentType("text/html; charset=UTF-8");
171 response
.setEntity(body
);
172 System
.out
.println("Cannot read file " + file
.getPath());
176 response
.setStatusCode(HttpStatus
.SC_OK
);
177 FileEntity body
= new FileEntity(file
, "text/html");
178 response
.setEntity(body
);
179 System
.out
.println("Serving file " + file
.getPath());
185 private String
thriftRequest(byte[] input
){
189 TMemoryBuffer inbuffer
= new TMemoryBuffer(input
.length
);
190 inbuffer
.write(input
);
191 TProtocol inprotocol
= new TJSONProtocol(inbuffer
);
194 TMemoryBuffer outbuffer
= new TMemoryBuffer(100);
195 TProtocol outprotocol
= new TJSONProtocol(outbuffer
);
197 TProcessor processor
= new Calculator
.Processor(new CalculatorHandler());
198 processor
.process(inprotocol
, outprotocol
);
200 byte[] output
= new byte[outbuffer
.length()];
201 outbuffer
.readAll(output
, 0, output
.length
);
203 return new String(output
,"UTF-8");
205 return "Error:"+t
.getMessage();
213 static class RequestListenerThread
extends Thread
{
215 private final ServerSocket serversocket
;
216 private final HttpParams params
;
217 private final HttpService httpService
;
219 public RequestListenerThread(int port
, final String docroot
) throws IOException
{
220 this.serversocket
= new ServerSocket(port
);
221 this.params
= new BasicHttpParams();
222 this.params
.setIntParameter(CoreConnectionPNames
.SO_TIMEOUT
, 1000).setIntParameter(CoreConnectionPNames
.SOCKET_BUFFER_SIZE
, 8 * 1024)
223 .setBooleanParameter(CoreConnectionPNames
.STALE_CONNECTION_CHECK
, false).setBooleanParameter(CoreConnectionPNames
.TCP_NODELAY
, true)
224 .setParameter(CoreProtocolPNames
.ORIGIN_SERVER
, "HttpComponents/1.1");
226 // Set up the HTTP protocol processor
227 HttpProcessor httpproc
= new BasicHttpProcessor();
229 // Set up request handlers
230 HttpRequestHandlerRegistry reqistry
= new HttpRequestHandlerRegistry();
231 reqistry
.register("*", new HttpFileHandler(docroot
));
233 // Set up the HTTP service
234 this.httpService
= new HttpService(httpproc
, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory());
235 this.httpService
.setParams(this.params
);
236 this.httpService
.setHandlerResolver(reqistry
);
240 System
.out
.println("Listening on port " + this.serversocket
.getLocalPort());
241 System
.out
.println("Point your browser to http://localhost:8088/tutorial/js/tutorial.html");
243 while (!Thread
.interrupted()) {
245 // Set up HTTP connection
246 Socket socket
= this.serversocket
.accept();
247 DefaultHttpServerConnection conn
= new DefaultHttpServerConnection();
248 System
.out
.println("Incoming connection from " + socket
.getInetAddress());
249 conn
.bind(socket
, this.params
);
251 // Start worker thread
252 Thread t
= new WorkerThread(this.httpService
, conn
);
255 } catch (InterruptedIOException ex
) {
257 } catch (IOException e
) {
258 System
.err
.println("I/O error initialising connection thread: " + e
.getMessage());
265 static class WorkerThread
extends Thread
{
267 private final HttpService httpservice
;
268 private final HttpServerConnection conn
;
270 public WorkerThread(final HttpService httpservice
, final HttpServerConnection conn
) {
272 this.httpservice
= httpservice
;
277 System
.out
.println("New connection thread");
278 HttpContext context
= new BasicHttpContext(null);
280 while (!Thread
.interrupted() && this.conn
.isOpen()) {
281 this.httpservice
.handleRequest(this.conn
, context
);
283 } catch (ConnectionClosedException ex
) {
284 System
.err
.println("Client closed connection");
285 } catch (IOException ex
) {
286 System
.err
.println("I/O error: " + ex
.getMessage());
287 } catch (HttpException ex
) {
288 System
.err
.println("Unrecoverable HTTP protocol violation: " + ex
.getMessage());
291 this.conn
.shutdown();
292 } catch (IOException ignore
) {