blob: 0ed051e96123a3b59646686b144b023c2ddb1a7c [file] [log] [blame]
T Jake Luciani322caa22010-02-15 03:24:55 +00001/*
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
28package test;
29
30import java.io.File;
31import java.io.IOException;
32import java.io.InterruptedIOException;
33import java.io.OutputStream;
34import java.io.OutputStreamWriter;
35import java.net.ServerSocket;
36import java.net.Socket;
37import java.net.URLDecoder;
38import java.util.Locale;
39
40import org.apache.http.ConnectionClosedException;
41import org.apache.http.HttpEntity;
42import org.apache.http.HttpEntityEnclosingRequest;
43import org.apache.http.HttpException;
44import org.apache.http.HttpRequest;
45import org.apache.http.HttpResponse;
46import org.apache.http.HttpServerConnection;
47import org.apache.http.HttpStatus;
48import org.apache.http.MethodNotSupportedException;
49import org.apache.http.entity.ContentProducer;
50import org.apache.http.entity.EntityTemplate;
51import org.apache.http.entity.FileEntity;
52import org.apache.http.impl.DefaultHttpResponseFactory;
53import org.apache.http.impl.DefaultHttpServerConnection;
54import org.apache.http.impl.NoConnectionReuseStrategy;
55import org.apache.http.params.BasicHttpParams;
56import org.apache.http.params.CoreConnectionPNames;
57import org.apache.http.params.CoreProtocolPNames;
58import org.apache.http.params.HttpParams;
59import org.apache.http.protocol.BasicHttpContext;
60import org.apache.http.protocol.BasicHttpProcessor;
61import org.apache.http.protocol.HttpContext;
62import org.apache.http.protocol.HttpProcessor;
63import org.apache.http.protocol.HttpRequestHandler;
64import org.apache.http.protocol.HttpRequestHandlerRegistry;
65import org.apache.http.protocol.HttpService;
66import org.apache.http.util.EntityUtils;
67import org.apache.thrift.TProcessor;
68import org.apache.thrift.protocol.TJSONProtocol;
69import org.apache.thrift.protocol.TProtocol;
70import org.apache.thrift.transport.TMemoryBuffer;
71
72import thrift.test.ThriftTest;
Roger Meier37b5bf82010-10-24 21:41:24 +000073import org.apache.thrift.server.ServerTestBase.TestHandler;
T Jake Luciani322caa22010-02-15 03:24:55 +000074
75/**
76 * Basic, yet fully functional and spec compliant, HTTP/1.1 file server.
77 * <p>
78 * Please note the purpose of this application is demonstrate the usage of
79 * HttpCore APIs. It is NOT intended to demonstrate the most efficient way of
80 * building an HTTP file server.
81 *
82 *
83 */
84public class Httpd {
85
86 public static void main(String[] args) throws Exception {
87 if (args.length < 1) {
88 System.err.println("Please specify document root directory");
89 System.exit(1);
90 }
91 Thread t = new RequestListenerThread(8088, args[0]);
92 t.setDaemon(false);
93 t.start();
94 }
95
96 static class HttpFileHandler implements HttpRequestHandler {
97
98 private final String docRoot;
99
100 public HttpFileHandler(final String docRoot) {
101 super();
102 this.docRoot = docRoot;
103 }
104
105 public void handle(final HttpRequest request, final HttpResponse response, final HttpContext context) throws HttpException, IOException {
106
107 String method = request.getRequestLine().getMethod().toUpperCase(Locale.ENGLISH);
108 if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) {
109 throw new MethodNotSupportedException(method + " method not supported");
110 }
111 String target = request.getRequestLine().getUri();
112
113 if (request instanceof HttpEntityEnclosingRequest && target.equals("/service")) {
114 HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
115 byte[] entityContent = EntityUtils.toByteArray(entity);
116 System.out.println("Incoming content: " + new String(entityContent));
117
118 final String output = this.thriftRequest(entityContent);
119
120 System.out.println("Outgoing content: "+output);
121
122 EntityTemplate body = new EntityTemplate(new ContentProducer() {
123
124 public void writeTo(final OutputStream outstream) throws IOException {
125 OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
126 writer.write(output);
127 writer.flush();
128 }
129
130 });
131 body.setContentType("text/html; charset=UTF-8");
132 response.setEntity(body);
133 } else {
Roger Meier0b267252011-07-29 21:08:04 +0000134 if(target.indexOf("?") != -1) {
135 target = target.substring(1, target.indexOf("?"));
136 }
T Jake Luciani322caa22010-02-15 03:24:55 +0000137
Roger Meier0b267252011-07-29 21:08:04 +0000138 final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8"));
139
T Jake Luciani322caa22010-02-15 03:24:55 +0000140 if (!file.exists()) {
141
142 response.setStatusCode(HttpStatus.SC_NOT_FOUND);
143 EntityTemplate body = new EntityTemplate(new ContentProducer() {
144
145 public void writeTo(final OutputStream outstream) throws IOException {
146 OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
147 writer.write("<html><body><h1>");
148 writer.write("File ");
149 writer.write(file.getPath());
150 writer.write(" not found");
151 writer.write("</h1></body></html>");
152 writer.flush();
153 }
154
155 });
156 body.setContentType("text/html; charset=UTF-8");
157 response.setEntity(body);
158 System.out.println("File " + file.getPath() + " not found");
159
160 } else if (!file.canRead() || file.isDirectory()) {
161
162 response.setStatusCode(HttpStatus.SC_FORBIDDEN);
163 EntityTemplate body = new EntityTemplate(new ContentProducer() {
164
165 public void writeTo(final OutputStream outstream) throws IOException {
166 OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
167 writer.write("<html><body><h1>");
168 writer.write("Access denied");
169 writer.write("</h1></body></html>");
170 writer.flush();
171 }
172
173 });
174 body.setContentType("text/html; charset=UTF-8");
175 response.setEntity(body);
176 System.out.println("Cannot read file " + file.getPath());
177
178 } else {
179
180 response.setStatusCode(HttpStatus.SC_OK);
181 FileEntity body = new FileEntity(file, "text/html");
182 response.setEntity(body);
183 System.out.println("Serving file " + file.getPath());
184
185 }
186 }
187 }
188
189 private String thriftRequest(byte[] input){
190 try{
191
192 //Input
193 TMemoryBuffer inbuffer = new TMemoryBuffer(input.length);
194 inbuffer.write(input);
195 TProtocol inprotocol = new TJSONProtocol(inbuffer);
196
197 //Output
198 TMemoryBuffer outbuffer = new TMemoryBuffer(100);
199 TProtocol outprotocol = new TJSONProtocol(outbuffer);
200
201 TProcessor processor = new ThriftTest.Processor(new TestHandler());
202 processor.process(inprotocol, outprotocol);
203
204 byte[] output = new byte[outbuffer.length()];
205 outbuffer.readAll(output, 0, output.length);
206
207 return new String(output,"UTF-8");
208 }catch(Throwable t){
209 return "Error:"+t.getMessage();
210 }
211
212
213 }
214
215 }
216
217 static class RequestListenerThread extends Thread {
218
219 private final ServerSocket serversocket;
220 private final HttpParams params;
221 private final HttpService httpService;
222
223 public RequestListenerThread(int port, final String docroot) throws IOException {
224 this.serversocket = new ServerSocket(port);
225 this.params = new BasicHttpParams();
226 this.params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 1000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
227 .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
228 .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
229
230 // Set up the HTTP protocol processor
231 HttpProcessor httpproc = new BasicHttpProcessor();
232
233 // Set up request handlers
234 HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
235 reqistry.register("*", new HttpFileHandler(docroot));
236
237 // Set up the HTTP service
238 this.httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory());
239 this.httpService.setParams(this.params);
240 this.httpService.setHandlerResolver(reqistry);
241 }
242
243 public void run() {
244 System.out.println("Listening on port " + this.serversocket.getLocalPort());
245 System.out.println("Point your browser to http://localhost:8088/test/test.html");
246
247 while (!Thread.interrupted()) {
248 try {
249 // Set up HTTP connection
250 Socket socket = this.serversocket.accept();
251 DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
252 System.out.println("Incoming connection from " + socket.getInetAddress());
253 conn.bind(socket, this.params);
254
255 // Start worker thread
256 Thread t = new WorkerThread(this.httpService, conn);
257 t.setDaemon(true);
258 t.start();
259 } catch (InterruptedIOException ex) {
260 break;
261 } catch (IOException e) {
262 System.err.println("I/O error initialising connection thread: " + e.getMessage());
263 break;
264 }
265 }
266 }
267 }
268
269 static class WorkerThread extends Thread {
270
271 private final HttpService httpservice;
272 private final HttpServerConnection conn;
273
274 public WorkerThread(final HttpService httpservice, final HttpServerConnection conn) {
275 super();
276 this.httpservice = httpservice;
277 this.conn = conn;
278 }
279
280 public void run() {
281 System.out.println("New connection thread");
282 HttpContext context = new BasicHttpContext(null);
283 try {
284 while (!Thread.interrupted() && this.conn.isOpen()) {
285 this.httpservice.handleRequest(this.conn, context);
286 }
287 } catch (ConnectionClosedException ex) {
288 System.err.println("Client closed connection");
289 } catch (IOException ex) {
290 System.err.println("I/O error: " + ex.getMessage());
291 } catch (HttpException ex) {
292 System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
293 } finally {
294 try {
295 this.conn.shutdown();
296 } catch (IOException ignore) {
297 }
298 }
299 }
300
301 }
302
303}