1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpServer.java $
3 * $Revision: 576077 $
4 * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
5 *
6 * ====================================================================
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements.  See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership.  The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License.  You may obtain a copy of the License at
14 *
15 *   http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied.  See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 * ====================================================================
24 *
25 * This software consists of voluntary contributions made by many
26 * individuals on behalf of the Apache Software Foundation.  For more
27 * information on the Apache Software Foundation, please see
28 * <http://www.apache.org/>.
29 *
30 */
31
32package com.android.unit_tests;
33
34
35import java.io.IOException;
36import java.io.InterruptedIOException;
37import java.net.InetAddress;
38import java.net.ServerSocket;
39import java.net.Socket;
40
41import org.apache.http.ConnectionClosedException;
42import org.apache.http.ConnectionReuseStrategy;
43import org.apache.http.HttpException;
44import org.apache.http.HttpResponseFactory;
45import org.apache.http.HttpServerConnection;
46import org.apache.http.impl.DefaultConnectionReuseStrategy;
47import org.apache.http.impl.DefaultHttpResponseFactory;
48import org.apache.http.impl.DefaultHttpServerConnection;
49import org.apache.http.params.BasicHttpParams;
50import org.apache.http.params.CoreConnectionPNames;
51import org.apache.http.params.HttpParams;
52import org.apache.http.params.CoreProtocolPNames;
53import org.apache.http.protocol.BasicHttpProcessor;
54import org.apache.http.protocol.HttpContext;
55import org.apache.http.protocol.BasicHttpContext;
56import org.apache.http.protocol.HttpExpectationVerifier;
57import org.apache.http.protocol.HttpRequestHandler;
58import org.apache.http.protocol.HttpRequestHandlerRegistry;
59import org.apache.http.protocol.HttpService;
60import org.apache.http.protocol.ResponseConnControl;
61import org.apache.http.protocol.ResponseContent;
62import org.apache.http.protocol.ResponseDate;
63import org.apache.http.protocol.ResponseServer;
64
65public class TestHttpServer {
66
67    private final HttpParams params;
68    private final BasicHttpProcessor httpproc;
69    private final ConnectionReuseStrategy connStrategy;
70    private final HttpResponseFactory responseFactory;
71    private final HttpRequestHandlerRegistry reqistry;
72    private final ServerSocket serversocket;
73
74    private HttpExpectationVerifier expectationVerifier;
75
76    private Thread listener;
77    private volatile boolean shutdown;
78
79    public TestHttpServer() throws IOException {
80        super();
81        this.params = new BasicHttpParams();
82        this.params
83            .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
84            .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
85            .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
86            .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
87            .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "TEST-SERVER/1.1");
88        this.httpproc = new BasicHttpProcessor();
89        this.httpproc.addInterceptor(new ResponseDate());
90        this.httpproc.addInterceptor(new ResponseServer());
91        this.httpproc.addInterceptor(new ResponseContent());
92        this.httpproc.addInterceptor(new ResponseConnControl());
93        this.connStrategy = new DefaultConnectionReuseStrategy();
94        this.responseFactory = new DefaultHttpResponseFactory();
95        this.reqistry = new HttpRequestHandlerRegistry();
96        this.serversocket = new ServerSocket(0);
97    }
98
99    public void registerHandler(
100            final String pattern,
101            final HttpRequestHandler handler) {
102        this.reqistry.register(pattern, handler);
103    }
104
105    public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
106        this.expectationVerifier = expectationVerifier;
107    }
108
109    private HttpServerConnection acceptConnection() throws IOException {
110        Socket socket = this.serversocket.accept();
111        DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
112        conn.bind(socket, this.params);
113        return conn;
114    }
115
116    public int getPort() {
117        return this.serversocket.getLocalPort();
118    }
119
120    public InetAddress getInetAddress() {
121        return this.serversocket.getInetAddress();
122    }
123
124    public void start() {
125        if (this.listener != null) {
126            throw new IllegalStateException("Listener already running");
127        }
128        this.listener = new Thread(new Runnable() {
129
130            public void run() {
131                while (!shutdown && !Thread.interrupted()) {
132                    try {
133                        // Set up HTTP connection
134                        HttpServerConnection conn = acceptConnection();
135                        // Set up the HTTP service
136                        HttpService httpService = new HttpService(
137                                httpproc,
138                                connStrategy,
139                                responseFactory);
140                        httpService.setParams(params);
141                        httpService.setExpectationVerifier(expectationVerifier);
142                        httpService.setHandlerResolver(reqistry);
143
144                        // Start worker thread
145                        Thread t = new WorkerThread(httpService, conn);
146                        t.setDaemon(true);
147                        t.start();
148                    } catch (InterruptedIOException ex) {
149                        break;
150                    } catch (IOException e) {
151                        break;
152                    }
153                }
154            }
155
156        });
157        this.listener.start();
158    }
159
160    public void shutdown() {
161        if (this.shutdown) {
162            return;
163        }
164        this.shutdown = true;
165        try {
166            this.serversocket.close();
167        } catch (IOException ignore) {}
168        this.listener.interrupt();
169        try {
170            this.listener.join(1000);
171        } catch (InterruptedException ignore) {}
172    }
173
174    static class WorkerThread extends Thread {
175
176        private final HttpService httpservice;
177        private final HttpServerConnection conn;
178
179        public WorkerThread(
180                final HttpService httpservice,
181                final HttpServerConnection conn) {
182            super();
183            this.httpservice = httpservice;
184            this.conn = conn;
185        }
186
187        public void run() {
188            HttpContext context = new BasicHttpContext(null);
189            try {
190                while (!Thread.interrupted() && this.conn.isOpen()) {
191                    this.httpservice.handleRequest(this.conn, context);
192                }
193            } catch (ConnectionClosedException ex) {
194            } catch (IOException ex) {
195                System.err.println("I/O error: " + ex.getMessage());
196            } catch (HttpException ex) {
197                System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
198            } finally {
199                try {
200                    this.conn.shutdown();
201                } catch (IOException ignore) {}
202            }
203        }
204
205    }
206
207}
208