1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.apache.commons.httpclient.server;
31
32 import java.io.IOException;
33 import java.net.InetAddress;
34 import java.net.ServerSocket;
35 import java.net.Socket;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39
40 /***
41 * A simple, but extensible HTTP server, mostly for testing purposes.
42 *
43 * @author Christian Kohlschuetter
44 * @author Oleg Kalnichevski
45 */
46 public class SimpleHttpServer implements Runnable {
47 private static final Log LOG = LogFactory.getLog(SimpleHttpServer.class);
48
49 private String testname = "Simple test";
50 private long count = 0;
51 private ServerSocket listener = null;
52 private Thread t;
53 private ThreadGroup tg;
54 private boolean stopped = false;
55
56 private SimpleConnSet connections = new SimpleConnSet();
57
58 private HttpRequestHandler requestHandler = null;
59
60 /***
61 * Creates a new HTTP server instance, using an arbitrary free TCP port
62 *
63 * @throws IOException if anything goes wrong during initialization
64 */
65 public SimpleHttpServer() throws IOException {
66 this(null, 0);
67 }
68
69 /***
70 * Creates a new HTTP server instance, using the specified socket
71 * factory and the TCP port
72 *
73 * @param port Desired TCP port
74 * @throws IOException if anything goes wrong during initialization
75 */
76 public SimpleHttpServer(SimpleSocketFactory socketfactory, int port)
77 throws IOException {
78 if (socketfactory == null) {
79 socketfactory = new SimplePlainSocketFactory();
80 }
81 listener = socketfactory.createServerSocket(port);
82 if(LOG.isDebugEnabled()) {
83 LOG.debug("Starting test HTTP server on port " + getLocalPort());
84 }
85 tg = new ThreadGroup("SimpleHttpServer thread group");
86 t = new Thread(tg, this, "SimpleHttpServer listener");
87 t.setDaemon(true);
88 t.start();
89 }
90
91 /***
92 * Creates a new HTTP server instance, using the specified TCP port
93 *
94 * @param port Desired TCP port
95 * @throws IOException if anything goes wrong during initialization
96 */
97 public SimpleHttpServer(int port) throws IOException {
98 this(null, port);
99 }
100
101 public String getTestname() {
102 return this.testname;
103 }
104
105 public void setTestname(final String testname) {
106 this.testname = testname;
107 }
108
109 /***
110 * Returns the TCP port that this HTTP server instance is bound to.
111 *
112 * @return TCP port, or -1 if not running
113 */
114 public int getLocalPort() {
115 return listener.getLocalPort();
116 }
117
118 /***
119 * Returns the IP address that this HTTP server instance is bound to.
120 * @return String representation of the IP address or <code>null</code> if not running
121 */
122 public String getLocalAddress() {
123 InetAddress address = listener.getInetAddress();
124
125 byte[] octets = address.getAddress();
126 if ((octets[0] == 0)
127 && (octets[1] == 0)
128 && (octets[2] == 0)
129 && (octets[3] == 0)) {
130 return "localhost";
131 } else {
132 return address.getHostAddress();
133 }
134 }
135
136 /***
137 * Checks if this HTTP server instance is running.
138 *
139 * @return true/false
140 */
141 public boolean isRunning() {
142 if(t == null) {
143 return false;
144 }
145 return t.isAlive();
146 }
147
148 /***
149 * Stops this HTTP server instance.
150 */
151 public synchronized void destroy() {
152 if (stopped) {
153 return;
154 }
155
156 this.stopped = true;
157 if(LOG.isDebugEnabled()) {
158 LOG.debug("Stopping test HTTP server on port " + getLocalPort());
159 }
160 tg.interrupt();
161
162 if (listener != null) {
163 try {
164 listener.close();
165 } catch(IOException e) {
166
167 }
168 }
169 this.connections.shutdown();
170 }
171
172 /***
173 * Returns the currently used HttpRequestHandler by this SimpleHttpServer
174 *
175 * @return The used HttpRequestHandler, or null.
176 */
177 public HttpRequestHandler getRequestHandler() {
178 return requestHandler;
179 }
180
181 /***
182 * Sets the HttpRequestHandler to be used for this SimpleHttpServer.
183 *
184 * @param rh Request handler to be used, or null to disable.
185 */
186 public void setRequestHandler(HttpRequestHandler rh) {
187 this.requestHandler = rh;
188 }
189
190 public void setHttpService(HttpService service) {
191 setRequestHandler(new HttpServiceHandler(service));
192 }
193
194 public void run() {
195 try {
196 while (!this.stopped && !Thread.interrupted()) {
197 Socket socket = listener.accept();
198 try {
199 if (this.requestHandler == null) {
200 socket.close();
201 break;
202 }
203 SimpleHttpServerConnection conn = new SimpleHttpServerConnection(socket);
204 this.connections.addConnection(conn);
205
206 Thread t = new SimpleConnectionThread(
207 tg,
208 this.testname + " thread " + this.count,
209 conn,
210 this.connections,
211 this.requestHandler);
212 t.setDaemon(true);
213 t.start();
214 } catch (IOException e) {
215 LOG.error("I/O error: " + e.getMessage());
216 }
217 this.count++;
218 Thread.sleep(100);
219 }
220 } catch (InterruptedException accept) {
221 } catch (IOException e) {
222 if (!stopped) {
223 LOG.error("I/O error: " + e.getMessage());
224 }
225 } finally {
226 destroy();
227 }
228 }
229 }