Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
<version>2.3.2</version>
<inherited>true</inherited>
<configuration>
<source>1.6</source>
<target>1.6</target>
<source>1.7</source>
<target>1.7</target>
<showDeprecation>false</showDeprecation>
<showWarnings>true</showWarnings>
<optimize>true</optimize>
Expand Down
193 changes: 7 additions & 186 deletions src/main/java/net/gescobar/httpserver/HttpConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -20,17 +18,17 @@
*/
public class HttpConnection implements Runnable {

private Logger log = LoggerFactory.getLogger(HttpConnection.class);
private final Logger log = LoggerFactory.getLogger(HttpConnection.class);

/**
* The socket with the underlying connection.
*/
private Socket socket;
private final Socket socket;

/**
* The implementation that will handle requests.
*/
private Handler handler;
private final Handler handler;

/**
* Constructor.
Expand All @@ -48,18 +46,16 @@ public void run() {

log.trace("handling HTTP request ... ");

try {

InputStream is = socket.getInputStream();
BufferedReader reader = new BufferedReader( new InputStreamReader(is) );

try (InputStream is = socket.getInputStream();
BufferedReader reader = new BufferedReader( new InputStreamReader(is) );
OutputStream os = socket.getOutputStream();) {

// build the request and response object
RequestImpl request = new RequestImpl(reader);
ResponseImpl response = new ResponseImpl();

handler.handle(request, response);

OutputStream os = socket.getOutputStream();
os.write(response.toString().getBytes());
os.flush();
os.close();
Expand All @@ -72,179 +68,4 @@ public void run() {

}

/**
* This is an internal implementation of the {@link Request} interface.
*
* @author German Escobar
*/
private class RequestImpl implements Request {

/**
* The Host header.
*/
private String host;

/**
* The HTTP method
*/
private String method;

/**
* The request path
*/
private String path;

/**
* The request headers
*/
private Map<String,String> headers;

/**
* Constructor.
*
* @param reader from which we are reading the headers.
*
* @throws IOException if an I/O error occurs in the underlying connection.
*/
public RequestImpl(BufferedReader reader) throws IOException {

String request = reader.readLine();

// get the method and the path
method = request.split(" ")[0];
path = request.split(" ")[1];

// get the headers
headers = retrieveHeaders(reader);

}

/**
* Helper method. Retrieves the headers of the request.
*
* @param reader the reader from which we are retrieving the request information.
*
* @return a Map<String,String> object with the headers of the request.
* @throws IOException if an I/O error occurs in the underlying communication.
*/
private Map<String,String> retrieveHeaders(BufferedReader reader) throws IOException {

Map<String,String> headers = new HashMap<String,String>();

// iterate through the headers
String headerLine = reader.readLine();
while( !headerLine.equals("") ) {

// headers come in the form "name: value"
String name = headerLine.split(":")[0].trim();
String value = headerLine.split(":")[1].trim();

// add to the headers only if there is no corresponding field (e.g. "Host" header is mapped to the
// *host* field of the request)
if ( !isKnownHeader(name, value) ) {
headers.put(name, value);
}

// read next line
headerLine = reader.readLine();
}

return headers;

}

/**
* Checks if it is a known header and sets the corresponding field.
*
* @param name the name of the header to check.
* @param value the value of the header to check.
*
* @return true if it is a known header, false otherwise
*/
private boolean isKnownHeader(String name, String value) {

boolean ret = false;

if (name.equalsIgnoreCase("host")) {
host = value;
return true;
}

return ret;

}

@Override
public String getMethod() {
return method;
}

@Override
public String getPath() {
return path;
}

@Override
public String getHost() {
return host;
}

@Override
public Map<String, String> getHeaders() {
return headers;
}

@Override
public String getHeader(String name) {
return headers.get(name);
}

}

/**
* This is a private implementation of the {@link Response interface}
*
* @author German Escobar
*/
private class ResponseImpl implements Response {

private HttpStatus status = HttpStatus.OK;

private String contentType;

@Override
public Response status(HttpStatus status) {
this.status = status;

return this;
}

@Override
public Response ok() {
return status(HttpStatus.OK);
}

@Override
public Response notFound() {
return status(HttpStatus.NOT_FOUND);
}

@Override
public Response contentType(String contentType) {
this.contentType = contentType;

return this;
}

public String toString() {
String ret = "HTTP/1.1 " + status.getCode() + " " + status.getReason() + "\r\n";

if (contentType != null) {
ret += "Content-Type: " + contentType + "\r\n";
}

return ret + "\r\n";
}

}
}
4 changes: 2 additions & 2 deletions src/main/java/net/gescobar/httpserver/HttpServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
*/
public class HttpServer {

private Logger log = LoggerFactory.getLogger(HttpServer.class);
private final Logger log = LoggerFactory.getLogger(HttpServer.class);

/**
* The default port to use unless other is specified.
Expand Down Expand Up @@ -68,7 +68,7 @@ public class HttpServer {
/**
* Tells if the server is running or not.
*/
private boolean running;
private volatile boolean running;

/**
* Constructor. Initializes the server with the default port and {@link Handler} implementation.
Expand Down
136 changes: 136 additions & 0 deletions src/main/java/net/gescobar/httpserver/RequestImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package net.gescobar.httpserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


/**
* This is an internal implementation of the {@link Request} interface.
*
* @author German Escobar
*/
class RequestImpl implements Request {

/**
* The Host header.
*/
private String host;

/**
* The HTTP method
*/
private final String method;

/**
* The request path
*/
private final String path;

/**
* The request headers
*/
private final Map<String,String> headers;

/**
* Constructor.
*
* @param reader from which we are reading the headers.
*
* @throws IOException if an I/O error occurs in the underlying connection.
*/
public RequestImpl(BufferedReader reader) throws IOException {

String request = reader.readLine();

// get the method and the path
method = request.split(" ")[0];
path = request.split(" ")[1];

// get the headers
headers = retrieveHeaders(reader);

}

/**
* Helper method. Retrieves the headers of the request.
*
* @param reader the reader from which we are retrieving the request information.
*
* @return a Map<String,String> object with the headers of the request.
* @throws IOException if an I/O error occurs in the underlying communication.
*/
private Map<String,String> retrieveHeaders(BufferedReader reader) throws IOException {

Map<String,String> headers = new HashMap<String,String>();

// iterate through the headers
String headerLine = reader.readLine();
while( !headerLine.equals("") ) {

// headers come in the form "name: value"
String name = headerLine.split(":")[0].trim();
String value = headerLine.split(":")[1].trim();

// add to the headers only if there is no corresponding field (e.g. "Host" header is mapped to the
// *host* field of the request)
if ( !isKnownHeader(name, value) ) {
headers.put(name, value);
}

// read next line
headerLine = reader.readLine();
}

return headers;

}

/**
* Checks if it is a known header and sets the corresponding field.
*
* @param name the name of the header to check.
* @param value the value of the header to check.
*
* @return true if it is a known header, false otherwise
*/
private boolean isKnownHeader(String name, String value) {

boolean ret = false;

if (name.equalsIgnoreCase("host")) {
host = value;
return true;
}

return ret;

}

@Override
public String getMethod() {
return method;
}

@Override
public String getPath() {
return path;
}

@Override
public String getHost() {
return host;
}

@Override
public Map<String, String> getHeaders() {
return headers;
}

@Override
public String getHeader(String name) {
return headers.get(name);
}

}
Loading