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