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