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(0);
67 }
68
69 /***
70 * Creates a new HTTP server instance, using the specified TCP port
71 *
72 * @param port Desired TCP port
73 * @throws IOException if anything goes wrong during initialization
74 */
75 public SimpleHttpServer(int port) throws IOException {
76 listener = new ServerSocket(port);
77 if(LOG.isDebugEnabled()) {
78 LOG.debug("Starting test HTTP server on port " + getLocalPort());
79 }
80 tg = new ThreadGroup("SimpleHttpServer thread group");
81 t = new Thread(tg, this, "SimpleHttpServer listener");
82 t.setDaemon(true);
83 t.start();
84 }
85
86 public String getTestname() {
87 return this.testname;
88 }
89
90 public void setTestname(final String testname) {
91 this.testname = testname;
92 }
93
94 /***
95 * Returns the TCP port that this HTTP server instance is bound to.
96 *
97 * @return TCP port, or -1 if not running
98 */
99 public int getLocalPort() {
100 return listener.getLocalPort();
101 }
102
103 /***
104 * Returns the IP address that this HTTP server instance is bound to.
105 * @return String representation of the IP address or <code>null</code> if not running
106 */
107 public String getLocalAddress() {
108 InetAddress address = listener.getInetAddress();
109
110 byte[] octets = address.getAddress();
111 if ((octets[0] == 0)
112 && (octets[1] == 0)
113 && (octets[2] == 0)
114 && (octets[3] == 0)) {
115 return "localhost";
116 } else {
117 return address.getHostAddress();
118 }
119 }
120
121 /***
122 * Checks if this HTTP server instance is running.
123 *
124 * @return true/false
125 */
126 public boolean isRunning() {
127 if(t == null) {
128 return false;
129 }
130 return t.isAlive();
131 }
132
133 /***
134 * Stops this HTTP server instance.
135 */
136 public void destroy() {
137 if (stopped) {
138 return;
139 }
140
141 stopped = true;
142 if(LOG.isDebugEnabled()) {
143 LOG.debug("Stopping test HTTP server on port " + getLocalPort());
144 }
145
146 tg.interrupt();
147
148 if (listener != null) {
149 try {
150 listener.close();
151 } catch(IOException e) {
152
153 }
154 }
155 this.connections.shutdown();
156 }
157
158 /***
159 * Returns the currently used HttpRequestHandler by this SimpleHttpServer
160 *
161 * @return The used HttpRequestHandler, or null.
162 */
163 public HttpRequestHandler getRequestHandler() {
164 return requestHandler;
165 }
166
167 /***
168 * Sets the HttpRequestHandler to be used for this SimpleHttpServer.
169 *
170 * @param rh Request handler to be used, or null to disable.
171 */
172 public void setRequestHandler(HttpRequestHandler rh) {
173 this.requestHandler = rh;
174 }
175
176 public void setHttpService(HttpService service) {
177 setRequestHandler(new HttpServiceHandler(service));
178 }
179
180 public void run() {
181 try {
182 while (!Thread.interrupted()) {
183 Socket socket = listener.accept();
184 try {
185 if (this.requestHandler == null) {
186 socket.close();
187 break;
188 }
189 SimpleHttpServerConnection conn = new SimpleHttpServerConnection(socket);
190 this.connections.addConnection(conn);
191
192 Thread t = new SimpleConnectionThread(
193 tg,
194 this.testname + " thread " + this.count,
195 conn,
196 this.connections,
197 this.requestHandler);
198 t.setDaemon(true);
199 t.start();
200 } catch (IOException e) {
201 LOG.error("I/O error: " + e.getMessage());
202 }
203 this.count++;
204 Thread.sleep(100);
205 }
206 } catch (InterruptedException accept) {
207 } catch (IOException e) {
208 if (!stopped) {
209 LOG.error("I/O error: " + e.getMessage());
210 }
211 } finally {
212 destroy();
213 }
214 }
215 }