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