001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0-beta1/module-main/src/examples/org/apache/http/examples/ElementalHttpServer.java $
003: * $Revision: 610464 $
004: * $Date: 2008-01-09 18:10:55 +0100 (Wed, 09 Jan 2008) $
005: *
006: * ====================================================================
007: * Licensed to the Apache Software Foundation (ASF) under one
008: * or more contributor license agreements. See the NOTICE file
009: * distributed with this work for additional information
010: * regarding copyright ownership. The ASF licenses this file
011: * to you under the Apache License, Version 2.0 (the
012: * "License"); you may not use this file except in compliance
013: * with the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing,
018: * software distributed under the License is distributed on an
019: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020: * KIND, either express or implied. See the License for the
021: * specific language governing permissions and limitations
022: * under the License.
023: * ====================================================================
024: *
025: * This software consists of voluntary contributions made by many
026: * individuals on behalf of the Apache Software Foundation. For more
027: * information on the Apache Software Foundation, please see
028: * <http://www.apache.org/>.
029: *
030: */
031:
032: package org.apache.http.examples;
033:
034: import java.io.File;
035: import java.io.IOException;
036: import java.io.InterruptedIOException;
037: import java.io.OutputStream;
038: import java.io.OutputStreamWriter;
039: import java.net.ServerSocket;
040: import java.net.Socket;
041: import java.net.URLDecoder;
042:
043: import org.apache.http.ConnectionClosedException;
044: import org.apache.http.HttpEntity;
045: import org.apache.http.HttpEntityEnclosingRequest;
046: import org.apache.http.HttpException;
047: import org.apache.http.HttpRequest;
048: import org.apache.http.HttpResponse;
049: import org.apache.http.HttpServerConnection;
050: import org.apache.http.HttpStatus;
051: import org.apache.http.MethodNotSupportedException;
052: import org.apache.http.entity.ContentProducer;
053: import org.apache.http.entity.EntityTemplate;
054: import org.apache.http.entity.FileEntity;
055: import org.apache.http.impl.DefaultConnectionReuseStrategy;
056: import org.apache.http.impl.DefaultHttpResponseFactory;
057: import org.apache.http.impl.DefaultHttpServerConnection;
058: import org.apache.http.params.BasicHttpParams;
059: import org.apache.http.params.CoreConnectionPNames;
060: import org.apache.http.params.HttpParams;
061: import org.apache.http.params.CoreProtocolPNames;
062: import org.apache.http.protocol.BasicHttpProcessor;
063: import org.apache.http.protocol.HttpContext;
064: import org.apache.http.protocol.BasicHttpContext;
065: import org.apache.http.protocol.HttpRequestHandler;
066: import org.apache.http.protocol.HttpRequestHandlerRegistry;
067: import org.apache.http.protocol.HttpService;
068: import org.apache.http.protocol.ResponseConnControl;
069: import org.apache.http.protocol.ResponseContent;
070: import org.apache.http.protocol.ResponseDate;
071: import org.apache.http.protocol.ResponseServer;
072: import org.apache.http.util.EntityUtils;
073:
074: /**
075: * Basic, yet fully functional and spec compliant, HTTP/1.1 file server.
076: *
077: * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
078: *
079: * @version $Revision: 610464 $
080: */
081: public class ElementalHttpServer {
082:
083: public static void main(String[] args) throws Exception {
084: if (args.length < 1) {
085: System.err
086: .println("Please specify document root directory");
087: System.exit(1);
088: }
089: Thread t = new RequestListenerThread(8080, args[0]);
090: t.setDaemon(false);
091: t.start();
092: }
093:
094: static class HttpFileHandler implements HttpRequestHandler {
095:
096: private final String docRoot;
097:
098: public HttpFileHandler(final String docRoot) {
099: super ();
100: this .docRoot = docRoot;
101: }
102:
103: public void handle(final HttpRequest request,
104: final HttpResponse response, final HttpContext context)
105: throws HttpException, IOException {
106:
107: String method = request.getRequestLine().getMethod()
108: .toUpperCase();
109: if (!method.equals("GET") && !method.equals("HEAD")
110: && !method.equals("POST")) {
111: throw new MethodNotSupportedException(method
112: + " method not supported");
113: }
114: String target = request.getRequestLine().getUri();
115:
116: if (request instanceof HttpEntityEnclosingRequest) {
117: HttpEntity entity = ((HttpEntityEnclosingRequest) request)
118: .getEntity();
119: byte[] entityContent = EntityUtils.toByteArray(entity);
120: System.out.println("Incoming entity content (bytes): "
121: + entityContent.length);
122: }
123:
124: final File file = new File(this .docRoot, URLDecoder
125: .decode(target));
126: if (!file.exists()) {
127:
128: response.setStatusCode(HttpStatus.SC_NOT_FOUND);
129: EntityTemplate body = new EntityTemplate(
130: new ContentProducer() {
131:
132: public void writeTo(
133: final OutputStream outstream)
134: throws IOException {
135: OutputStreamWriter writer = new OutputStreamWriter(
136: outstream, "UTF-8");
137: writer.write("<html><body><h1>");
138: writer.write("File ");
139: writer.write(file.getPath());
140: writer.write(" not found");
141: writer.write("</h1></body></html>");
142: writer.flush();
143: }
144:
145: });
146: body.setContentType("text/html; charset=UTF-8");
147: response.setEntity(body);
148: System.out.println("File " + file.getPath()
149: + " not found");
150:
151: } else if (!file.canRead() || file.isDirectory()) {
152:
153: response.setStatusCode(HttpStatus.SC_FORBIDDEN);
154: EntityTemplate body = new EntityTemplate(
155: new ContentProducer() {
156:
157: public void writeTo(
158: final OutputStream outstream)
159: throws IOException {
160: OutputStreamWriter writer = new OutputStreamWriter(
161: 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
172: .println("Cannot read file " + file.getPath());
173:
174: } else {
175:
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());
180:
181: }
182: }
183:
184: }
185:
186: static class RequestListenerThread extends Thread {
187:
188: private final ServerSocket serversocket;
189: private final HttpParams params;
190: private final String docRoot;
191:
192: public RequestListenerThread(int port, final String docroot)
193: throws IOException {
194: this .serversocket = new ServerSocket(port);
195: this .params = new BasicHttpParams();
196: this .params
197: .setIntParameter(CoreConnectionPNames.SO_TIMEOUT,
198: 5000)
199: .setIntParameter(
200: CoreConnectionPNames.SOCKET_BUFFER_SIZE,
201: 8 * 1024)
202: .setBooleanParameter(
203: CoreConnectionPNames.STALE_CONNECTION_CHECK,
204: false).setBooleanParameter(
205: CoreConnectionPNames.TCP_NODELAY, true)
206: .setParameter(CoreProtocolPNames.ORIGIN_SERVER,
207: "HttpComponents/1.1");
208: this .docRoot = docroot;
209: }
210:
211: public void run() {
212: System.out.println("Listening on port "
213: + this .serversocket.getLocalPort());
214: while (!Thread.interrupted()) {
215: try {
216: // Set up HTTP connection
217: Socket socket = this .serversocket.accept();
218: DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
219: System.out.println("Incoming connection from "
220: + socket.getInetAddress());
221: conn.bind(socket, this .params);
222:
223: // Set up the HTTP protocol processor
224: BasicHttpProcessor httpproc = new BasicHttpProcessor();
225: httpproc.addInterceptor(new ResponseDate());
226: httpproc.addInterceptor(new ResponseServer());
227: httpproc.addInterceptor(new ResponseContent());
228: httpproc.addInterceptor(new ResponseConnControl());
229:
230: // Set up request handlers
231: HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
232: reqistry.register("*", new HttpFileHandler(
233: this .docRoot));
234:
235: // Set up the HTTP service
236: HttpService httpService = new HttpService(httpproc,
237: new DefaultConnectionReuseStrategy(),
238: new DefaultHttpResponseFactory());
239: httpService.setParams(this .params);
240: httpService.setHandlerResolver(reqistry);
241:
242: // Start worker thread
243: Thread t = new WorkerThread(httpService, conn);
244: t.setDaemon(true);
245: t.start();
246: } catch (InterruptedIOException ex) {
247: break;
248: } catch (IOException e) {
249: System.err
250: .println("I/O error initialising connection thread: "
251: + e.getMessage());
252: break;
253: }
254: }
255: }
256: }
257:
258: static class WorkerThread extends Thread {
259:
260: private final HttpService httpservice;
261: private final HttpServerConnection conn;
262:
263: public WorkerThread(final HttpService httpservice,
264: final HttpServerConnection conn) {
265: super ();
266: this .httpservice = httpservice;
267: this .conn = conn;
268: }
269:
270: public void run() {
271: System.out.println("New connection thread");
272: HttpContext context = new BasicHttpContext(null);
273: try {
274: while (!Thread.interrupted() && this .conn.isOpen()) {
275: this .httpservice.handleRequest(this .conn, context);
276: }
277: } catch (ConnectionClosedException ex) {
278: System.err.println("Client closed connection");
279: } catch (IOException ex) {
280: System.err.println("I/O error: " + ex.getMessage());
281: } catch (HttpException ex) {
282: System.err
283: .println("Unrecoverable HTTP protocol violation: "
284: + ex.getMessage());
285: } finally {
286: try {
287: this .conn.shutdown();
288: } catch (IOException ignore) {
289: }
290: }
291: }
292:
293: }
294:
295: }
|