Skip to content

Instantly share code, notes, and snippets.

@strattondev
Created January 22, 2013 03:24
Show Gist options
  • Save strattondev/4591812 to your computer and use it in GitHub Desktop.
Save strattondev/4591812 to your computer and use it in GitHub Desktop.
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