diff --git a/pom.xml b/pom.xml index 12d48c2..6394361 100644 --- a/pom.xml +++ b/pom.xml @@ -60,8 +60,8 @@ 2.3.2 true - 1.6 - 1.6 + 1.7 + 1.7 false true true diff --git a/src/main/java/net/gescobar/httpserver/HttpConnection.java b/src/main/java/net/gescobar/httpserver/HttpConnection.java index 0b2aaa5..47f1196 100644 --- a/src/main/java/net/gescobar/httpserver/HttpConnection.java +++ b/src/main/java/net/gescobar/httpserver/HttpConnection.java @@ -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; @@ -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. @@ -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(); @@ -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 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 object with the headers of the request. - * @throws IOException if an I/O error occurs in the underlying communication. - */ - private Map retrieveHeaders(BufferedReader reader) throws IOException { - - Map headers = new HashMap(); - - // 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 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"; - } - - } } diff --git a/src/main/java/net/gescobar/httpserver/HttpServer.java b/src/main/java/net/gescobar/httpserver/HttpServer.java index f353bed..60e8580 100644 --- a/src/main/java/net/gescobar/httpserver/HttpServer.java +++ b/src/main/java/net/gescobar/httpserver/HttpServer.java @@ -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. @@ -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. diff --git a/src/main/java/net/gescobar/httpserver/RequestImpl.java b/src/main/java/net/gescobar/httpserver/RequestImpl.java new file mode 100644 index 0000000..bfb9c25 --- /dev/null +++ b/src/main/java/net/gescobar/httpserver/RequestImpl.java @@ -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 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 object with the headers of the request. + * @throws IOException if an I/O error occurs in the underlying communication. + */ + private Map retrieveHeaders(BufferedReader reader) throws IOException { + + Map headers = new HashMap(); + + // 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 getHeaders() { + return headers; + } + + @Override + public String getHeader(String name) { + return headers.get(name); + } + +} \ No newline at end of file diff --git a/src/main/java/net/gescobar/httpserver/Response.java b/src/main/java/net/gescobar/httpserver/Response.java index f6a2aaf..d3b36d3 100644 --- a/src/main/java/net/gescobar/httpserver/Response.java +++ b/src/main/java/net/gescobar/httpserver/Response.java @@ -28,9 +28,9 @@ public enum HttpStatus { OVERLOADED(502, "Overloaded"), GATEWAY_TIMEOUT(503, "Gateway Timeout"); - private int code; + private final int code; - private String reason; + private final String reason; private HttpStatus(int code, String reason) { this.code = code; diff --git a/src/main/java/net/gescobar/httpserver/ResponseImpl.java b/src/main/java/net/gescobar/httpserver/ResponseImpl.java new file mode 100644 index 0000000..fffc6cd --- /dev/null +++ b/src/main/java/net/gescobar/httpserver/ResponseImpl.java @@ -0,0 +1,50 @@ + +package net.gescobar.httpserver; + +/** + * This is a private implementation of the {@link Response interface} + * + * @author German Escobar + */ +class ResponseImpl implements Response { + + private Response.HttpStatus status = Response.HttpStatus.OK; + + private String contentType; + + @Override + public Response status(Response.HttpStatus status) { + this.status = status; + + return this; + } + + @Override + public Response ok() { + return status(Response.HttpStatus.OK); + } + + @Override + public Response notFound() { + return status(Response.HttpStatus.NOT_FOUND); + } + + @Override + public Response contentType(String contentType) { + this.contentType = contentType; + + return this; + } + + @Override + 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"; + } + +} diff --git a/src/test/java/net/gescobar/httpserver/HttpServerTest.java b/src/test/java/net/gescobar/httpserver/HttpServerTest.java index 79141a6..6363450 100644 --- a/src/test/java/net/gescobar/httpserver/HttpServerTest.java +++ b/src/test/java/net/gescobar/httpserver/HttpServerTest.java @@ -123,26 +123,4 @@ public void doHandle(Request request, Response response) { } - - private class TestHandler implements Handler { - - private Request request; - - @Override - public final void handle(Request request, Response response) { - this.request = request; - - doHandle(request, response); - } - - public void doHandle(Request request, Response response) { - - } - - public Request getRequest() { - return request; - } - - } - } diff --git a/src/test/java/net/gescobar/httpserver/TestHandler.java b/src/test/java/net/gescobar/httpserver/TestHandler.java new file mode 100644 index 0000000..23f1a22 --- /dev/null +++ b/src/test/java/net/gescobar/httpserver/TestHandler.java @@ -0,0 +1,23 @@ + +package net.gescobar.httpserver; + +class TestHandler implements Handler { + + private Request request; + + @Override + public final void handle(Request request, Response response) { + this.request = request; + + doHandle(request, response); + } + + public void doHandle(Request request, Response response) { + + } + + public Request getRequest() { + return request; + } + +}