1 package org.feistymeow.networking;
7 import org.apache.commons.logging.Log;
8 import org.apache.commons.logging.LogFactory;
11 * Provides a lightweight way for RNS structures to be accessible over http.
13 * @Author Chris Koeritz
17 * original example thanks to Matt Mahoney, at
18 * http://cs.fit.edu/~mmahoney/cse3103/java/Webserver.java
21 public class BasicWebServer
23 static private Log logger = LogFactory.getLog(BasicWebServer.class);
26 private boolean leaving = false; // turns to true when should stop serving.
27 servingThread socketThread;
28 private ServerSocket realSocket;
30 BasicWebServer(int portIn)
35 public void shutDown()
38 if (realSocket != null) {
41 } catch (IOException e) {
44 if (socketThread != null) {
49 public class servingThread implements Runnable
51 private Thread thread;
52 private ServerSocket serverSocket;
54 servingThread(ServerSocket socket)
56 serverSocket = socket;
57 thread = new Thread(this);
66 logger.debug("about to accept on server socket.");
67 Socket s = serverSocket.accept(); // Wait for a client to
69 logger.debug("accepted client, spawning handler.");
70 new ClientHandler(s); // Handle the client in a separate
72 } catch (Throwable cause) {
73 logger.error("exception raised while handling accepted socket", cause);
79 // enums for outcomes? really need better reporting.
80 public int startServing()
82 if (socketThread != null)
83 return 1; // already running outcome.
85 realSocket = new ServerSocket(port);
86 } catch (Throwable cause) {
87 logger.error("failure to start server on port " + port, cause);
89 // socket failure outcome.
91 socketThread = new servingThread(realSocket);
95 public String predictMimeType(String filename)
98 // kludge to try one type:
99 return "text/plain;charset=utf-8";
103 * if (filename.endsWith(".html") || filename.endsWith(".htm")) return "text/html"; if
104 * (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) return "image/jpeg"; if
105 * (filename.endsWith(".gif")) return "image/gif"; if (filename.endsWith(".class")) return
106 * "application/octet-stream"; return "text/plain";
110 // A ClientHandler reads an HTTP request and responds
111 class ClientHandler extends Thread
113 private Socket socket; // The accepted socket from the Webserver
115 // Start the thread in the constructor
116 public ClientHandler(Socket s)
122 // Read the HTTP request, respond, and close the connection
126 logger.debug("into client run(): listening for gets.");
128 // Open connections to the socket
129 BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
130 PrintStream out = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
132 // Read filename from first input line "GET /filename.html ..."
133 // or if not in this format, treat as a file not found.
134 String s = in.readLine();
135 logger.debug("request is: " + s); // Log the request
137 // Attempt to serve the file. Catch FileNotFoundException and
138 // return an HTTP error "404 Not Found". Treat invalid requests
140 String filename = "";
141 StringTokenizer st = new StringTokenizer(s);
144 boolean transferFile = true;
145 // get the command first.
146 String command = st.nextToken();
147 // Parse the filename from the command.
148 if (st.hasMoreElements() && command.equalsIgnoreCase("GET") && st.hasMoreElements()) {
149 filename = st.nextToken();
150 } else if (st.hasMoreElements() && command.equalsIgnoreCase("HEAD") && st.hasMoreElements()) {
151 filename = st.nextToken();
152 transferFile = false; // don't need to do that, just the
155 logger.error("going to blow file not found exception now.");
156 throw new FileNotFoundException(); // Bad request
158 logger.info("filename to handle is now: " + filename);
160 // Append trailing "/" with "index.html"
161 // /hmmm: may want to make this assume directory.
162 if (filename.endsWith("/"))
163 logger.error("unhandled attempt to get item ending in slash");
164 // if (filename.endsWith("/"))
165 // filename += "index.html";
167 // Remove leading / from filename
168 // / while (filename.indexOf("/") == 0)
169 // / filename = filename.substring(1);
171 // Replace "/" with "\" in path for PC-based servers
172 filename = filename.replace('/', File.separator.charAt(0));
174 logger.info("asking for rns path of " + filename);
176 // Check for illegal characters to prevent access to
178 if (filename.indexOf("..") >= 0 || filename.indexOf(':') >= 0 || filename.indexOf('|') >= 0)
179 throw new FileNotFoundException();
181 logger.info("got past filename checks for: " + filename);
184 * this doesn't actually check that trailing slash is missing! // If a directory
185 * is requested and the trailing / is missing, // send the client an HTTP
186 * request to append it. (This is // necessary for relative links to work
187 * correctly in the client). if ((new GeniiPath(filename)).isDirectory()) {
188 * out.print("HTTP/1.0 301 Moved Permanently\r\n" + "Location: /" + filename +
189 * "/\r\n\r\n"); out.close(); return; }
192 // trying to get around worrying about mime types by saying
193 // "just get this there".
194 String mimeType = predictMimeType(filename);
195 // //"application/octet-stream";
197 File source = new File(filename);
198 if (!source.exists()) {
199 logger.error("source does not exist for serving: " + filename);
201 // hmmm: below could be abstracted to more general
203 out.println("HTTP/1.1 404 Not Found\r\n" + "Content-type: text/html\r\n\r\n"
204 + "<html><head></head><body>" + filename + " not found</body></html>\n");
208 out.print("HTTP/1.1 200 OK\r\n" + "Content-type: " + mimeType + "\r\n" + "Connection: close" + "\r\n"
209 // // + "\r\nContent-Length: " + source.size? +
213 logger.debug("closing stream for finished HEAD request.");
217 logger.debug("moving to handle GET request.");
218 FileInputStream f = new FileInputStream(filename);
219 logger.debug("opened stream on source");
220 // Send file contents to client, then close the connection.
221 byte[] a = new byte[4096];
223 while ((n = f.read(a)) > 0)
225 logger.debug("wrote file back for request, closing stream.");
228 } catch (FileNotFoundException x) {
229 logger.error("failed to find requested file: " + filename);
230 out.println("HTTP/1.1 404 Not Found\r\n" + "Content-type: text/html\r\n\r\n" + "<html><head></head><body>"
231 + filename + " not found</body></html>\n");
234 } catch (IOException x) {
235 logger.error("exception blew out in outer area of web server", x);
236 // / System.out.println(x);