Created
January 22, 2013 03:24
-
-
Save strattondev/4591812 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.io.PrintWriter; | |
import java.net.ServerSocket; | |
import java.net.Socket; | |
import java.util.StringTokenizer; | |
import java.lang.Integer; | |
import java.io.DataInputStream; | |
import java.io.FileInputStream; | |
import java.io.BufferedWriter; | |
import java.io.FileWriter; | |
import java.util.regex.*; | |
import java.lang.Thread; | |
import java.util.ArrayList; | |
public class myhttpd { | |
public static void main(String[] args) { | |
if (args.length != 1) { | |
System.err.println("Please enter a port number to listen on"); | |
System.exit(1); | |
} | |
final int SERVER_PORT = Integer.valueOf(args[0]); | |
ServerSocket serverSocket = null; | |
String servPath = getServerPath(); | |
//String servPath = "/home/wstratto/html/"; | |
String[] contentTypes = getContentTypes(); | |
int sizePool = getPoolSize(); | |
int sizeQueue = getQueueSize(); | |
ArrayList<Connection> csPool = new ArrayList<Connection>(); | |
ArrayList<Connection> csQueue = new ArrayList<Connection>(); | |
try { | |
serverSocket = new ServerSocket(SERVER_PORT); | |
} catch (IOException e) { | |
System.err.println("Could not listen on port: " + SERVER_PORT); | |
System.exit(1); | |
} | |
System.out.println("Waiting for connections..."); | |
while (true) { | |
Socket clientSocket = null; | |
try { | |
clientSocket = serverSocket.accept(); | |
System.out.println("Connection Accepted -> " + clientSocket.toString()); | |
Connection cs = new Connection(clientSocket, servPath); | |
// Check for available openings in the POOL | |
// If availability found, adds the connection to the pool | |
if (csPool.size() < sizePool) { | |
csPool.add(cs); | |
} // No availability in the POOL, checking to see if room in QUEUE | |
else if (csQueue.size() < sizeQueue) { | |
csQueue.add(cs); | |
} | |
int con = csPool.indexOf(cs); | |
cs = csPool.get(con); | |
cs.start(); | |
} catch (IOException e) { | |
System.err.println("Accept failed."); | |
System.exit(1); | |
} | |
// Checks for dead connections and removes them from the list | |
for (Connection c : csPool) { | |
if (!c.isAlive()) { | |
csPool.remove(c); | |
// Dead connection found | |
// Replacing with first connection from the QUEUE and starts the connection | |
if (csQueue.size() > 0) { | |
Connection cs = csQueue.get(0); | |
csPool.add(cs); | |
csQueue.remove(cs); | |
int con = csPool.indexOf(cs); | |
cs = csPool.get(con); | |
cs.start(); | |
} | |
} | |
} | |
} | |
} | |
private static String[] getContentTypes() { | |
String line = ""; | |
try { | |
FileInputStream fs = new FileInputStream("myhttpd.conf"); | |
DataInputStream in = new DataInputStream(fs); | |
BufferedReader br = new BufferedReader(new InputStreamReader(in)); | |
line = br.readLine(); | |
line = br.readLine(); | |
} catch (Exception e) { | |
System.err.println("Error reading myhttpd.conf: " + e.getMessage()); | |
System.exit(0); | |
} | |
StringTokenizer token = new StringTokenizer(line); | |
String[] contentTypes = new String[token.countTokens() - 1]; | |
token.nextToken(); | |
int i = 0; | |
while (token.hasMoreTokens()) { | |
contentTypes[i] = token.nextToken(); | |
++i; | |
} | |
return contentTypes; | |
} | |
private static int getPoolSize() { | |
String line; | |
try { | |
FileInputStream fs = new FileInputStream("myhttpd.conf"); | |
DataInputStream in = new DataInputStream(fs); | |
BufferedReader br = new BufferedReader(new InputStreamReader(in)); | |
while(!(line = br.readLine()).isEmpty()) { | |
if (line.contains("POOL")) { | |
String[] s = line.split(" "); | |
return Integer.valueOf(s[1]); | |
} | |
} | |
} catch (Exception e) { | |
System.err.println("Error reading myhttpd.conf: " + e.getMessage()); | |
System.exit(0); | |
} | |
return 0; | |
} | |
private static int getQueueSize() { | |
String line; | |
try { | |
FileInputStream fs = new FileInputStream("myhttpd.conf"); | |
DataInputStream in = new DataInputStream(fs); | |
BufferedReader br = new BufferedReader(new InputStreamReader(in)); | |
while(!(line = br.readLine()).isEmpty()) { | |
if (line.contains("QUEUE")) { | |
String[] s = line.split(" "); | |
return Integer.valueOf(s[1]); | |
} | |
} | |
} catch (Exception e) { | |
System.err.println("Error reading myhttpd.conf: " + e.getMessage()); | |
System.exit(0); | |
} | |
return 0; | |
} | |
private static String getServerPath() { | |
String line = ""; | |
try { | |
FileInputStream fs = new FileInputStream("myhttpd.conf"); | |
DataInputStream in = new DataInputStream(fs); | |
BufferedReader br = new BufferedReader(new InputStreamReader(in)); | |
line = br.readLine(); | |
} catch (Exception e) { | |
System.err.println("Error reading myhttpd.conf: " + e.getMessage()); | |
System.exit(0); | |
} | |
line = line.replace("HTTP1.0 [", ""); | |
line = line.replace("]", ""); | |
if (line.equalsIgnoreCase("")) { | |
System.err.println("Unknownk error reading myhttpd.conf"); | |
System.exit(0); | |
} | |
return line; | |
} | |
} | |
class Connection extends Thread { | |
private static String SERVER_NAME = "Tom & Wesley CPS 730"; | |
private Socket clientSocket = null; | |
private String servPath = ""; | |
public Connection(Socket clientSocket, String servPath) { | |
this.clientSocket = clientSocket; | |
this.servPath = servPath; | |
} | |
public void run() { | |
System.out.println("Thread -> " + this.clientSocket.toString()); | |
PrintWriter out=null; | |
BufferedReader in=null; | |
try { | |
out = new PrintWriter(clientSocket.getOutputStream(), true); | |
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); | |
out.flush(); | |
String s; | |
while (!(s = in.readLine()).isEmpty()) { | |
if(s.length() > 0) { | |
System.out.println("REQUEST: " + s); | |
if (verifyRequest(s)) { | |
StringTokenizer tokens = new StringTokenizer(s); | |
// Unfortunately Java won't do Switch on strings. | |
String httpRequest = tokens.nextToken(); | |
if(httpRequest.equals("GET")) { | |
String fileRequested = tokens.nextToken(); | |
if (fileRequested.equals("/REPEAT.html")) { | |
for (;;) { | |
out.write("REPEATING" + System.currentTimeMillis() + "\n"); | |
out.flush(); | |
} | |
} | |
if(fileRequested.equals("/")) { // If the root is requested | |
fileRequested += "index.html"; // Show the index.html page | |
} | |
File reqFile = new File(getRequestedFile(this.servPath, fileRequested)); | |
System.out.println("File " + fileRequested + " was requested."); | |
if(reqFile.exists() && reqFile.canRead()) { | |
try { | |
FileReader fText = new FileReader(reqFile); | |
BufferedReader bfFile = new BufferedReader(fText); | |
out.write(getRequestHeader(reqFile, fileRequested, 200)); | |
String line; | |
while ((line = bfFile.readLine()) != null) { | |
out.write(line); | |
out.write("\n"); | |
} | |
bfFile.close(); | |
System.out.println("The file was served."); | |
} catch(IOException e) { | |
out.write("The file you have requested (" + fileRequested + ") could not be served: " + e.getMessage()); | |
System.out.println("An IO exception occured."); | |
} | |
} | |
else if (reqFile.exists() && !reqFile.canRead()) { | |
out.write(getRequestHeader(reqFile, fileRequested, 403)); | |
System.out.println("403 return on file " + fileRequested + " from " + clientSocket.toString()); | |
} | |
else { | |
out.write(getRequestHeader(reqFile, fileRequested, 404)); | |
System.out.println("404 return on file " + fileRequested); | |
} | |
out.flush(); | |
} | |
else if (httpRequest.equals("HEAD")) { | |
String fileRequested = tokens.nextToken(); | |
if(fileRequested.equals("/")) { // If the root is requested | |
fileRequested += "index.html"; // Show the index.html page | |
} | |
File reqFile = new File(getRequestedFile(this.servPath, fileRequested)); | |
System.out.println("File Header " + fileRequested + " was requested."); | |
if (reqFile.exists() && reqFile.canRead()) | |
out.write(getRequestHeader(reqFile, fileRequested, 200)); | |
else if (reqFile.exists() && !reqFile.canRead()) | |
out.write(getRequestHeader(reqFile, fileRequested, 403)); | |
else | |
out.write(getRequestHeader(reqFile, fileRequested, 404)); | |
out.flush(); | |
} | |
else if (httpRequest.equals("POST")) { | |
String fileRequested = tokens.nextToken(); | |
int contentLen = -1; | |
// Get Content-Length: ### | |
while (!(s = in.readLine()).isEmpty()) { | |
if (verifyContentLength(s)) { | |
//Sets the amount of bytes that we expect to receive | |
s = s.replace("Content-Length: ", ""); | |
contentLen = Integer.valueOf(s); | |
} | |
else { | |
out.write(getRequestHeader(new File("/index.html"), fileRequested, 400)); | |
out.flush(); | |
} | |
} | |
if (contentLen != -1) { // Verifies that Content-Length: passed | |
while(!(s = in.readLine()).isEmpty()) { | |
if (s.length() > contentLen) { | |
// Sent bytes > than what we expected | |
out.write(getRequestHeader(new File("/index.html"), fileRequested, 400)); | |
} | |
else { | |
// Something here that makes the file that was posted and then confiming that it was created | |
try { | |
FileWriter fw = new FileWriter(this.servPath + fileRequested); | |
BufferedWriter bw = new BufferedWriter(fw); | |
bw.write(s); | |
bw.close(); | |
out.write(getRequestHeader(new File(this.servPath + fileRequested), fileRequested, 201)); | |
} catch (Exception e) { | |
out.write(getRequestHeader(new File("/index.html"), fileRequested, 400)); | |
} | |
} | |
out.flush(); | |
break; | |
} | |
} | |
} | |
else { | |
String fileRequested = tokens.nextToken(); | |
if(fileRequested.equals("/")) { // If the root is requested | |
fileRequested += "index.html"; // Show the index.html page | |
} | |
out.write(getRequestHeader(new File("/index.html"), fileRequested, 501)); | |
out.flush(); | |
System.err.println("Invalid request: " + s); | |
} | |
//System.exit(0); | |
} | |
else { | |
out.write(getRequestHeader(new File("/index.html"), "/index.html", 400)); | |
out.flush(); | |
} | |
} | |
break; | |
} | |
out.close(); | |
in.close(); | |
clientSocket.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
private static String getRequestedFile(String path, String fileName) { | |
String reqFile = path + fileName; | |
File f = new File(reqFile); | |
if (!f.exists() && fileName.contains(".htm")) { | |
if (fileName.contains(".html")) { | |
reqFile = reqFile.replace(".html", ".htm"); | |
} | |
else { | |
reqFile = reqFile.replace(".htm", ".html"); | |
} | |
} | |
return reqFile; | |
} | |
private static String getRequestHeader(File f, String s, int d) { | |
String r = ""; | |
switch (d) { | |
case 200: | |
r += "HTTP/1.0 200 OK\r\n"; | |
break; | |
case 201: | |
r += "HTTP/1.0 201 Created\r\n"; | |
break; | |
case 400: | |
r += "HTTP/1.0 400 Bad Request\r\n"; | |
break; | |
case 403: | |
r += "HTTP/1.0 403 Forbidden\r\n"; | |
break; | |
case 404: | |
r += "HTTP/1.0 404 Not Found\r\n"; | |
break; | |
case 501: | |
r += "HTTP/1.0 501 Not Implemented\r\n"; | |
break; | |
default: | |
break; | |
} | |
r += "Server:" + SERVER_NAME + "\r\n"; | |
r += "Content-Type: " + getMIMEType(s) + "\r\n"; | |
r += "Content-Length: " + f.length() + "; charset=UTF-8\r\n"; | |
r += "\r\n"; | |
return r; | |
} | |
private static String getMIMEType(String s) { | |
if (s.contains(".htm")) | |
return "text/html"; | |
else if (s.contains(".jpg") || s.contains(".jpeg")) | |
return "image/jpeg"; | |
else if (s.contains(".gif")) | |
return "image/gif"; | |
else if (s.contains(".png")) | |
return "image/png"; | |
else if (s.contains(".css")) | |
return "text/css"; | |
return ""; | |
} | |
private static boolean verifyRequest(String str) { | |
boolean isVerified = false; | |
String s = str; | |
String[] commands = {"(GET)", "(HEAD)", "(POST)"}; | |
String whiteSpace="(\\s+)"; // White Space 1 | |
String filePath="((?:\\/[\\w\\.\\-]+)+)"; // Unix Path 1 | |
String wordHTTP="(HTTP)"; // Word 2 | |
String wordHTTPVer="(\\/1\\.0)"; // Unix Path 2 | |
if (s.contains(" / ")) { | |
s = s.replace(" / ", " /index.html "); | |
} | |
for (int i = 0; i < commands.length; ++i) { | |
//System.out.println(commands[i] + whiteSpace + filePath + whiteSpace + wordHTTP + wordHTTPVer); | |
Pattern p = Pattern.compile(commands[i] + whiteSpace + filePath + whiteSpace + wordHTTP + wordHTTPVer, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); | |
Matcher m = p.matcher(s); | |
if (m.find()) { | |
isVerified = true; | |
break; | |
} | |
} | |
return isVerified; | |
} | |
private static boolean verifyContentLength(String s) { | |
String content = "(Content)", hyphen = "(-)", length = "(Length)", | |
colon = "(:)", whiteSpace = "(\\s+)", intNumber = "(\\d+)"; | |
Pattern p = Pattern.compile(content + hyphen + length + colon + whiteSpace + intNumber, Pattern.CASE_INSENSITIVE | Pattern.DOTALL); | |
Matcher m = p.matcher(s); | |
return m.find(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment