From bada3ab42026a411e3100520d2d5c950b14f3096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:13:44 +0900 Subject: [PATCH 01/81] =?UTF-8?q?feat(Http11Processor):=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=A5=BC=20HttpRequest?= =?UTF-8?q?=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EB=B3=80=EA=B2=BD=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index bb14184757..f3416865d6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,16 +1,29 @@ package org.apache.coyote.http11; -import com.techcourse.exception.UncheckedServletException; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.Socket; +import java.net.URI; +import java.net.URL; +import java.net.http.HttpClient.Version; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.nio.file.Files; +import java.nio.file.Path; + import org.apache.coyote.Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.net.Socket; +import com.techcourse.exception.UncheckedServletException; public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); + private static final String STATIC_RESOURCE_PATH = "static/"; private final Socket connection; @@ -26,12 +39,14 @@ public void run() { @Override public void process(final Socket connection) { - try (final var inputStream = connection.getInputStream(); - final var outputStream = connection.getOutputStream()) { + try (final InputStream inputStream = connection.getInputStream(); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + final OutputStream outputStream = connection.getOutputStream()) { - final var responseBody = "Hello world!"; + final HttpRequest httpRequest = readHttpRequest(bufferedReader); - final var response = String.join("\r\n", + final String responseBody = "Hello world!"; + final String response = String.join("\r\n", "HTTP/1.1 200 OK ", "Content-Type: text/html;charset=utf-8 ", "Content-Length: " + responseBody.getBytes().length + " ", @@ -44,4 +59,22 @@ public void process(final Socket connection) { log.error(e.getMessage(), e); } } + + private HttpRequest readHttpRequest(BufferedReader bufferedReader) throws IOException { + final var requestLines = bufferedReader.readLine(); + + final var requestStartLine = requestLines.split(" "); + final var requestMethod = requestStartLine[0]; + final var requestEndPoint = requestStartLine[1]; + final var requestVersion = requestStartLine[2] + .replace("/", "_") + .replace(".", "_"); + + // TODO: GET, OPTION 이 아닌 경우 BODYPUBLISH + return HttpRequest.newBuilder() + .uri(URI.create("http://localhost:8080" + requestEndPoint)) + .version(Version.valueOf(requestVersion)) + .method(requestMethod, BodyPublishers.noBody()) + .build(); + } } From c4a1553f07a3280905d4cad2a434ad6566ad83ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 18:14:15 +0900 Subject: [PATCH 02/81] =?UTF-8?q?feat(Http11Processor):=20=EC=9A=94?= =?UTF-8?q?=EC=B2=ADURL=EA=B3=BC=20=EC=9D=BC=EC=B9=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=A0=95=EC=A0=81=20=ED=8C=8C=EC=9D=BC=EC=9D=84=20=EB=B0=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/http11/Http11Processor.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index f3416865d6..faac4b8d4a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -45,7 +45,7 @@ public void process(final Socket connection) { final HttpRequest httpRequest = readHttpRequest(bufferedReader); - final String responseBody = "Hello world!"; + final String responseBody = readStaticResource(httpRequest); final String response = String.join("\r\n", "HTTP/1.1 200 OK ", "Content-Type: text/html;charset=utf-8 ", @@ -77,4 +77,11 @@ private HttpRequest readHttpRequest(BufferedReader bufferedReader) throws IOExce .method(requestMethod, BodyPublishers.noBody()) .build(); } + + private String readStaticResource(HttpRequest httpRequest) throws IOException { + final String fileName = httpRequest.uri().getPath().replace("/", STATIC_RESOURCE_PATH); + final URL resourceURL = getClass().getClassLoader().getResource(fileName); + + return Files.readString(Path.of(resourceURL.getPath())); + } } From c18f016214df5de12697276e3df32ebbfead9dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 19:33:20 +0900 Subject: [PATCH 03/81] =?UTF-8?q?feat(Http11Processor):=20root=20url?= =?UTF-8?q?=EB=A1=9C=20=EC=9A=94=EC=B2=AD=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=ED=8A=B9=EC=A0=95=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EB=B0=98?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http11/Http11Processor.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index faac4b8d4a..d859edabd9 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -23,7 +23,9 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); + private static final String STATIC_RESOURCE_PATH = "static/"; + private static final String ROOT_PATH = "/"; private final Socket connection; @@ -45,7 +47,7 @@ public void process(final Socket connection) { final HttpRequest httpRequest = readHttpRequest(bufferedReader); - final String responseBody = readStaticResource(httpRequest); + final String responseBody = findResponseBody(httpRequest); final String response = String.join("\r\n", "HTTP/1.1 200 OK ", "Content-Type: text/html;charset=utf-8 ", @@ -78,8 +80,13 @@ private HttpRequest readHttpRequest(BufferedReader bufferedReader) throws IOExce .build(); } - private String readStaticResource(HttpRequest httpRequest) throws IOException { - final String fileName = httpRequest.uri().getPath().replace("/", STATIC_RESOURCE_PATH); + private String findResponseBody(HttpRequest httpRequest) throws IOException { + String endPoint = httpRequest.uri().getPath(); + if (endPoint.equals(ROOT_PATH)) { + return "Hello world!"; + } + + final String fileName = endPoint.replace(ROOT_PATH, STATIC_RESOURCE_PATH); final URL resourceURL = getClass().getClassLoader().getResource(fileName); return Files.readString(Path.of(resourceURL.getPath())); From f1faac65866402bc1557f44a2e7a2fdf63c45cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:30:28 +0900 Subject: [PATCH 04/81] =?UTF-8?q?feat(Http11Processor):=20html=EC=9D=B4=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20=EB=8B=A4=EB=A5=B8=20=ED=98=95=EC=8B=9D?= =?UTF-8?q?=EC=9D=98=20=ED=8C=8C=EC=9D=BC=20=EC=A7=80=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 68 ++++++++++++++----- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index d859edabd9..fa11cf8b46 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -13,6 +13,7 @@ import java.net.http.HttpRequest.BodyPublishers; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Set; import org.apache.coyote.Processor; import org.slf4j.Logger; @@ -24,8 +25,9 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); - private static final String STATIC_RESOURCE_PATH = "static/"; - private static final String ROOT_PATH = "/"; + private static final Set STATIC_RESOURCE_EXTENSIONS = Set.of("css", "js", "ico"); + private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; + private static final String PATH_DELIMITER = "/"; private final Socket connection; @@ -46,14 +48,7 @@ public void process(final Socket connection) { final OutputStream outputStream = connection.getOutputStream()) { final HttpRequest httpRequest = readHttpRequest(bufferedReader); - - final String responseBody = findResponseBody(httpRequest); - final String response = String.join("\r\n", - "HTTP/1.1 200 OK ", - "Content-Type: text/html;charset=utf-8 ", - "Content-Length: " + responseBody.getBytes().length + " ", - "", - responseBody); + final String response = processResponse(httpRequest); outputStream.write(response.getBytes()); outputStream.flush(); @@ -62,7 +57,7 @@ public void process(final Socket connection) { } } - private HttpRequest readHttpRequest(BufferedReader bufferedReader) throws IOException { + private HttpRequest readHttpRequest(final BufferedReader bufferedReader) throws IOException { final var requestLines = bufferedReader.readLine(); final var requestStartLine = requestLines.split(" "); @@ -80,15 +75,52 @@ private HttpRequest readHttpRequest(BufferedReader bufferedReader) throws IOExce .build(); } - private String findResponseBody(HttpRequest httpRequest) throws IOException { - String endPoint = httpRequest.uri().getPath(); - if (endPoint.equals(ROOT_PATH)) { - return "Hello world!"; + private String processResponse(final HttpRequest httpRequest) throws IOException { + final String endPoint = httpRequest.uri().getPath(); + final String[] paths = endPoint.split(PATH_DELIMITER); + + if (paths.length == 0) { + return processRootResponse(); + } + + final String resourceName = paths[paths.length - 1]; + if (resourceName.contains(".")) { + return processStaticResponse(resourceName); } - final String fileName = endPoint.replace(ROOT_PATH, STATIC_RESOURCE_PATH); - final URL resourceURL = getClass().getClassLoader().getResource(fileName); + return processRootResponse(); + } + + private String processStaticResponse(final String resourceName) throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); + final Path resourcePath = Path.of(resourceURL.getPath()); + final String responseBody = Files.readString(resourcePath); + final String mimeType = Files.probeContentType(resourcePath); + + return getResponse(mimeType, responseBody); + } + + private String processRootResponse() { + final String responseBody = "Hello world!"; + return getResponse("text/html", responseBody); + } + + private String getResponse(String mimeType, String responseBody) { + return String.join("\r\n", + "HTTP/1.1 200 OK ", + "Content-Type: " + mimeType +";charset=utf-8 ", + "Content-Length: " + responseBody.getBytes().length + " ", + "", + responseBody); + } + + private String findResourcePath(final String resourcePath) { + final String[] fileNames = resourcePath.split("\\."); + + if (STATIC_RESOURCE_EXTENSIONS.contains(fileNames[1])) { + return STATIC_RESOURCE_ROOT_PATH.concat(fileNames[1]).concat(PATH_DELIMITER).concat(resourcePath); + } - return Files.readString(Path.of(resourceURL.getPath())); + return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); } } From 46e764765b3f2eef897e1bcc9207394747837e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:40:55 +0900 Subject: [PATCH 05/81] =?UTF-8?q?refactor(HttpRequestParser):=20HttpReques?= =?UTF-8?q?t=EB=A5=BC=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/HttpRequestParser.java | 32 +++++++++++++++++ .../apache/coyote/http11/Http11Processor.java | 34 ++++--------------- 2 files changed, 39 insertions(+), 27 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java new file mode 100644 index 0000000000..671070f991 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java @@ -0,0 +1,32 @@ +package org.apache.coyote; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.http.HttpClient.Version; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; + +public class HttpRequestParser { + public static HttpRequest parseRequest(InputStream inputStream) throws IOException { + return parseGetRequest(inputStream); + } + + public static HttpRequest parseGetRequest(InputStream inputStream) throws IOException { + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + final String request = bufferedReader.readLine(); + + final var requestStartLine = request.split(" "); + return HttpRequest.newBuilder() + .uri(URI.create("http://localhost:8080" + requestStartLine[0])) + .method(requestStartLine[1], BodyPublishers.noBody()) + .version(getHttpVersion(requestStartLine[2])) + .build(); + } + + private static Version getHttpVersion(String version) { + return Version.valueOf(version.replace("/", "_").replace(".", "_")); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index fa11cf8b46..587a49ee29 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,20 +1,18 @@ package org.apache.coyote.http11; -import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; -import java.net.URI; import java.net.URL; -import java.net.http.HttpClient.Version; import java.net.http.HttpRequest; -import java.net.http.HttpRequest.BodyPublishers; import java.nio.file.Files; import java.nio.file.Path; import java.util.Set; +import jakarta.activation.MimeTypeEntry; + +import org.apache.coyote.HttpRequestParser; import org.apache.coyote.Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,10 +42,9 @@ public void run() { @Override public void process(final Socket connection) { try (final InputStream inputStream = connection.getInputStream(); - final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); final OutputStream outputStream = connection.getOutputStream()) { - final HttpRequest httpRequest = readHttpRequest(bufferedReader); + final HttpRequest httpRequest = HttpRequestParser.parseRequest(inputStream); final String response = processResponse(httpRequest); outputStream.write(response.getBytes()); @@ -57,24 +54,6 @@ public void process(final Socket connection) { } } - private HttpRequest readHttpRequest(final BufferedReader bufferedReader) throws IOException { - final var requestLines = bufferedReader.readLine(); - - final var requestStartLine = requestLines.split(" "); - final var requestMethod = requestStartLine[0]; - final var requestEndPoint = requestStartLine[1]; - final var requestVersion = requestStartLine[2] - .replace("/", "_") - .replace(".", "_"); - - // TODO: GET, OPTION 이 아닌 경우 BODYPUBLISH - return HttpRequest.newBuilder() - .uri(URI.create("http://localhost:8080" + requestEndPoint)) - .version(Version.valueOf(requestVersion)) - .method(requestMethod, BodyPublishers.noBody()) - .build(); - } - private String processResponse(final HttpRequest httpRequest) throws IOException { final String endPoint = httpRequest.uri().getPath(); final String[] paths = endPoint.split(PATH_DELIMITER); @@ -116,9 +95,10 @@ private String getResponse(String mimeType, String responseBody) { private String findResourcePath(final String resourcePath) { final String[] fileNames = resourcePath.split("\\."); + final String extension = fileNames[1]; - if (STATIC_RESOURCE_EXTENSIONS.contains(fileNames[1])) { - return STATIC_RESOURCE_ROOT_PATH.concat(fileNames[1]).concat(PATH_DELIMITER).concat(resourcePath); + if (STATIC_RESOURCE_EXTENSIONS.contains(extension)) { + return STATIC_RESOURCE_ROOT_PATH.concat(extension).concat(PATH_DELIMITER).concat(resourcePath); } return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); From e759369a9419a8650ac4ba83fb3bb354508f4df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:48:10 +0900 Subject: [PATCH 06/81] =?UTF-8?q?feat(RequestHandler):=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=9D=84=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/RequestHandler.java | 64 +++++++++++++++++++ .../apache/coyote/http11/Http11Processor.java | 58 +---------------- 2 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/RequestHandler.java diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java new file mode 100644 index 0000000000..cad8d46fea --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -0,0 +1,64 @@ +package org.apache.coyote; + +import java.io.IOException; +import java.net.URL; +import java.net.http.HttpRequest; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; + +public class RequestHandler { + private static final Set STATIC_RESOURCE_EXTENSIONS = Set.of("css", "js", "ico"); + private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; + private static final String PATH_DELIMITER = "/"; + + public String handle(final HttpRequest httpRequest) throws IOException { + final String endPoint = httpRequest.uri().getPath(); + final String[] paths = endPoint.split(PATH_DELIMITER); + + if (paths.length == 0) { + return processRootResponse(); + } + + final String resourceName = paths[paths.length - 1]; + if (resourceName.contains(".")) { + return processStaticResponse(resourceName); + } + + return processRootResponse(); + } + + private String processStaticResponse(final String resourceName) throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); + final Path resourcePath = Path.of(resourceURL.getPath()); + final String responseBody = Files.readString(resourcePath); + final String mimeType = Files.probeContentType(resourcePath); + + return getResponse(mimeType, responseBody); + } + + private String processRootResponse() { + final String responseBody = "Hello world!"; + return getResponse("text/html", responseBody); + } + + private String getResponse(String mimeType, String responseBody) { + return String.join("\r\n", + "HTTP/1.1 200 OK ", + "Content-Type: " + mimeType +";charset=utf-8 ", + "Content-Length: " + responseBody.getBytes().length + " ", + "", + responseBody); + } + + private String findResourcePath(final String resourcePath) { + final String[] fileNames = resourcePath.split("\\."); + final String extension = fileNames[1]; + + if (STATIC_RESOURCE_EXTENSIONS.contains(extension)) { + return STATIC_RESOURCE_ROOT_PATH.concat(extension).concat(PATH_DELIMITER).concat(resourcePath); + } + + return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 587a49ee29..8c2351e7f1 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -14,6 +14,7 @@ import org.apache.coyote.HttpRequestParser; import org.apache.coyote.Processor; +import org.apache.coyote.RequestHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,10 +24,6 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); - private static final Set STATIC_RESOURCE_EXTENSIONS = Set.of("css", "js", "ico"); - private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; - private static final String PATH_DELIMITER = "/"; - private final Socket connection; public Http11Processor(final Socket connection) { @@ -45,7 +42,8 @@ public void process(final Socket connection) { final OutputStream outputStream = connection.getOutputStream()) { final HttpRequest httpRequest = HttpRequestParser.parseRequest(inputStream); - final String response = processResponse(httpRequest); + final RequestHandler requestHandler = new RequestHandler(); + final String response = requestHandler.handle(httpRequest); outputStream.write(response.getBytes()); outputStream.flush(); @@ -53,54 +51,4 @@ public void process(final Socket connection) { log.error(e.getMessage(), e); } } - - private String processResponse(final HttpRequest httpRequest) throws IOException { - final String endPoint = httpRequest.uri().getPath(); - final String[] paths = endPoint.split(PATH_DELIMITER); - - if (paths.length == 0) { - return processRootResponse(); - } - - final String resourceName = paths[paths.length - 1]; - if (resourceName.contains(".")) { - return processStaticResponse(resourceName); - } - - return processRootResponse(); - } - - private String processStaticResponse(final String resourceName) throws IOException { - final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); - final Path resourcePath = Path.of(resourceURL.getPath()); - final String responseBody = Files.readString(resourcePath); - final String mimeType = Files.probeContentType(resourcePath); - - return getResponse(mimeType, responseBody); - } - - private String processRootResponse() { - final String responseBody = "Hello world!"; - return getResponse("text/html", responseBody); - } - - private String getResponse(String mimeType, String responseBody) { - return String.join("\r\n", - "HTTP/1.1 200 OK ", - "Content-Type: " + mimeType +";charset=utf-8 ", - "Content-Length: " + responseBody.getBytes().length + " ", - "", - responseBody); - } - - private String findResourcePath(final String resourcePath) { - final String[] fileNames = resourcePath.split("\\."); - final String extension = fileNames[1]; - - if (STATIC_RESOURCE_EXTENSIONS.contains(extension)) { - return STATIC_RESOURCE_ROOT_PATH.concat(extension).concat(PATH_DELIMITER).concat(resourcePath); - } - - return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); - } } From fe4966a8c8c249e42dbdbc9764b0f5c0788b8633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 21:41:37 +0900 Subject: [PATCH 07/81] =?UTF-8?q?feat(RequestHandler):=20login=20=EC=97=94?= =?UTF-8?q?=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=A0=91=EC=86=8D=20?= =?UTF-8?q?=EC=8B=9C=20=EB=A1=9C=EC=A7=81=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/HttpRequestParser.java | 9 +-- .../org/apache/coyote/RequestHandler.java | 57 ++++++++++++++++--- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java index 671070f991..4598aa3a27 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java @@ -10,18 +10,19 @@ import java.net.http.HttpRequest.BodyPublishers; public class HttpRequestParser { - public static HttpRequest parseRequest(InputStream inputStream) throws IOException { + public static HttpRequest parseRequest(final InputStream inputStream) throws IOException { + // TODO: 다른 메서드일 때 처리 return parseGetRequest(inputStream); } - public static HttpRequest parseGetRequest(InputStream inputStream) throws IOException { + public static HttpRequest parseGetRequest(final InputStream inputStream) throws IOException { final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); final String request = bufferedReader.readLine(); final var requestStartLine = request.split(" "); return HttpRequest.newBuilder() - .uri(URI.create("http://localhost:8080" + requestStartLine[0])) - .method(requestStartLine[1], BodyPublishers.noBody()) + .method(requestStartLine[0], BodyPublishers.noBody()) + .uri(URI.create("http://localhost:8080" + requestStartLine[1])) .version(getHttpVersion(requestStartLine[2])) .build(); } diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index cad8d46fea..31d754e310 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -5,30 +5,44 @@ import java.net.http.HttpRequest; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Optional; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + public class RequestHandler { - private static final Set STATIC_RESOURCE_EXTENSIONS = Set.of("css", "js", "ico"); + private static final Set STATIC_RESOURCE_EXTENSIONS = Set.of("css", "js"); private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; private static final String PATH_DELIMITER = "/"; + private static final Logger log = LoggerFactory.getLogger(RequestHandler.class); + // mapping handler method public String handle(final HttpRequest httpRequest) throws IOException { final String endPoint = httpRequest.uri().getPath(); final String[] paths = endPoint.split(PATH_DELIMITER); if (paths.length == 0) { - return processRootResponse(); + return handleRoot(); } final String resourceName = paths[paths.length - 1]; if (resourceName.contains(".")) { - return processStaticResponse(resourceName); + return handleSimpleResource(resourceName); } - return processRootResponse(); + return handleURL(httpRequest); } - private String processStaticResponse(final String resourceName) throws IOException { + private String handleRoot() { + final String responseBody = "Hello world!"; + return getResponse("text/html", responseBody); + } + + private String handleSimpleResource(final String resourceName) throws IOException { final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); final Path resourcePath = Path.of(resourceURL.getPath()); final String responseBody = Files.readString(resourcePath); @@ -37,15 +51,40 @@ private String processStaticResponse(final String resourceName) throws IOExcepti return getResponse(mimeType, responseBody); } - private String processRootResponse() { - final String responseBody = "Hello world!"; - return getResponse("text/html", responseBody); + // TOOD: change naming + private String handleURL(final HttpRequest httpRequest) throws IOException { + String uri = httpRequest.uri().getPath(); + if (uri.contains("login")) { + return handleLogin(httpRequest); + } + + throw new IllegalCallerException("유효하지 않은 기능입니다."); + } + + private String handleLogin(final HttpRequest httpRequest) throws IOException { + String query = httpRequest.uri().getQuery(); + String[] params = query.split("&"); + + String account = params[0].split("=")[1]; + String password = params[1].split("=")[1]; + + Optional userOptional = InMemoryUserRepository.findByAccount(account); + if (userOptional.isEmpty()) { + return handleSimpleResource("login.html"); + } + + User user = userOptional.get(); + if (user.checkPassword(password)) { + log.info(user.toString()); + } + + return handleSimpleResource("401.html"); } private String getResponse(String mimeType, String responseBody) { return String.join("\r\n", "HTTP/1.1 200 OK ", - "Content-Type: " + mimeType +";charset=utf-8 ", + "Content-Type: " + mimeType + ";charset=utf-8 ", "Content-Length: " + responseBody.getBytes().length + " ", "", responseBody); From eec7b5ea8c3c9c91cb5f39d221589986e3a19b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:09:17 +0900 Subject: [PATCH 08/81] =?UTF-8?q?fix(RequestHandler):=20query=20null?= =?UTF-8?q?=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20=EC=A0=95=EC=A0=81=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=A0=8C=EB=8D=94=EB=A7=81=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/coyote/RequestHandler.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index 31d754e310..b9918994ed 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -63,8 +63,11 @@ private String handleURL(final HttpRequest httpRequest) throws IOException { private String handleLogin(final HttpRequest httpRequest) throws IOException { String query = httpRequest.uri().getQuery(); - String[] params = query.split("&"); + if (query == null) { + return handleSimpleResource("login.html"); + } + String[] params = query.split("&"); String account = params[0].split("=")[1]; String password = params[1].split("=")[1]; @@ -76,6 +79,7 @@ private String handleLogin(final HttpRequest httpRequest) throws IOException { User user = userOptional.get(); if (user.checkPassword(password)) { log.info(user.toString()); + return handleSimpleResource("login.html"); } return handleSimpleResource("401.html"); From 5585ca3e9939bc67774d363e89b75784e0b7e6f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:14:20 +0900 Subject: [PATCH 09/81] =?UTF-8?q?feat(RequestHandler):=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=84=B1=EA=B3=B5=20=EC=8B=9C=20=EB=A6=AC?= =?UTF-8?q?=EB=8B=A4=EC=9D=B4=EB=A0=89=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/HttpRequestParser.java | 1 + .../java/org/apache/coyote/RequestHandler.java | 16 +++------------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java index 4598aa3a27..521ca3b17e 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java @@ -25,6 +25,7 @@ public static HttpRequest parseGetRequest(final InputStream inputStream) throws .uri(URI.create("http://localhost:8080" + requestStartLine[1])) .version(getHttpVersion(requestStartLine[2])) .build(); + } private static Version getHttpVersion(String version) { diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index b9918994ed..811f754f99 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -39,7 +39,7 @@ public String handle(final HttpRequest httpRequest) throws IOException { private String handleRoot() { final String responseBody = "Hello world!"; - return getResponse("text/html", responseBody); + return HttpResponseGenerator.getOkResponse("text/html", responseBody); } private String handleSimpleResource(final String resourceName) throws IOException { @@ -48,7 +48,7 @@ private String handleSimpleResource(final String resourceName) throws IOExceptio final String responseBody = Files.readString(resourcePath); final String mimeType = Files.probeContentType(resourcePath); - return getResponse(mimeType, responseBody); + return HttpResponseGenerator.getOkResponse(mimeType, responseBody); } // TOOD: change naming @@ -78,22 +78,12 @@ private String handleLogin(final HttpRequest httpRequest) throws IOException { User user = userOptional.get(); if (user.checkPassword(password)) { - log.info(user.toString()); - return handleSimpleResource("login.html"); + return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } return handleSimpleResource("401.html"); } - private String getResponse(String mimeType, String responseBody) { - return String.join("\r\n", - "HTTP/1.1 200 OK ", - "Content-Type: " + mimeType + ";charset=utf-8 ", - "Content-Length: " + responseBody.getBytes().length + " ", - "", - responseBody); - } - private String findResourcePath(final String resourcePath) { final String[] fileNames = resourcePath.split("\\."); final String extension = fileNames[1]; From 7611c00621440c2f405fbfb80620bfe3d46399c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:14:51 +0900 Subject: [PATCH 10/81] =?UTF-8?q?refactor(HttpResponseGenerator):=20respon?= =?UTF-8?q?se=20=EC=83=9D=EC=84=B1=20=EA=B0=9D=EC=B2=B4=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/HttpResponseGenerator.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/HttpResponseGenerator.java diff --git a/tomcat/src/main/java/org/apache/coyote/HttpResponseGenerator.java b/tomcat/src/main/java/org/apache/coyote/HttpResponseGenerator.java new file mode 100644 index 0000000000..742241bd29 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/HttpResponseGenerator.java @@ -0,0 +1,18 @@ +package org.apache.coyote; + +public class HttpResponseGenerator { + public static String getOkResponse(String mimeType, String responseBody) { + return String.join("\r\n", + "HTTP/1.1 200 OK ", + "Content-Type: " + mimeType + ";charset=utf-8 ", + "Content-Length: " + responseBody.getBytes().length + " ", + "", + responseBody); + } + + public static String getFoundResponse(String url) { + return String.join("\r\n", + "HTTP/1.1 302 FOUND ", + "Location: " + url); + } +} From 14134453b3d8e736cb05022b4f58d6f2b7722eb1 Mon Sep 17 00:00:00 2001 From: Gyeongho Yang Date: Thu, 5 Sep 2024 11:11:09 +0900 Subject: [PATCH 11/81] fix: remove implementation logback-classic on gradle (#501) --- study/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/study/build.gradle b/study/build.gradle index 5c69542f84..87a1f0313c 100644 --- a/study/build.gradle +++ b/study/build.gradle @@ -19,7 +19,6 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-webflux' - implementation 'ch.qos.logback:logback-classic:1.5.7' implementation 'org.apache.commons:commons-lang3:3.14.0' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1' From a622aa803764aa3fbf0c55b053760e7204ea581e Mon Sep 17 00:00:00 2001 From: Gyeongho Yang Date: Thu, 5 Sep 2024 13:51:07 +0900 Subject: [PATCH 12/81] fix: add threads min-spare configuration on properties (#502) --- study/src/main/resources/application.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml index 4e8655a962..e3503a5fb9 100644 --- a/study/src/main/resources/application.yml +++ b/study/src/main/resources/application.yml @@ -6,4 +6,5 @@ server: accept-count: 1 max-connections: 1 threads: + min-spare: 2 max: 2 From 113c1f2814667c4e9a891e9d7ed3a0e5c879e973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Thu, 5 Sep 2024 21:51:29 +0900 Subject: [PATCH 13/81] =?UTF-8?q?feat(HttpHeader):=20Header=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/HttpHeader.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/HttpHeader.java diff --git a/tomcat/src/main/java/org/apache/coyote/HttpHeader.java b/tomcat/src/main/java/org/apache/coyote/HttpHeader.java new file mode 100644 index 0000000000..12d188502f --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/HttpHeader.java @@ -0,0 +1,19 @@ +package org.apache.coyote; + +public class HttpHeader { + private final String key; + private final String value; + + public HttpHeader(String key, String value) { + this.key = key; + this.value = value; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } +} From 4b09d6c2f7cbf8f011cd80e30a7220b59e17a540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Thu, 5 Sep 2024 21:51:54 +0900 Subject: [PATCH 14/81] =?UTF-8?q?feat(HttpReqeust):=20Request=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/HttpRequest.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/HttpRequest.java diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java new file mode 100644 index 0000000000..dcbb07b3ce --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java @@ -0,0 +1,72 @@ +package org.apache.coyote; + +import java.util.Arrays; + +public class HttpRequest { + private final String method; + private final String url; + private final String path; + private final String version; + private final HttpHeader[] headers; + private final String body; + + public HttpRequest(String method, String path, String version, HttpHeader[] headers, String body) { + this.method = method; + this.path = path; + this.version = version; + this.headers = headers; + this.url = parseUrl(path); + this.body = body; + } + + public HttpRequest(String method, String path, String version, HttpHeader[] headers) { + this.method = method; + this.path = path; + this.version = version; + this.headers = headers; + this.url = parseUrl(path); + this.body = null; + } + + public String getMethod() { + return method; + } + + public String getUrl() { + return url; + } + + public String getPath() { + return path; + } + + private String parseUrl(final String path) { + HttpHeader hostHeader = Arrays.stream(headers) + .filter(header -> header.getKey().equalsIgnoreCase("host")) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Host 헤더가 존재하지 않습니다.")); + + return hostHeader.getValue() + path; + } + + public String getVersion() { + return version; + } + + public HttpHeader[] getHeaders() { + return headers; + } + + public String getHeader(String key) { + for (HttpHeader header : headers) { + if (header.getKey().equals(key)) { + return header.getValue(); + } + } + throw new IllegalArgumentException("존재 하지 않는 Header " + key + "입니다."); + } + + public String getBody() { + return body; + } +} From 1cc268b2e106d90c7d7ce235ba88a7f3ed76f6bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Thu, 5 Sep 2024 21:55:09 +0900 Subject: [PATCH 15/81] =?UTF-8?q?feat(HttpRequestParser):=20Get=EC=9D=B4?= =?UTF-8?q?=20=EC=95=84=EB=8B=8C=20=EB=8B=A4=EB=A5=B8=20method=EC=97=AC?= =?UTF-8?q?=EB=8F=84=20Request=20=EA=B0=9D=EC=B2=B4=20=ED=8C=8C=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/HttpRequestParser.java | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java index 521ca3b17e..99c6127588 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java @@ -2,33 +2,56 @@ import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URI; -import java.net.http.HttpClient.Version; -import java.net.http.HttpRequest; -import java.net.http.HttpRequest.BodyPublishers; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; public class HttpRequestParser { - public static HttpRequest parseRequest(final InputStream inputStream) throws IOException { - // TODO: 다른 메서드일 때 처리 - return parseGetRequest(inputStream); + + private HttpRequestParser() { } - public static HttpRequest parseGetRequest(final InputStream inputStream) throws IOException { - final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + public static HttpRequest parseRequest(final BufferedReader bufferedReader) throws IOException { final String request = bufferedReader.readLine(); - final var requestStartLine = request.split(" "); - return HttpRequest.newBuilder() - .method(requestStartLine[0], BodyPublishers.noBody()) - .uri(URI.create("http://localhost:8080" + requestStartLine[1])) - .version(getHttpVersion(requestStartLine[2])) - .build(); + final String[] requestStartLine = request.split(" "); + final String method = requestStartLine[0]; + final String path = requestStartLine[1]; + final String version = requestStartLine[2]; + final HttpHeader[] headers = parseRequestHeaders(bufferedReader); + return new HttpRequest(method, path, version, headers, parseRequestBody(headers, bufferedReader)); } - private static Version getHttpVersion(String version) { - return Version.valueOf(version.replace("/", "_").replace(".", "_")); + private static HttpHeader[] parseRequestHeaders(final BufferedReader bufferedReader) throws IOException { + String header = bufferedReader.readLine(); + + final List headers = new ArrayList<>(); + while (header != null && !header.isEmpty()) { + String[] keyAndValue = header.split(": "); + headers.add(new HttpHeader(keyAndValue[0], keyAndValue[1])); + header = bufferedReader.readLine(); + if(header.isEmpty()) { + break; + } + } + + return headers.toArray(HttpHeader[]::new); + } + + private static String parseRequestBody(final HttpHeader[] headers, final BufferedReader bufferedReader) throws IOException { + Optional httpHeader = Arrays.stream(headers) + .filter(header -> header.getKey().equalsIgnoreCase("Content-Length")) + .findFirst(); + + if (httpHeader.isEmpty()) { + return null; + } + + int contentLength = Integer.parseInt(httpHeader.get().getValue()); + char[] buffer = new char[contentLength]; + bufferedReader.read(buffer, 0, contentLength); + return new String(buffer); } } From f03ad134f8b6c01db1f0cb6773727772f4a68ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Thu, 5 Sep 2024 21:58:34 +0900 Subject: [PATCH 16/81] =?UTF-8?q?feat(RequestHandler):=20queryString?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EB=8A=94=20path=EC=9D=BC=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EA=B2=80=EC=A6=9D=20=ED=9B=84=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/RequestHandler.java | 62 ++++++++++++------- .../apache/coyote/http11/Http11Processor.java | 13 ++-- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index 811f754f99..e486790082 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -2,28 +2,27 @@ import java.io.IOException; import java.net.URL; -import java.net.http.HttpRequest; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; +import java.util.Objects; import java.util.Optional; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; public class RequestHandler { - private static final Set STATIC_RESOURCE_EXTENSIONS = Set.of("css", "js"); + private static final Map STATIC_RESOURCE_EXTENSIONS = Map.of( + "css", "css", + "js", "assets" + ); private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; private static final String PATH_DELIMITER = "/"; - private static final Logger log = LoggerFactory.getLogger(RequestHandler.class); // mapping handler method public String handle(final HttpRequest httpRequest) throws IOException { - final String endPoint = httpRequest.uri().getPath(); - final String[] paths = endPoint.split(PATH_DELIMITER); + final String path = httpRequest.getPath(); + final String[] paths = path.split(PATH_DELIMITER); if (paths.length == 0) { return handleRoot(); @@ -53,30 +52,34 @@ private String handleSimpleResource(final String resourceName) throws IOExceptio // TOOD: change naming private String handleURL(final HttpRequest httpRequest) throws IOException { - String uri = httpRequest.uri().getPath(); + final String uri = httpRequest.getUrl(); if (uri.contains("login")) { - return handleLogin(httpRequest); + return processLoginRequest(httpRequest); + } + + if (uri.contains("register")) { + return processRegisterRequest(httpRequest); } throw new IllegalCallerException("유효하지 않은 기능입니다."); } - private String handleLogin(final HttpRequest httpRequest) throws IOException { - String query = httpRequest.uri().getQuery(); - if (query == null) { + private String processLoginRequest(final HttpRequest httpRequest) throws IOException { + final String path = httpRequest.getPath(); + if (!path.contains("?")) { return handleSimpleResource("login.html"); } - String[] params = query.split("&"); - String account = params[0].split("=")[1]; - String password = params[1].split("=")[1]; + final String[] params = path.split("\\?")[1].split("&"); + final String account = params[0].split("=")[1]; + final String password = params[1].split("=")[1]; - Optional userOptional = InMemoryUserRepository.findByAccount(account); + final Optional userOptional = InMemoryUserRepository.findByAccount(account); if (userOptional.isEmpty()) { return handleSimpleResource("login.html"); } - User user = userOptional.get(); + final User user = userOptional.get(); if (user.checkPassword(password)) { return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } @@ -84,12 +87,29 @@ private String handleLogin(final HttpRequest httpRequest) throws IOException { return handleSimpleResource("401.html"); } + private String processRegisterRequest(final HttpRequest httpRequest) throws IOException { + if (Objects.equals(httpRequest.getMethod(), "GET")) { + return handleSimpleResource("register.html"); + } + + if (Objects.equals(httpRequest.getMethod(), "POST")) { + return processRegisterPostRequest(httpRequest); + } + + return handleSimpleResource("401.html"); + } + + private String processRegisterPostRequest(final HttpRequest httpRequest) { + return "string"; + } + private String findResourcePath(final String resourcePath) { final String[] fileNames = resourcePath.split("\\."); final String extension = fileNames[1]; - if (STATIC_RESOURCE_EXTENSIONS.contains(extension)) { - return STATIC_RESOURCE_ROOT_PATH.concat(extension).concat(PATH_DELIMITER).concat(resourcePath); + if (STATIC_RESOURCE_EXTENSIONS.containsKey(extension)) { + return STATIC_RESOURCE_ROOT_PATH.concat(STATIC_RESOURCE_EXTENSIONS.get(extension)).concat(PATH_DELIMITER) + .concat(resourcePath); } return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 8c2351e7f1..b1a54dd6f2 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,17 +1,13 @@ package org.apache.coyote.http11; +import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; -import java.net.URL; -import java.net.http.HttpRequest; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Set; - -import jakarta.activation.MimeTypeEntry; +import org.apache.coyote.HttpRequest; import org.apache.coyote.HttpRequestParser; import org.apache.coyote.Processor; import org.apache.coyote.RequestHandler; @@ -39,9 +35,10 @@ public void run() { @Override public void process(final Socket connection) { try (final InputStream inputStream = connection.getInputStream(); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); final OutputStream outputStream = connection.getOutputStream()) { - final HttpRequest httpRequest = HttpRequestParser.parseRequest(inputStream); + final HttpRequest httpRequest = HttpRequestParser.parseRequest(bufferedReader); final RequestHandler requestHandler = new RequestHandler(); final String response = requestHandler.handle(httpRequest); From 25e2e2d4ccd2e37a36c0f9c43f9ef0a66286b440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:05:12 +0900 Subject: [PATCH 17/81] =?UTF-8?q?feat(RequestHandler):=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20post=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/RequestHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index e486790082..11722a357b 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -4,6 +4,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -100,7 +101,12 @@ private String processRegisterRequest(final HttpRequest httpRequest) throws IOEx } private String processRegisterPostRequest(final HttpRequest httpRequest) { - return "string"; + String[] body = httpRequest.getBody().split("&"); + String account = body[0].split("=")[1]; + String password = body[1].split("=")[1]; + String email = body[2].split("=")[1]; + InMemoryUserRepository.save(new User(account, password, email)); + return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } private String findResourcePath(final String resourcePath) { From 8dd16d845b165964e2474a76c315802d9f1a8a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:18:39 +0900 Subject: [PATCH 18/81] =?UTF-8?q?feat(HttpCookie):=20Cookie=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http11/HttpCookie.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java new file mode 100644 index 0000000000..9d5b037266 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java @@ -0,0 +1,30 @@ +package org.apache.coyote.http11; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class HttpCookie { + public final Map cookie; + + public HttpCookie(Map cookie) { + this.cookie = cookie; + } + + public HttpCookie(String cookie) { + this.cookie = parseCookie(cookie); + } + + public static Map parseCookie(String cookie) { + String[] cookiePairs = cookie.split("; "); + + Map cookies = new HashMap<>(); + Arrays.stream(cookiePairs) + .forEach(pair -> { + String[] keyAndValue = pair.split("="); + cookies.put(keyAndValue[0], keyAndValue[1]); + }); + + return cookies; + } +} From e9a913f108fb043855c391067954da036d0fd7ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:53:20 +0900 Subject: [PATCH 19/81] =?UTF-8?q?fix(RequestHandler):=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20=EC=8B=9C=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8,=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=ED=8C=8C=EC=8B=B1?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/RequestHandler.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index 11722a357b..f20aeb30b3 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -1,13 +1,14 @@ package org.apache.coyote; import java.io.IOException; +import java.net.HttpCookie; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.UUID; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; @@ -82,7 +83,9 @@ private String processLoginRequest(final HttpRequest httpRequest) throws IOExcep final User user = userOptional.get(); if (user.checkPassword(password)) { - return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); + return setCookie( + HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), + new HttpCookie("JSESSIONID", String.valueOf(UUID.randomUUID()))); } return handleSimpleResource("401.html"); @@ -103,8 +106,8 @@ private String processRegisterRequest(final HttpRequest httpRequest) throws IOEx private String processRegisterPostRequest(final HttpRequest httpRequest) { String[] body = httpRequest.getBody().split("&"); String account = body[0].split("=")[1]; - String password = body[1].split("=")[1]; - String email = body[2].split("=")[1]; + String email = body[1].split("=")[1]; + String password = body[2].split("=")[1]; InMemoryUserRepository.save(new User(account, password, email)); return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } @@ -120,4 +123,10 @@ private String findResourcePath(final String resourcePath) { return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); } + + private String setCookie(final String response, final HttpCookie cookie) { + response.concat("Set-Cookie: ").concat(cookie.toString()).concat("\r\n"); + System.out.println("response " + response); + return response; + } } From f3ae89335d087aab60e97b3b5da0880749f2be36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:03:08 +0900 Subject: [PATCH 20/81] =?UTF-8?q?feat(index.html):=20login=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=ED=9B=84=20=EC=BD=94=EB=93=9C=20=ED=99=9C=EC=84=B1?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/resources/static/index.html | 28 ++++++++------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/tomcat/src/main/resources/static/index.html b/tomcat/src/main/resources/static/index.html index 18ac924d4e..a0255a4498 100644 --- a/tomcat/src/main/resources/static/index.html +++ b/tomcat/src/main/resources/static/index.html @@ -17,24 +17,16 @@ - - - - - - - - - - - - - - - - +
From 66716c9555e282f80db5185225c54c692e3e9478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:54:34 +0900 Subject: [PATCH 21/81] =?UTF-8?q?feat(RequestHandler):=20login=20=EC=9D=84?= =?UTF-8?q?=20post=20method=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/RequestHandler.java | 25 ++++++++++++------- .../apache/coyote/http11/Http11Processor.java | 1 + tomcat/src/main/resources/static/login.html | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index f20aeb30b3..33733b1921 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -67,28 +67,35 @@ private String handleURL(final HttpRequest httpRequest) throws IOException { } private String processLoginRequest(final HttpRequest httpRequest) throws IOException { - final String path = httpRequest.getPath(); - if (!path.contains("?")) { + if (Objects.equals(httpRequest.getMethod(), "GET")) { return handleSimpleResource("login.html"); } - final String[] params = path.split("\\?")[1].split("&"); + if (Objects.equals(httpRequest.getMethod(), "POST")) { + return processLoginPostRequest(httpRequest); + } + + return handleSimpleResource("404.html"); + } + + private String processLoginPostRequest(final HttpRequest httpRequest) throws IOException { + final String[] params = httpRequest.getBody().split("&"); final String account = params[0].split("=")[1]; final String password = params[1].split("=")[1]; final Optional userOptional = InMemoryUserRepository.findByAccount(account); if (userOptional.isEmpty()) { - return handleSimpleResource("login.html"); + return handleSimpleResource("401.html"); } final User user = userOptional.get(); if (user.checkPassword(password)) { - return setCookie( + return addCookie( HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), new HttpCookie("JSESSIONID", String.valueOf(UUID.randomUUID()))); } - return handleSimpleResource("401.html"); + return handleSimpleResource("404.html"); } private String processRegisterRequest(final HttpRequest httpRequest) throws IOException { @@ -124,9 +131,9 @@ private String findResourcePath(final String resourcePath) { return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); } - private String setCookie(final String response, final HttpCookie cookie) { - response.concat("Set-Cookie: ").concat(cookie.toString()).concat("\r\n"); - System.out.println("response " + response); + private String addCookie(final String response, final HttpCookie cookie) { + response.concat("Set-Cookie: ").concat(cookie.toString()); + System.out.println("response!!!!!!!!!! " + response); return response; } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index b1a54dd6f2..235ea89bd5 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -42,6 +42,7 @@ public void process(final Socket connection) { final RequestHandler requestHandler = new RequestHandler(); final String response = requestHandler.handle(httpRequest); + System.out.println(response); outputStream.write(response.getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { diff --git a/tomcat/src/main/resources/static/login.html b/tomcat/src/main/resources/static/login.html index f4ed9de875..bc933357f2 100644 --- a/tomcat/src/main/resources/static/login.html +++ b/tomcat/src/main/resources/static/login.html @@ -20,7 +20,7 @@

로그인

-
+
From df2f62f86e13792b8952cf4382f2efad7f5cd855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 01:12:37 +0900 Subject: [PATCH 22/81] =?UTF-8?q?fix(RequestHandler):=20Set-Cookie=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=EC=97=90=20=EC=B6=94=EA=B0=80=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/RequestHandler.java | 9 ++++----- .../main/java/org/apache/coyote/http11/HttpCookie.java | 9 +++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index 33733b1921..b0d50adb98 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -1,7 +1,6 @@ package org.apache.coyote; import java.io.IOException; -import java.net.HttpCookie; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; @@ -10,6 +9,8 @@ import java.util.Optional; import java.util.UUID; +import org.apache.coyote.http11.HttpCookie; + import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; @@ -92,7 +93,7 @@ private String processLoginPostRequest(final HttpRequest httpRequest) throws IOE if (user.checkPassword(password)) { return addCookie( HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), - new HttpCookie("JSESSIONID", String.valueOf(UUID.randomUUID()))); + new HttpCookie("JSESSIONID=" + UUID.randomUUID())); } return handleSimpleResource("404.html"); @@ -132,8 +133,6 @@ private String findResourcePath(final String resourcePath) { } private String addCookie(final String response, final HttpCookie cookie) { - response.concat("Set-Cookie: ").concat(cookie.toString()); - System.out.println("response!!!!!!!!!! " + response); - return response; + return response.concat("\n").concat("Set-Cookie: " + cookie.toString()); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java index 9d5b037266..0339f15a82 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; public class HttpCookie { public final Map cookie; @@ -27,4 +28,12 @@ public static Map parseCookie(String cookie) { return cookies; } + + @Override + public String toString() { + return cookie.entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining("; ")); + } } From ebfb27e136258c24d86b643b09fb017fddc12b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:06:58 +0900 Subject: [PATCH 23/81] =?UTF-8?q?feat(Session):=20Session,=20Manger=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/catalina/Manager.java | 10 +++--- .../org/apache/catalina/SessionManager.java | 28 +++++++++++++++ .../main/java/org/apache/coyote/Session.java | 35 +++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/catalina/SessionManager.java create mode 100644 tomcat/src/main/java/org/apache/coyote/Session.java diff --git a/tomcat/src/main/java/org/apache/catalina/Manager.java b/tomcat/src/main/java/org/apache/catalina/Manager.java index e69410f6a9..7a3b32d401 100644 --- a/tomcat/src/main/java/org/apache/catalina/Manager.java +++ b/tomcat/src/main/java/org/apache/catalina/Manager.java @@ -1,9 +1,9 @@ package org.apache.catalina; -import jakarta.servlet.http.HttpSession; - import java.io.IOException; +import org.apache.coyote.Session; + /** * A Manager manages the pool of Sessions that are associated with a * particular Container. Different Manager implementations may support @@ -29,7 +29,7 @@ public interface Manager { * * @param session Session to be added */ - void add(HttpSession session); + void add(Session session); /** * Return the active Session, associated with this Manager, with the @@ -45,12 +45,12 @@ public interface Manager { * @return the request session or {@code null} if a session with the * requested ID could not be found */ - HttpSession findSession(String id) throws IOException; + Session findSession(String id) throws IOException; /** * Remove this Session from the active Sessions for this Manager. * * @param session Session to be removed */ - void remove(HttpSession session); + void remove(Session session); } diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/SessionManager.java new file mode 100644 index 0000000000..46339272f9 --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/SessionManager.java @@ -0,0 +1,28 @@ +package org.apache.catalina; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.coyote.Session; + +public class SessionManager implements Manager { + private static final Map SESSIONS = new HashMap<>(); + + private SessionManager() {} + + @Override + public void add(Session session) { + SESSIONS.put(session.getId(), session); + } + + @Override + public Session findSession(final String id) { + return SESSIONS.get(id); + } + + @Override + public void remove(Session session) { + SESSIONS.remove(session.getId()); + } +} + diff --git a/tomcat/src/main/java/org/apache/coyote/Session.java b/tomcat/src/main/java/org/apache/coyote/Session.java new file mode 100644 index 0000000000..eb57a32f49 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/Session.java @@ -0,0 +1,35 @@ +package org.apache.coyote; + +import java.util.HashMap; +import java.util.Map; + +public class Session { + + private final String id; + private final Map values = new HashMap<>(); + + public Session(final String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public Object getAttribute(final String name) { + return values.entrySet() + .stream() + .filter(entry -> entry.getKey().equals(name)) + .map(Map.Entry::getValue) + .findFirst() + .orElse(null); + } + + public Map getValues() { + return values; + } + + public void setAttribute(String sessionId, Object value) { + values.put(sessionId, value); + } +} From 72a7a76e812a9877e3ff5837591e9ef4aa5f47c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:29:58 +0900 Subject: [PATCH 24/81] =?UTF-8?q?feat(SessionManager):=20=EC=8B=B1?= =?UTF-8?q?=EA=B8=80=ED=86=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/catalina/SessionManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/SessionManager.java index 46339272f9..8667dd30b6 100644 --- a/tomcat/src/main/java/org/apache/catalina/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/SessionManager.java @@ -7,9 +7,14 @@ public class SessionManager implements Manager { private static final Map SESSIONS = new HashMap<>(); + private static final SessionManager INSTANCE = new SessionManager(); private SessionManager() {} + public static SessionManager getInstance() { + return INSTANCE; + } + @Override public void add(Session session) { SESSIONS.put(session.getId(), session); From dfef52cc136d451ffb31153cd9a2380d94ce2d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:30:34 +0900 Subject: [PATCH 25/81] =?UTF-8?q?feat(RequestHandler):=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=90=98=EC=96=B4?= =?UTF-8?q?=EC=9E=88=EB=8A=94=EC=A7=80=20=EC=84=B8=EC=85=98=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B2=80=EC=A6=9D=20=EB=B0=8F=20=EB=A6=AC=EB=8B=A4?= =?UTF-8?q?=EC=9D=B4=EB=A0=89=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/HttpRequest.java | 4 ++++ .../java/org/apache/coyote/RequestHandler.java | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java index dcbb07b3ce..93fa55f83b 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java @@ -69,4 +69,8 @@ public String getHeader(String key) { public String getBody() { return body; } + + public Session getSession() { + return new Session("session-id"); + } } diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index b0d50adb98..fdcae8ff2f 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -9,6 +9,7 @@ import java.util.Optional; import java.util.UUID; +import org.apache.catalina.SessionManager; import org.apache.coyote.http11.HttpCookie; import com.techcourse.db.InMemoryUserRepository; @@ -21,8 +22,9 @@ public class RequestHandler { ); private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; private static final String PATH_DELIMITER = "/"; + private final SessionManager sessionManager = SessionManager.getInstance(); - // mapping handler method + // TODO: mapping handler method public String handle(final HttpRequest httpRequest) throws IOException { final String path = httpRequest.getPath(); final String[] paths = path.split(PATH_DELIMITER); @@ -69,7 +71,7 @@ private String handleURL(final HttpRequest httpRequest) throws IOException { private String processLoginRequest(final HttpRequest httpRequest) throws IOException { if (Objects.equals(httpRequest.getMethod(), "GET")) { - return handleSimpleResource("login.html"); + return processLoginGetRequest(httpRequest); } if (Objects.equals(httpRequest.getMethod(), "POST")) { @@ -79,6 +81,14 @@ private String processLoginRequest(final HttpRequest httpRequest) throws IOExcep return handleSimpleResource("404.html"); } + private String processLoginGetRequest(final HttpRequest httpRequest) throws IOException { + Session session = httpRequest.getSession(); + if (sessionManager.findSession(session.getId()) == null) { + return handleSimpleResource("login.html"); + } + return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); + } + private String processLoginPostRequest(final HttpRequest httpRequest) throws IOException { final String[] params = httpRequest.getBody().split("&"); final String account = params[0].split("=")[1]; @@ -91,6 +101,9 @@ private String processLoginPostRequest(final HttpRequest httpRequest) throws IOE final User user = userOptional.get(); if (user.checkPassword(password)) { + final Session session = httpRequest.getSession(); + session.setAttribute("user", user); + sessionManager.add(session); return addCookie( HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), new HttpCookie("JSESSIONID=" + UUID.randomUUID())); From e36802ddbe238635e1e680a326f7b6bda87c1e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:47:27 +0900 Subject: [PATCH 26/81] =?UTF-8?q?chore:=20=ED=83=80=EC=9E=84=EB=A6=AC?= =?UTF-8?q?=ED=94=84=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/study/build.gradle b/study/build.gradle index 87a1f0313c..bb8b420ca5 100644 --- a/study/build.gradle +++ b/study/build.gradle @@ -22,6 +22,7 @@ dependencies { implementation 'org.apache.commons:commons-lang3:3.14.0' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.assertj:assertj-core:3.26.0' From 76ab97bb3387a13b6018f1679b35eb1cec9f2efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:56:06 +0900 Subject: [PATCH 27/81] =?UTF-8?q?feat(CacheWebConfig):=20=ED=9C=B4?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8B=B1=20=EC=BA=90=EC=8B=B1=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache/com/example/cachecontrol/CacheWebConfig.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java index 305b1f1e1e..b29cdb1aec 100644 --- a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java +++ b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java @@ -1,13 +1,21 @@ package cache.com.example.cachecontrol; import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.mvc.WebContentInterceptor; @Configuration public class CacheWebConfig implements WebMvcConfigurer { @Override public void addInterceptors(final InterceptorRegistry registry) { + CacheControl cacheControl = CacheControl.noCache().cachePrivate(); + + WebContentInterceptor webContentInterceptor = new WebContentInterceptor(); + webContentInterceptor.addCacheMapping(cacheControl, "/**"); + + registry.addInterceptor(webContentInterceptor); } } From 2567872146ecd853d9d34229917c497c556f2295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:56:37 +0900 Subject: [PATCH 28/81] =?UTF-8?q?feat(CacheWebConfig):=20HTTP=20Compressio?= =?UTF-8?q?n=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/main/resources/application.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml index e3503a5fb9..4c735aea11 100644 --- a/study/src/main/resources/application.yml +++ b/study/src/main/resources/application.yml @@ -2,6 +2,9 @@ handlebars: suffix: .html server: + compression: + enabled: true + min-response-size: 10 tomcat: accept-count: 1 max-connections: 1 From 1ca0846e9336b26ba30b956977f5277bcaa8a694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:59:02 +0900 Subject: [PATCH 29/81] =?UTF-8?q?feat(EtagFilterConfiguration):=20ETag/If-?= =?UTF-8?q?None-Match=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/etag/EtagFilterConfiguration.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java index 41ef7a3d9a..04d792a493 100644 --- a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java +++ b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java @@ -1,12 +1,17 @@ package cache.com.example.etag; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.ShallowEtagHeaderFilter; @Configuration public class EtagFilterConfiguration { -// @Bean -// public FilterRegistrationBean shallowEtagHeaderFilter() { -// return null; -// } + @Bean + public FilterRegistrationBean shallowEtagHeaderFilter() { + FilterRegistrationBean filter = new FilterRegistrationBean<>(); + filter.setFilter(new ShallowEtagHeaderFilter()); + return filter; + } } From 8a983caa5e7c83b434523c7ed6fcaa2f53a89dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:12:24 +0900 Subject: [PATCH 30/81] =?UTF-8?q?feat(HttpRequest):=20Cookie=20=ED=8C=8C?= =?UTF-8?q?=EC=8B=B1=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD,=20Session?= =?UTF-8?q?=20=ED=8C=8C=EC=8B=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/HttpRequest.java | 25 +++++++++++-------- .../org/apache/coyote/RequestHandler.java | 13 +++++++--- .../org/apache/coyote/RequestMapping.java | 4 +++ .../org/apache/coyote/http11/HttpCookie.java | 4 +++ 4 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/RequestMapping.java diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java index 93fa55f83b..65da4331cc 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java @@ -1,6 +1,9 @@ package org.apache.coyote; import java.util.Arrays; +import java.util.Optional; + +import org.apache.coyote.http11.HttpCookie; public class HttpRequest { private final String method; @@ -9,6 +12,7 @@ public class HttpRequest { private final String version; private final HttpHeader[] headers; private final String body; + private final HttpCookie httpCookie; public HttpRequest(String method, String path, String version, HttpHeader[] headers, String body) { this.method = method; @@ -17,15 +21,7 @@ public HttpRequest(String method, String path, String version, HttpHeader[] head this.headers = headers; this.url = parseUrl(path); this.body = body; - } - - public HttpRequest(String method, String path, String version, HttpHeader[] headers) { - this.method = method; - this.path = path; - this.version = version; - this.headers = headers; - this.url = parseUrl(path); - this.body = null; + this.httpCookie = parseCookie(headers); } public String getMethod() { @@ -49,6 +45,13 @@ private String parseUrl(final String path) { return hostHeader.getValue() + path; } + private HttpCookie parseCookie(HttpHeader[] headers) { + return Arrays.stream(headers) + .filter(header -> header.getKey().equalsIgnoreCase("Cookie")) + .findFirst() + .map(header -> new HttpCookie(header.getValue())).orElse(null); + } + public String getVersion() { return version; } @@ -70,7 +73,7 @@ public String getBody() { return body; } - public Session getSession() { - return new Session("session-id"); + public HttpCookie getHttpCookie() { + return httpCookie; } } diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index fdcae8ff2f..a3af1e0e6f 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -82,8 +82,13 @@ private String processLoginRequest(final HttpRequest httpRequest) throws IOExcep } private String processLoginGetRequest(final HttpRequest httpRequest) throws IOException { - Session session = httpRequest.getSession(); - if (sessionManager.findSession(session.getId()) == null) { + HttpCookie httpCookie = httpRequest.getHttpCookie(); + if (httpCookie == null) { + return handleSimpleResource("login.html"); + } + + String sessionId = httpCookie.getValue("JSESSIONID="); + if (sessionManager.findSession(sessionId) == null) { return handleSimpleResource("login.html"); } return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); @@ -101,12 +106,12 @@ private String processLoginPostRequest(final HttpRequest httpRequest) throws IOE final User user = userOptional.get(); if (user.checkPassword(password)) { - final Session session = httpRequest.getSession(); + final Session session = new Session(UUID.randomUUID().toString()); session.setAttribute("user", user); sessionManager.add(session); return addCookie( HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), - new HttpCookie("JSESSIONID=" + UUID.randomUUID())); + new HttpCookie("JSESSIONID=" + session.getId())); } return handleSimpleResource("404.html"); diff --git a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java new file mode 100644 index 0000000000..f732165db3 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java @@ -0,0 +1,4 @@ +package org.apache.coyote; + +public class RequestMapping { +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java index 0339f15a82..f8db11be45 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java @@ -16,6 +16,10 @@ public HttpCookie(String cookie) { this.cookie = parseCookie(cookie); } + public String getValue(String key) { + return cookie.get(key); + } + public static Map parseCookie(String cookie) { String[] cookiePairs = cookie.split("; "); From 42efdd6ae101e972c91801b6e0ec34ea9b2d57b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:13:08 +0900 Subject: [PATCH 31/81] =?UTF-8?q?refactor(HttpCookie):=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/{http11 => }/HttpCookie.java | 2 +- tomcat/src/main/java/org/apache/coyote/HttpRequest.java | 3 --- tomcat/src/main/java/org/apache/coyote/RequestHandler.java | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) rename tomcat/src/main/java/org/apache/coyote/{http11 => }/HttpCookie.java (96%) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/HttpCookie.java similarity index 96% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java rename to tomcat/src/main/java/org/apache/coyote/HttpCookie.java index f8db11be45..d788cbc162 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpCookie.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11; +package org.apache.coyote; import java.util.Arrays; import java.util.HashMap; diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java index 65da4331cc..793f5f4c4b 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java @@ -1,9 +1,6 @@ package org.apache.coyote; import java.util.Arrays; -import java.util.Optional; - -import org.apache.coyote.http11.HttpCookie; public class HttpRequest { private final String method; diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index a3af1e0e6f..c2da7877ae 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -10,7 +10,6 @@ import java.util.UUID; import org.apache.catalina.SessionManager; -import org.apache.coyote.http11.HttpCookie; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; From 0268d0747c05954a3b37b84d644703b8e04026c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:24:40 +0900 Subject: [PATCH 32/81] =?UTF-8?q?refactor(/request):=20request=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20=EC=9C=84=EC=B9=98=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/HttpRequest.java | 76 ------------------- .../org/apache/coyote/HttpRequestParser.java | 57 -------------- .../org/apache/coyote/RequestHandler.java | 2 + .../org/apache/coyote/RequestMapping.java | 4 - .../apache/coyote/http11/Http11Processor.java | 4 +- 5 files changed, 4 insertions(+), 139 deletions(-) delete mode 100644 tomcat/src/main/java/org/apache/coyote/HttpRequest.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/RequestMapping.java diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/HttpRequest.java deleted file mode 100644 index 793f5f4c4b..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequest.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.apache.coyote; - -import java.util.Arrays; - -public class HttpRequest { - private final String method; - private final String url; - private final String path; - private final String version; - private final HttpHeader[] headers; - private final String body; - private final HttpCookie httpCookie; - - public HttpRequest(String method, String path, String version, HttpHeader[] headers, String body) { - this.method = method; - this.path = path; - this.version = version; - this.headers = headers; - this.url = parseUrl(path); - this.body = body; - this.httpCookie = parseCookie(headers); - } - - public String getMethod() { - return method; - } - - public String getUrl() { - return url; - } - - public String getPath() { - return path; - } - - private String parseUrl(final String path) { - HttpHeader hostHeader = Arrays.stream(headers) - .filter(header -> header.getKey().equalsIgnoreCase("host")) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Host 헤더가 존재하지 않습니다.")); - - return hostHeader.getValue() + path; - } - - private HttpCookie parseCookie(HttpHeader[] headers) { - return Arrays.stream(headers) - .filter(header -> header.getKey().equalsIgnoreCase("Cookie")) - .findFirst() - .map(header -> new HttpCookie(header.getValue())).orElse(null); - } - - public String getVersion() { - return version; - } - - public HttpHeader[] getHeaders() { - return headers; - } - - public String getHeader(String key) { - for (HttpHeader header : headers) { - if (header.getKey().equals(key)) { - return header.getValue(); - } - } - throw new IllegalArgumentException("존재 하지 않는 Header " + key + "입니다."); - } - - public String getBody() { - return body; - } - - public HttpCookie getHttpCookie() { - return httpCookie; - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java deleted file mode 100644 index 99c6127588..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/HttpRequestParser.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.apache.coyote; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -public class HttpRequestParser { - - private HttpRequestParser() { - } - - public static HttpRequest parseRequest(final BufferedReader bufferedReader) throws IOException { - final String request = bufferedReader.readLine(); - - final String[] requestStartLine = request.split(" "); - final String method = requestStartLine[0]; - final String path = requestStartLine[1]; - final String version = requestStartLine[2]; - - final HttpHeader[] headers = parseRequestHeaders(bufferedReader); - return new HttpRequest(method, path, version, headers, parseRequestBody(headers, bufferedReader)); - } - - private static HttpHeader[] parseRequestHeaders(final BufferedReader bufferedReader) throws IOException { - String header = bufferedReader.readLine(); - - final List headers = new ArrayList<>(); - while (header != null && !header.isEmpty()) { - String[] keyAndValue = header.split(": "); - headers.add(new HttpHeader(keyAndValue[0], keyAndValue[1])); - header = bufferedReader.readLine(); - if(header.isEmpty()) { - break; - } - } - - return headers.toArray(HttpHeader[]::new); - } - - private static String parseRequestBody(final HttpHeader[] headers, final BufferedReader bufferedReader) throws IOException { - Optional httpHeader = Arrays.stream(headers) - .filter(header -> header.getKey().equalsIgnoreCase("Content-Length")) - .findFirst(); - - if (httpHeader.isEmpty()) { - return null; - } - - int contentLength = Integer.parseInt(httpHeader.get().getValue()); - char[] buffer = new char[contentLength]; - bufferedReader.read(buffer, 0, contentLength); - return new String(buffer); - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index c2da7877ae..6efedb9385 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -10,6 +10,8 @@ import java.util.UUID; import org.apache.catalina.SessionManager; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponseGenerator; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; diff --git a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java deleted file mode 100644 index f732165db3..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.apache.coyote; - -public class RequestMapping { -} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 235ea89bd5..e482918e42 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -7,8 +7,8 @@ import java.io.OutputStream; import java.net.Socket; -import org.apache.coyote.HttpRequest; -import org.apache.coyote.HttpRequestParser; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.request.HttpRequestParser; import org.apache.coyote.Processor; import org.apache.coyote.RequestHandler; import org.slf4j.Logger; From a2dfeddf271c9a44b912f9e82f4b0c439d0f8c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:33:24 +0900 Subject: [PATCH 33/81] =?UTF-8?q?refactor(/response):=20response=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/request/HttpRequest.java | 80 +++++++++++++++++++ .../coyote/request/HttpRequestParser.java | 59 ++++++++++++++ .../{ => response}/HttpResponseGenerator.java | 2 +- 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java create mode 100644 tomcat/src/main/java/org/apache/coyote/request/HttpRequestParser.java rename tomcat/src/main/java/org/apache/coyote/{ => response}/HttpResponseGenerator.java (93%) diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java new file mode 100644 index 0000000000..5bc0d7fcff --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -0,0 +1,80 @@ +package org.apache.coyote.request; + +import java.util.Arrays; + +import org.apache.coyote.HttpCookie; +import org.apache.coyote.HttpHeader; + +public class HttpRequest { + private final String method; + private final String url; + private final String path; + private final String version; + private final HttpHeader[] headers; + private final String body; + private final HttpCookie httpCookie; + + public HttpRequest(String method, String path, String version, HttpHeader[] headers, String body) { + this.method = method; + this.path = path; + this.version = version; + this.headers = headers; + this.url = parseUrl(path); + this.body = body; + this.httpCookie = parseCookie(headers); + } + + private String parseUrl(final String path) { + HttpHeader hostHeader = Arrays.stream(headers) + .filter(header -> header.getKey().equalsIgnoreCase("host")) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Host 헤더가 존재하지 않습니다.")); + + return hostHeader.getValue() + path; + } + + private HttpCookie parseCookie(HttpHeader[] headers) { + return Arrays.stream(headers) + .filter(header -> header.getKey().equalsIgnoreCase("Cookie")) + .findFirst() + .map(header -> new HttpCookie(header.getValue())) + .orElse(null); + } + + public String getMethod() { + return method; + } + + public String getUrl() { + return url; + } + + public String getPath() { + return path; + } + + public String getVersion() { + return version; + } + + public HttpHeader[] getHeaders() { + return headers; + } + + public String getHeader(String key) { + for (HttpHeader header : headers) { + if (header.getKey().equals(key)) { + return header.getValue(); + } + } + throw new IllegalArgumentException("존재 하지 않는 Header " + key + "입니다."); + } + + public String getBody() { + return body; + } + + public HttpCookie getHttpCookie() { + return httpCookie; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequestParser.java new file mode 100644 index 0000000000..c09bc9060c --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequestParser.java @@ -0,0 +1,59 @@ +package org.apache.coyote.request; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import org.apache.coyote.HttpHeader; + +public class HttpRequestParser { + + private HttpRequestParser() { + } + + public static HttpRequest parseRequest(final BufferedReader bufferedReader) throws IOException { + final String request = bufferedReader.readLine(); + + final String[] requestStartLine = request.split(" "); + final String method = requestStartLine[0]; + final String path = requestStartLine[1]; + final String version = requestStartLine[2]; + + final HttpHeader[] headers = parseRequestHeaders(bufferedReader); + return new HttpRequest(method, path, version, headers, parseRequestBody(headers, bufferedReader)); + } + + private static HttpHeader[] parseRequestHeaders(final BufferedReader bufferedReader) throws IOException { + String header = bufferedReader.readLine(); + + final List headers = new ArrayList<>(); + while (header != null && !header.isEmpty()) { + String[] keyAndValue = header.split(": "); + headers.add(new HttpHeader(keyAndValue[0], keyAndValue[1])); + header = bufferedReader.readLine(); + if(header.isEmpty()) { + break; + } + } + + return headers.toArray(HttpHeader[]::new); + } + + private static String parseRequestBody(final HttpHeader[] headers, final BufferedReader bufferedReader) throws IOException { + Optional httpHeader = Arrays.stream(headers) + .filter(header -> header.getKey().equalsIgnoreCase("Content-Length")) + .findFirst(); + + if (httpHeader.isEmpty()) { + return null; + } + + int contentLength = Integer.parseInt(httpHeader.get().getValue()); + char[] buffer = new char[contentLength]; + bufferedReader.read(buffer, 0, contentLength); + return new String(buffer); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/HttpResponseGenerator.java b/tomcat/src/main/java/org/apache/coyote/response/HttpResponseGenerator.java similarity index 93% rename from tomcat/src/main/java/org/apache/coyote/HttpResponseGenerator.java rename to tomcat/src/main/java/org/apache/coyote/response/HttpResponseGenerator.java index 742241bd29..c571030c1c 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpResponseGenerator.java +++ b/tomcat/src/main/java/org/apache/coyote/response/HttpResponseGenerator.java @@ -1,4 +1,4 @@ -package org.apache.coyote; +package org.apache.coyote.response; public class HttpResponseGenerator { public static String getOkResponse(String mimeType, String responseBody) { From 6a23a53ba612aa55c3d47aaacf2d185b4ba733d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:40:43 +0900 Subject: [PATCH 34/81] =?UTF-8?q?refactor(HttpMethod):=20http=20method=20?= =?UTF-8?q?=EC=83=81=EC=88=98=EB=A1=9C=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/HttpMethod.java | 14 ++++++++++++++ .../java/org/apache/coyote/RequestHandler.java | 9 ++++----- .../org/apache/coyote/request/HttpRequest.java | 11 ++++++++--- 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/HttpMethod.java diff --git a/tomcat/src/main/java/org/apache/coyote/HttpMethod.java b/tomcat/src/main/java/org/apache/coyote/HttpMethod.java new file mode 100644 index 0000000000..c0388ae944 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/HttpMethod.java @@ -0,0 +1,14 @@ +package org.apache.coyote; + +public enum HttpMethod { + GET, + POST, + PUT, + DELETE, + HEAD, + OPTIONS, + TRACE, + CONNECT, + PATCH, + ; +} diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index 6efedb9385..f449f5946f 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -5,7 +5,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -71,11 +70,11 @@ private String handleURL(final HttpRequest httpRequest) throws IOException { } private String processLoginRequest(final HttpRequest httpRequest) throws IOException { - if (Objects.equals(httpRequest.getMethod(), "GET")) { + if (httpRequest.isSameMethod(HttpMethod.GET)) { return processLoginGetRequest(httpRequest); } - if (Objects.equals(httpRequest.getMethod(), "POST")) { + if (httpRequest.isSameMethod(HttpMethod.POST)) { return processLoginPostRequest(httpRequest); } @@ -119,11 +118,11 @@ private String processLoginPostRequest(final HttpRequest httpRequest) throws IOE } private String processRegisterRequest(final HttpRequest httpRequest) throws IOException { - if (Objects.equals(httpRequest.getMethod(), "GET")) { + if (httpRequest.isSameMethod(HttpMethod.GET)) { return handleSimpleResource("register.html"); } - if (Objects.equals(httpRequest.getMethod(), "POST")) { + if (httpRequest.isSameMethod(HttpMethod.POST)) { return processRegisterPostRequest(httpRequest); } diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java index 5bc0d7fcff..009cd45d3d 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -4,9 +4,10 @@ import org.apache.coyote.HttpCookie; import org.apache.coyote.HttpHeader; +import org.apache.coyote.HttpMethod; public class HttpRequest { - private final String method; + private final HttpMethod method; private final String url; private final String path; private final String version; @@ -15,7 +16,7 @@ public class HttpRequest { private final HttpCookie httpCookie; public HttpRequest(String method, String path, String version, HttpHeader[] headers, String body) { - this.method = method; + this.method = HttpMethod.valueOf(method); this.path = path; this.version = version; this.headers = headers; @@ -41,7 +42,11 @@ private HttpCookie parseCookie(HttpHeader[] headers) { .orElse(null); } - public String getMethod() { + public boolean isSameMethod(HttpMethod httpMethod) { + return this.method == httpMethod; + } + + public HttpMethod getMethod() { return method; } From 0e7ed00ae04f03c90c5dfd505549f65c54dd1de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:51:16 +0900 Subject: [PATCH 35/81] =?UTF-8?q?refactor(handler):=20handler=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/RequestHandler.java | 119 +----------------- .../apache/coyote/handler/LoginHandler.java | 80 ++++++++++++ .../coyote/handler/RegisterHandler.java | 44 +++++++ .../coyote/handler/ResourceHandler.java | 49 ++++++++ 4 files changed, 179 insertions(+), 113 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index f449f5946f..4475ea979f 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -1,28 +1,15 @@ package org.apache.coyote; import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import org.apache.catalina.SessionManager; +import org.apache.coyote.handler.LoginHandler; +import org.apache.coyote.handler.RegisterHandler; +import org.apache.coyote.handler.ResourceHandler; import org.apache.coyote.request.HttpRequest; import org.apache.coyote.response.HttpResponseGenerator; -import com.techcourse.db.InMemoryUserRepository; -import com.techcourse.model.User; - public class RequestHandler { - private static final Map STATIC_RESOURCE_EXTENSIONS = Map.of( - "css", "css", - "js", "assets" - ); - private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; private static final String PATH_DELIMITER = "/"; - private final SessionManager sessionManager = SessionManager.getInstance(); // TODO: mapping handler method public String handle(final HttpRequest httpRequest) throws IOException { @@ -35,7 +22,7 @@ public String handle(final HttpRequest httpRequest) throws IOException { final String resourceName = paths[paths.length - 1]; if (resourceName.contains(".")) { - return handleSimpleResource(resourceName); + return ResourceHandler.getInstance().handleSimpleResource(resourceName); } return handleURL(httpRequest); @@ -46,111 +33,17 @@ private String handleRoot() { return HttpResponseGenerator.getOkResponse("text/html", responseBody); } - private String handleSimpleResource(final String resourceName) throws IOException { - final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); - final Path resourcePath = Path.of(resourceURL.getPath()); - final String responseBody = Files.readString(resourcePath); - final String mimeType = Files.probeContentType(resourcePath); - - return HttpResponseGenerator.getOkResponse(mimeType, responseBody); - } - // TOOD: change naming private String handleURL(final HttpRequest httpRequest) throws IOException { final String uri = httpRequest.getUrl(); if (uri.contains("login")) { - return processLoginRequest(httpRequest); + return LoginHandler.getInstance().processLoginRequest(httpRequest); } if (uri.contains("register")) { - return processRegisterRequest(httpRequest); + return RegisterHandler.getInstance().processRegisterRequest(httpRequest); } throw new IllegalCallerException("유효하지 않은 기능입니다."); } - - private String processLoginRequest(final HttpRequest httpRequest) throws IOException { - if (httpRequest.isSameMethod(HttpMethod.GET)) { - return processLoginGetRequest(httpRequest); - } - - if (httpRequest.isSameMethod(HttpMethod.POST)) { - return processLoginPostRequest(httpRequest); - } - - return handleSimpleResource("404.html"); - } - - private String processLoginGetRequest(final HttpRequest httpRequest) throws IOException { - HttpCookie httpCookie = httpRequest.getHttpCookie(); - if (httpCookie == null) { - return handleSimpleResource("login.html"); - } - - String sessionId = httpCookie.getValue("JSESSIONID="); - if (sessionManager.findSession(sessionId) == null) { - return handleSimpleResource("login.html"); - } - return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); - } - - private String processLoginPostRequest(final HttpRequest httpRequest) throws IOException { - final String[] params = httpRequest.getBody().split("&"); - final String account = params[0].split("=")[1]; - final String password = params[1].split("=")[1]; - - final Optional userOptional = InMemoryUserRepository.findByAccount(account); - if (userOptional.isEmpty()) { - return handleSimpleResource("401.html"); - } - - final User user = userOptional.get(); - if (user.checkPassword(password)) { - final Session session = new Session(UUID.randomUUID().toString()); - session.setAttribute("user", user); - sessionManager.add(session); - return addCookie( - HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), - new HttpCookie("JSESSIONID=" + session.getId())); - } - - return handleSimpleResource("404.html"); - } - - private String processRegisterRequest(final HttpRequest httpRequest) throws IOException { - if (httpRequest.isSameMethod(HttpMethod.GET)) { - return handleSimpleResource("register.html"); - } - - if (httpRequest.isSameMethod(HttpMethod.POST)) { - return processRegisterPostRequest(httpRequest); - } - - return handleSimpleResource("401.html"); - } - - private String processRegisterPostRequest(final HttpRequest httpRequest) { - String[] body = httpRequest.getBody().split("&"); - String account = body[0].split("=")[1]; - String email = body[1].split("=")[1]; - String password = body[2].split("=")[1]; - InMemoryUserRepository.save(new User(account, password, email)); - return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); - } - - private String findResourcePath(final String resourcePath) { - final String[] fileNames = resourcePath.split("\\."); - final String extension = fileNames[1]; - - if (STATIC_RESOURCE_EXTENSIONS.containsKey(extension)) { - return STATIC_RESOURCE_ROOT_PATH.concat(STATIC_RESOURCE_EXTENSIONS.get(extension)).concat(PATH_DELIMITER) - .concat(resourcePath); - } - - return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); - } - - private String addCookie(final String response, final HttpCookie cookie) { - return response.concat("\n").concat("Set-Cookie: " + cookie.toString()); - } } diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java new file mode 100644 index 0000000000..5929a2d225 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -0,0 +1,80 @@ +package org.apache.coyote.handler; + +import java.io.IOException; +import java.util.Optional; +import java.util.UUID; + +import org.apache.catalina.SessionManager; +import org.apache.coyote.HttpCookie; +import org.apache.coyote.HttpMethod; +import org.apache.coyote.Session; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponseGenerator; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + +public class LoginHandler { + private static final LoginHandler INSTANCE = new LoginHandler(); + private final SessionManager sessionManager = SessionManager.getInstance(); + + private LoginHandler() { + } + + public static LoginHandler getInstance() { + return INSTANCE; + } + + public String processLoginRequest(final HttpRequest httpRequest) throws IOException { + if (httpRequest.isSameMethod(HttpMethod.GET)) { + return processLoginGetRequest(httpRequest); + } + + if (httpRequest.isSameMethod(HttpMethod.POST)) { + return processLoginPostRequest(httpRequest); + } + + return ResourceHandler.getInstance().handleSimpleResource("404.html"); + + } + + private String processLoginGetRequest(final HttpRequest httpRequest) throws IOException { + HttpCookie httpCookie = httpRequest.getHttpCookie(); + if (httpCookie == null) { + return ResourceHandler.getInstance().handleSimpleResource("login.html"); + } + + String sessionId = httpCookie.getValue("JSESSIONID="); + if (sessionManager.findSession(sessionId) == null) { + return ResourceHandler.getInstance().handleSimpleResource("login.html"); + } + return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); + } + + private String processLoginPostRequest(final HttpRequest httpRequest) throws IOException { + final String[] params = httpRequest.getBody().split("&"); + final String account = params[0].split("=")[1]; + final String password = params[1].split("=")[1]; + + final Optional userOptional = InMemoryUserRepository.findByAccount(account); + if (userOptional.isEmpty()) { + return ResourceHandler.getInstance().handleSimpleResource("401.html"); + } + + final User user = userOptional.get(); + if (user.checkPassword(password)) { + final Session session = new Session(UUID.randomUUID().toString()); + session.setAttribute("user", user); + sessionManager.add(session); + return addCookie( + HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), + new HttpCookie("JSESSIONID=" + session.getId())); + } + + return ResourceHandler.getInstance().handleSimpleResource("404.html"); + } + + private String addCookie(final String response, final HttpCookie cookie) { + return response.concat("\n").concat("Set-Cookie: " + cookie.toString()); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java new file mode 100644 index 0000000000..700fb1947c --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java @@ -0,0 +1,44 @@ +package org.apache.coyote.handler; + +import java.io.IOException; + +import org.apache.coyote.HttpMethod; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponseGenerator; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + +public class RegisterHandler { + + private static final RegisterHandler INSTANCE = new RegisterHandler(); + + private RegisterHandler() { + } + + public static RegisterHandler getInstance() { + return INSTANCE; + } + + public String processRegisterRequest(final HttpRequest httpRequest) throws IOException { + if (httpRequest.isSameMethod(HttpMethod.GET)) { + return ResourceHandler.getInstance().handleSimpleResource("register.html"); + } + + if (httpRequest.isSameMethod(HttpMethod.POST)) { + return processRegisterPostRequest(httpRequest); + } + + return ResourceHandler.getInstance().handleSimpleResource("401.html"); + } + + private String processRegisterPostRequest(final HttpRequest httpRequest) { + String[] body = httpRequest.getBody().split("&"); + String account = body[0].split("=")[1]; + String email = body[1].split("=")[1]; + String password = body[2].split("=")[1]; + InMemoryUserRepository.save(new User(account, password, email)); + return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); + } + +} diff --git a/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java new file mode 100644 index 0000000000..f9bc3b096d --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java @@ -0,0 +1,49 @@ +package org.apache.coyote.handler; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import org.apache.coyote.response.HttpResponseGenerator; + +public class ResourceHandler { + + private static final Map STATIC_RESOURCE_EXTENSIONS = Map.of( + "css", "css", + "js", "assets" + ); + private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; + private static final String PATH_DELIMITER = "/"; + + private static final ResourceHandler INSTANCE = new ResourceHandler(); + + private ResourceHandler() { + } + + public static ResourceHandler getInstance() { + return INSTANCE; + } + + public String handleSimpleResource(final String resourceName) throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); + final Path resourcePath = Path.of(resourceURL.getPath()); + final String responseBody = Files.readString(resourcePath); + final String mimeType = Files.probeContentType(resourcePath); + + return HttpResponseGenerator.getOkResponse(mimeType, responseBody); + } + + private String findResourcePath(final String resourcePath) { + final String[] fileNames = resourcePath.split("\\."); + final String extension = fileNames[1]; + + if (STATIC_RESOURCE_EXTENSIONS.containsKey(extension)) { + return STATIC_RESOURCE_ROOT_PATH.concat(STATIC_RESOURCE_EXTENSIONS.get(extension)).concat(PATH_DELIMITER) + .concat(resourcePath); + } + + return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); + } +} From 586ac33ee83000bb29c521febb88d15afec62bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 16:56:47 +0900 Subject: [PATCH 36/81] =?UTF-8?q?refactor(handler):=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EC=9D=84=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=B5=9C?= =?UTF-8?q?=EC=83=81=EC=9C=84=20Handler=20=EC=B6=94=EC=83=81=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/RequestHandler.java | 6 +++--- .../java/org/apache/coyote/handler/Handler.java | 7 +++++++ .../org/apache/coyote/handler/LoginHandler.java | 10 +++++----- .../org/apache/coyote/handler/RegisterHandler.java | 7 ++----- .../org/apache/coyote/handler/ResourceHandler.java | 14 +++++++++----- 5 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/Handler.java diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index 4475ea979f..ab31cc74f4 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -34,14 +34,14 @@ private String handleRoot() { } // TOOD: change naming - private String handleURL(final HttpRequest httpRequest) throws IOException { + private String handleURL(final HttpRequest httpRequest) { final String uri = httpRequest.getUrl(); if (uri.contains("login")) { - return LoginHandler.getInstance().processLoginRequest(httpRequest); + return LoginHandler.getInstance().handle(httpRequest); } if (uri.contains("register")) { - return RegisterHandler.getInstance().processRegisterRequest(httpRequest); + return RegisterHandler.getInstance().handle(httpRequest); } throw new IllegalCallerException("유효하지 않은 기능입니다."); diff --git a/tomcat/src/main/java/org/apache/coyote/handler/Handler.java b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java new file mode 100644 index 0000000000..d74064f8c0 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java @@ -0,0 +1,7 @@ +package org.apache.coyote.handler; + +import org.apache.coyote.request.HttpRequest; + +public abstract class Handler { + abstract String handle(HttpRequest httpRequest); +} diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 5929a2d225..7aa641b4e4 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -1,6 +1,5 @@ package org.apache.coyote.handler; -import java.io.IOException; import java.util.Optional; import java.util.UUID; @@ -14,7 +13,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -public class LoginHandler { +public class LoginHandler extends Handler { private static final LoginHandler INSTANCE = new LoginHandler(); private final SessionManager sessionManager = SessionManager.getInstance(); @@ -25,7 +24,8 @@ public static LoginHandler getInstance() { return INSTANCE; } - public String processLoginRequest(final HttpRequest httpRequest) throws IOException { + @Override + public String handle(final HttpRequest httpRequest) { if (httpRequest.isSameMethod(HttpMethod.GET)) { return processLoginGetRequest(httpRequest); } @@ -38,7 +38,7 @@ public String processLoginRequest(final HttpRequest httpRequest) throws IOExcept } - private String processLoginGetRequest(final HttpRequest httpRequest) throws IOException { + private String processLoginGetRequest(final HttpRequest httpRequest) { HttpCookie httpCookie = httpRequest.getHttpCookie(); if (httpCookie == null) { return ResourceHandler.getInstance().handleSimpleResource("login.html"); @@ -51,7 +51,7 @@ private String processLoginGetRequest(final HttpRequest httpRequest) throws IOEx return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } - private String processLoginPostRequest(final HttpRequest httpRequest) throws IOException { + private String processLoginPostRequest(final HttpRequest httpRequest) { final String[] params = httpRequest.getBody().split("&"); final String account = params[0].split("=")[1]; final String password = params[1].split("=")[1]; diff --git a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java index 700fb1947c..1974206094 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java @@ -1,7 +1,5 @@ package org.apache.coyote.handler; -import java.io.IOException; - import org.apache.coyote.HttpMethod; import org.apache.coyote.request.HttpRequest; import org.apache.coyote.response.HttpResponseGenerator; @@ -9,7 +7,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -public class RegisterHandler { +public class RegisterHandler extends Handler { private static final RegisterHandler INSTANCE = new RegisterHandler(); @@ -20,7 +18,7 @@ public static RegisterHandler getInstance() { return INSTANCE; } - public String processRegisterRequest(final HttpRequest httpRequest) throws IOException { + public String handle(final HttpRequest httpRequest) { if (httpRequest.isSameMethod(HttpMethod.GET)) { return ResourceHandler.getInstance().handleSimpleResource("register.html"); } @@ -40,5 +38,4 @@ private String processRegisterPostRequest(final HttpRequest httpRequest) { InMemoryUserRepository.save(new User(account, password, email)); return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } - } diff --git a/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java index f9bc3b096d..d19a107724 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java @@ -26,13 +26,17 @@ public static ResourceHandler getInstance() { return INSTANCE; } - public String handleSimpleResource(final String resourceName) throws IOException { + public String handleSimpleResource(final String resourceName) { final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); final Path resourcePath = Path.of(resourceURL.getPath()); - final String responseBody = Files.readString(resourcePath); - final String mimeType = Files.probeContentType(resourcePath); - - return HttpResponseGenerator.getOkResponse(mimeType, responseBody); + try { + final String responseBody = Files.readString(resourcePath); + final String mimeType = Files.probeContentType(resourcePath); + return HttpResponseGenerator.getOkResponse(mimeType, responseBody); + } catch (IOException e) { + e.printStackTrace(); + return HttpResponseGenerator.getFoundResponse("404.html"); + } } private String findResourcePath(final String resourcePath) { From 7ec70c70cd50aaf5950139942f211c1a2cf25f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:17:59 +0900 Subject: [PATCH 37/81] =?UTF-8?q?refactor(HttpHeader):=20toString=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/coyote/HttpHeader.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tomcat/src/main/java/org/apache/coyote/HttpHeader.java b/tomcat/src/main/java/org/apache/coyote/HttpHeader.java index 12d188502f..e4d6498759 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpHeader.java +++ b/tomcat/src/main/java/org/apache/coyote/HttpHeader.java @@ -16,4 +16,9 @@ public String getKey() { public String getValue() { return value; } + + @Override + public String toString() { + return key + ": " + value; + } } From 7dc68a1511339731db8fdcb2d5a9d8ccf9d749de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:18:26 +0900 Subject: [PATCH 38/81] =?UTF-8?q?refactor(RequestHandler):=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=98=88=EC=99=B8=20=EC=A0=84?= =?UTF-8?q?=ED=8C=8C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/coyote/RequestHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index ab31cc74f4..f5965a1569 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -1,7 +1,5 @@ package org.apache.coyote; -import java.io.IOException; - import org.apache.coyote.handler.LoginHandler; import org.apache.coyote.handler.RegisterHandler; import org.apache.coyote.handler.ResourceHandler; @@ -12,7 +10,7 @@ public class RequestHandler { private static final String PATH_DELIMITER = "/"; // TODO: mapping handler method - public String handle(final HttpRequest httpRequest) throws IOException { + public String handle(final HttpRequest httpRequest) { final String path = httpRequest.getPath(); final String[] paths = path.split(PATH_DELIMITER); From 0e8346a099587eb75111b5351c1fdc6566f5ff9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:28:48 +0900 Subject: [PATCH 39/81] =?UTF-8?q?refactor(mapping):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/RequestHandler.java | 23 +++----------- .../apache/coyote/handler/LoginHandler.java | 11 ++++--- .../coyote/handler/RegisterHandler.java | 5 +-- .../apache/coyote/mapping/HandlerMapping.java | 7 +++++ .../ResourceHandlerMapping.java} | 10 +++--- .../coyote/mapping/UrlHandlerMapping.java | 31 +++++++++++++++++++ 6 files changed, 56 insertions(+), 31 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java rename tomcat/src/main/java/org/apache/coyote/{handler/ResourceHandler.java => mapping/ResourceHandlerMapping.java} (86%) create mode 100644 tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java index f5965a1569..e2e1fc2e04 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -1,8 +1,7 @@ package org.apache.coyote; -import org.apache.coyote.handler.LoginHandler; -import org.apache.coyote.handler.RegisterHandler; -import org.apache.coyote.handler.ResourceHandler; +import org.apache.coyote.mapping.ResourceHandlerMapping; +import org.apache.coyote.mapping.UrlHandlerMapping; import org.apache.coyote.request.HttpRequest; import org.apache.coyote.response.HttpResponseGenerator; @@ -20,28 +19,14 @@ public String handle(final HttpRequest httpRequest) { final String resourceName = paths[paths.length - 1]; if (resourceName.contains(".")) { - return ResourceHandler.getInstance().handleSimpleResource(resourceName); + return ResourceHandlerMapping.getInstance().handleSimpleResource(resourceName); } - return handleURL(httpRequest); + return UrlHandlerMapping.getInstance().mapping(httpRequest); } private String handleRoot() { final String responseBody = "Hello world!"; return HttpResponseGenerator.getOkResponse("text/html", responseBody); } - - // TOOD: change naming - private String handleURL(final HttpRequest httpRequest) { - final String uri = httpRequest.getUrl(); - if (uri.contains("login")) { - return LoginHandler.getInstance().handle(httpRequest); - } - - if (uri.contains("register")) { - return RegisterHandler.getInstance().handle(httpRequest); - } - - throw new IllegalCallerException("유효하지 않은 기능입니다."); - } } diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 7aa641b4e4..6523bdc339 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -7,6 +7,7 @@ import org.apache.coyote.HttpCookie; import org.apache.coyote.HttpMethod; import org.apache.coyote.Session; +import org.apache.coyote.mapping.ResourceHandlerMapping; import org.apache.coyote.request.HttpRequest; import org.apache.coyote.response.HttpResponseGenerator; @@ -34,19 +35,19 @@ public String handle(final HttpRequest httpRequest) { return processLoginPostRequest(httpRequest); } - return ResourceHandler.getInstance().handleSimpleResource("404.html"); + return ResourceHandlerMapping.getInstance().handleSimpleResource("404.html"); } private String processLoginGetRequest(final HttpRequest httpRequest) { HttpCookie httpCookie = httpRequest.getHttpCookie(); if (httpCookie == null) { - return ResourceHandler.getInstance().handleSimpleResource("login.html"); + return ResourceHandlerMapping.getInstance().handleSimpleResource("login.html"); } String sessionId = httpCookie.getValue("JSESSIONID="); if (sessionManager.findSession(sessionId) == null) { - return ResourceHandler.getInstance().handleSimpleResource("login.html"); + return ResourceHandlerMapping.getInstance().handleSimpleResource("login.html"); } return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } @@ -58,7 +59,7 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { final Optional userOptional = InMemoryUserRepository.findByAccount(account); if (userOptional.isEmpty()) { - return ResourceHandler.getInstance().handleSimpleResource("401.html"); + return ResourceHandlerMapping.getInstance().handleSimpleResource("401.html"); } final User user = userOptional.get(); @@ -71,7 +72,7 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { new HttpCookie("JSESSIONID=" + session.getId())); } - return ResourceHandler.getInstance().handleSimpleResource("404.html"); + return ResourceHandlerMapping.getInstance().handleSimpleResource("404.html"); } private String addCookie(final String response, final HttpCookie cookie) { diff --git a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java index 1974206094..265abb97c4 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java @@ -1,6 +1,7 @@ package org.apache.coyote.handler; import org.apache.coyote.HttpMethod; +import org.apache.coyote.mapping.ResourceHandlerMapping; import org.apache.coyote.request.HttpRequest; import org.apache.coyote.response.HttpResponseGenerator; @@ -20,14 +21,14 @@ public static RegisterHandler getInstance() { public String handle(final HttpRequest httpRequest) { if (httpRequest.isSameMethod(HttpMethod.GET)) { - return ResourceHandler.getInstance().handleSimpleResource("register.html"); + return ResourceHandlerMapping.getInstance().handleSimpleResource("register.html"); } if (httpRequest.isSameMethod(HttpMethod.POST)) { return processRegisterPostRequest(httpRequest); } - return ResourceHandler.getInstance().handleSimpleResource("401.html"); + return ResourceHandlerMapping.getInstance().handleSimpleResource("401.html"); } private String processRegisterPostRequest(final HttpRequest httpRequest) { diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java new file mode 100644 index 0000000000..f0ae19b74d --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java @@ -0,0 +1,7 @@ +package org.apache.coyote.mapping; + +import org.apache.coyote.request.HttpRequest; + +public abstract class HandlerMapping { + abstract String mapping(HttpRequest httpRequest); +} diff --git a/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java similarity index 86% rename from tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java rename to tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java index d19a107724..fb99dd5a32 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/ResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java @@ -1,4 +1,4 @@ -package org.apache.coyote.handler; +package org.apache.coyote.mapping; import java.io.IOException; import java.net.URL; @@ -8,7 +8,7 @@ import org.apache.coyote.response.HttpResponseGenerator; -public class ResourceHandler { +public class ResourceHandlerMapping { private static final Map STATIC_RESOURCE_EXTENSIONS = Map.of( "css", "css", @@ -17,12 +17,12 @@ public class ResourceHandler { private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; private static final String PATH_DELIMITER = "/"; - private static final ResourceHandler INSTANCE = new ResourceHandler(); + private static final ResourceHandlerMapping INSTANCE = new ResourceHandlerMapping(); - private ResourceHandler() { + private ResourceHandlerMapping() { } - public static ResourceHandler getInstance() { + public static ResourceHandlerMapping getInstance() { return INSTANCE; } diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java new file mode 100644 index 0000000000..9976507bb5 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java @@ -0,0 +1,31 @@ +package org.apache.coyote.mapping; + +import org.apache.coyote.handler.LoginHandler; +import org.apache.coyote.handler.RegisterHandler; +import org.apache.coyote.request.HttpRequest; + +public class UrlHandlerMapping extends HandlerMapping { + + private static final UrlHandlerMapping INSTANCE = new UrlHandlerMapping(); + + private UrlHandlerMapping() { + } + + @Override + public String mapping(HttpRequest httpRequest) { + final String uri = httpRequest.getUrl(); + if (uri.contains("login")) { + return LoginHandler.getInstance().handle(httpRequest); + } + + if (uri.contains("register")) { + return RegisterHandler.getInstance().handle(httpRequest); + } + + throw new IllegalCallerException("유효하지 않은 기능입니다."); + } + + public static UrlHandlerMapping getInstance() { + return INSTANCE; + } +} From eec0659fd0f621cb0c670890d29ec41242b73c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:38:14 +0900 Subject: [PATCH 40/81] =?UTF-8?q?feat(EtagFilterConfiguration):=20etag=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cache/com/example/etag/EtagFilterConfiguration.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java index 04d792a493..35e972aeae 100644 --- a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java +++ b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java @@ -5,6 +5,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.ShallowEtagHeaderFilter; +import cache.com.example.version.CacheBustingWebConfig; + @Configuration public class EtagFilterConfiguration { @@ -12,6 +14,7 @@ public class EtagFilterConfiguration { public FilterRegistrationBean shallowEtagHeaderFilter() { FilterRegistrationBean filter = new FilterRegistrationBean<>(); filter.setFilter(new ShallowEtagHeaderFilter()); + filter.addUrlPatterns("/etag", CacheBustingWebConfig.PREFIX_STATIC_RESOURCES + "/*"); return filter; } } From 953dea1f7d1c9cbad4579de6eb26cedf223fc136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:38:56 +0900 Subject: [PATCH 41/81] =?UTF-8?q?refactor(CacheBustingWebConfig):=20bustin?= =?UTF-8?q?g=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache/com/example/version/CacheBustingWebConfig.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java b/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java index 6da6d2c795..8cf8162a46 100644 --- a/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java +++ b/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java @@ -1,7 +1,10 @@ package cache.com.example.version; +import java.time.Duration; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -20,6 +23,7 @@ public CacheBustingWebConfig(ResourceVersion version) { @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**") - .addResourceLocations("classpath:/static/"); + .addResourceLocations("classpath:/static/") + .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic()); } } From 96f9b695581a93840cb3fb8e42ceca84d4885d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:51:19 +0900 Subject: [PATCH 42/81] =?UTF-8?q?test(Http11ProcessorTest):=20content-leng?= =?UTF-8?q?th=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/java/org/apache/coyote/http11/Http11ProcessorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java index 2aba8c56e0..d3397c7967 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -52,7 +52,7 @@ void index() throws IOException { final URL resource = getClass().getClassLoader().getResource("static/index.html"); var expected = "HTTP/1.1 200 OK \r\n" + "Content-Type: text/html;charset=utf-8 \r\n" + - "Content-Length: 5564 \r\n" + + "Content-Length: 5128 \r\n" + "\r\n"+ new String(Files.readAllBytes(new File(resource.getFile()).toPath())); From 809d0fefbfbee04da43280736fbcfcb2c9a868b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:58:15 +0900 Subject: [PATCH 43/81] =?UTF-8?q?refactor(RequestHandlerAdapter):=20Adapte?= =?UTF-8?q?r=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{RequestHandler.java => RequestHandlerAdapter.java} | 2 +- .../main/java/org/apache/coyote/http11/Http11Processor.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename tomcat/src/main/java/org/apache/coyote/{RequestHandler.java => RequestHandlerAdapter.java} (96%) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java similarity index 96% rename from tomcat/src/main/java/org/apache/coyote/RequestHandler.java rename to tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java index e2e1fc2e04..e07c02649d 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java @@ -5,7 +5,7 @@ import org.apache.coyote.request.HttpRequest; import org.apache.coyote.response.HttpResponseGenerator; -public class RequestHandler { +public class RequestHandlerAdapter { private static final String PATH_DELIMITER = "/"; // TODO: mapping handler method diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index e482918e42..7fb7e881cf 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -10,7 +10,7 @@ import org.apache.coyote.request.HttpRequest; import org.apache.coyote.request.HttpRequestParser; import org.apache.coyote.Processor; -import org.apache.coyote.RequestHandler; +import org.apache.coyote.RequestHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,8 +39,8 @@ public void process(final Socket connection) { final OutputStream outputStream = connection.getOutputStream()) { final HttpRequest httpRequest = HttpRequestParser.parseRequest(bufferedReader); - final RequestHandler requestHandler = new RequestHandler(); - final String response = requestHandler.handle(httpRequest); + final RequestHandlerAdapter requestHandlerAdapter = new RequestHandlerAdapter(); + final String response = requestHandlerAdapter.handle(httpRequest); System.out.println(response); outputStream.write(response.getBytes()); From 60fd852525efc50fccba66ad9214d76039b87147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:01:36 +0900 Subject: [PATCH 44/81] =?UTF-8?q?refactor(/http):=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0,=20http=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/RequestHandlerAdapter.java | 4 ++-- .../src/main/java/org/apache/coyote/handler/Handler.java | 2 +- .../main/java/org/apache/coyote/handler/LoginHandler.java | 8 ++++---- .../java/org/apache/coyote/handler/RegisterHandler.java | 6 +++--- .../java/org/apache/coyote/http11/Http11Processor.java | 4 ++-- .../java/org/apache/coyote/mapping/HandlerMapping.java | 2 +- .../org/apache/coyote/mapping/ResourceHandlerMapping.java | 2 +- .../java/org/apache/coyote/mapping/UrlHandlerMapping.java | 2 +- .../main/java/org/apache/{coyote => http}/HttpCookie.java | 2 +- .../main/java/org/apache/{coyote => http}/HttpHeader.java | 2 +- .../main/java/org/apache/{coyote => http}/HttpMethod.java | 2 +- .../org/apache/{coyote => http}/request/HttpRequest.java | 8 ++++---- .../{coyote => http}/request/HttpRequestParser.java | 4 ++-- .../{coyote => http}/response/HttpResponseGenerator.java | 2 +- 14 files changed, 25 insertions(+), 25 deletions(-) rename tomcat/src/main/java/org/apache/{coyote => http}/HttpCookie.java (97%) rename tomcat/src/main/java/org/apache/{coyote => http}/HttpHeader.java (93%) rename tomcat/src/main/java/org/apache/{coyote => http}/HttpMethod.java (83%) rename tomcat/src/main/java/org/apache/{coyote => http}/request/HttpRequest.java (93%) rename tomcat/src/main/java/org/apache/{coyote => http}/request/HttpRequestParser.java (96%) rename tomcat/src/main/java/org/apache/{coyote => http}/response/HttpResponseGenerator.java (93%) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java b/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java index e07c02649d..a99a28af1a 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java @@ -2,8 +2,8 @@ import org.apache.coyote.mapping.ResourceHandlerMapping; import org.apache.coyote.mapping.UrlHandlerMapping; -import org.apache.coyote.request.HttpRequest; -import org.apache.coyote.response.HttpResponseGenerator; +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; public class RequestHandlerAdapter { private static final String PATH_DELIMITER = "/"; diff --git a/tomcat/src/main/java/org/apache/coyote/handler/Handler.java b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java index d74064f8c0..1391da41e9 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/Handler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java @@ -1,6 +1,6 @@ package org.apache.coyote.handler; -import org.apache.coyote.request.HttpRequest; +import org.apache.http.request.HttpRequest; public abstract class Handler { abstract String handle(HttpRequest httpRequest); diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 6523bdc339..b2d781929b 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -4,12 +4,12 @@ import java.util.UUID; import org.apache.catalina.SessionManager; -import org.apache.coyote.HttpCookie; -import org.apache.coyote.HttpMethod; +import org.apache.http.HttpCookie; +import org.apache.http.HttpMethod; import org.apache.coyote.Session; import org.apache.coyote.mapping.ResourceHandlerMapping; -import org.apache.coyote.request.HttpRequest; -import org.apache.coyote.response.HttpResponseGenerator; +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; diff --git a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java index 265abb97c4..2747e79c97 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java @@ -1,9 +1,9 @@ package org.apache.coyote.handler; -import org.apache.coyote.HttpMethod; +import org.apache.http.HttpMethod; import org.apache.coyote.mapping.ResourceHandlerMapping; -import org.apache.coyote.request.HttpRequest; -import org.apache.coyote.response.HttpResponseGenerator; +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 7fb7e881cf..0dbdc83433 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -7,8 +7,8 @@ import java.io.OutputStream; import java.net.Socket; -import org.apache.coyote.request.HttpRequest; -import org.apache.coyote.request.HttpRequestParser; +import org.apache.http.request.HttpRequest; +import org.apache.http.request.HttpRequestParser; import org.apache.coyote.Processor; import org.apache.coyote.RequestHandlerAdapter; import org.slf4j.Logger; diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java index f0ae19b74d..8993039de5 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java @@ -1,6 +1,6 @@ package org.apache.coyote.mapping; -import org.apache.coyote.request.HttpRequest; +import org.apache.http.request.HttpRequest; public abstract class HandlerMapping { abstract String mapping(HttpRequest httpRequest); diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java index fb99dd5a32..9e47ea1f4f 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java @@ -6,7 +6,7 @@ import java.nio.file.Path; import java.util.Map; -import org.apache.coyote.response.HttpResponseGenerator; +import org.apache.http.response.HttpResponseGenerator; public class ResourceHandlerMapping { diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java index 9976507bb5..0e14c55594 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java @@ -2,7 +2,7 @@ import org.apache.coyote.handler.LoginHandler; import org.apache.coyote.handler.RegisterHandler; -import org.apache.coyote.request.HttpRequest; +import org.apache.http.request.HttpRequest; public class UrlHandlerMapping extends HandlerMapping { diff --git a/tomcat/src/main/java/org/apache/coyote/HttpCookie.java b/tomcat/src/main/java/org/apache/http/HttpCookie.java similarity index 97% rename from tomcat/src/main/java/org/apache/coyote/HttpCookie.java rename to tomcat/src/main/java/org/apache/http/HttpCookie.java index d788cbc162..4f80dab514 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/http/HttpCookie.java @@ -1,4 +1,4 @@ -package org.apache.coyote; +package org.apache.http; import java.util.Arrays; import java.util.HashMap; diff --git a/tomcat/src/main/java/org/apache/coyote/HttpHeader.java b/tomcat/src/main/java/org/apache/http/HttpHeader.java similarity index 93% rename from tomcat/src/main/java/org/apache/coyote/HttpHeader.java rename to tomcat/src/main/java/org/apache/http/HttpHeader.java index e4d6498759..d0f0f88e7d 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpHeader.java +++ b/tomcat/src/main/java/org/apache/http/HttpHeader.java @@ -1,4 +1,4 @@ -package org.apache.coyote; +package org.apache.http; public class HttpHeader { private final String key; diff --git a/tomcat/src/main/java/org/apache/coyote/HttpMethod.java b/tomcat/src/main/java/org/apache/http/HttpMethod.java similarity index 83% rename from tomcat/src/main/java/org/apache/coyote/HttpMethod.java rename to tomcat/src/main/java/org/apache/http/HttpMethod.java index c0388ae944..6d1f5fc047 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpMethod.java +++ b/tomcat/src/main/java/org/apache/http/HttpMethod.java @@ -1,4 +1,4 @@ -package org.apache.coyote; +package org.apache.http; public enum HttpMethod { GET, diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java similarity index 93% rename from tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java rename to tomcat/src/main/java/org/apache/http/request/HttpRequest.java index 009cd45d3d..a07cdad966 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java @@ -1,10 +1,10 @@ -package org.apache.coyote.request; +package org.apache.http.request; import java.util.Arrays; -import org.apache.coyote.HttpCookie; -import org.apache.coyote.HttpHeader; -import org.apache.coyote.HttpMethod; +import org.apache.http.HttpCookie; +import org.apache.http.HttpHeader; +import org.apache.http.HttpMethod; public class HttpRequest { private final HttpMethod method; diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java similarity index 96% rename from tomcat/src/main/java/org/apache/coyote/request/HttpRequestParser.java rename to tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java index c09bc9060c..d84f543251 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java @@ -1,4 +1,4 @@ -package org.apache.coyote.request; +package org.apache.http.request; import java.io.BufferedReader; import java.io.IOException; @@ -7,7 +7,7 @@ import java.util.List; import java.util.Optional; -import org.apache.coyote.HttpHeader; +import org.apache.http.HttpHeader; public class HttpRequestParser { diff --git a/tomcat/src/main/java/org/apache/coyote/response/HttpResponseGenerator.java b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java similarity index 93% rename from tomcat/src/main/java/org/apache/coyote/response/HttpResponseGenerator.java rename to tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java index c571030c1c..3516a35e78 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/HttpResponseGenerator.java +++ b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java @@ -1,4 +1,4 @@ -package org.apache.coyote.response; +package org.apache.http.response; public class HttpResponseGenerator { public static String getOkResponse(String mimeType, String responseBody) { From cbd6b197bfd6b54f7e665f741f2c3b3d0d04b883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:34:17 +0900 Subject: [PATCH 45/81] =?UTF-8?q?refactor(Http11Processor):=20sout?= =?UTF-8?q?=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/http11/Http11Processor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 0dbdc83433..0aa22dd9ee 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -42,7 +42,6 @@ public void process(final Socket connection) { final RequestHandlerAdapter requestHandlerAdapter = new RequestHandlerAdapter(); final String response = requestHandlerAdapter.handle(httpRequest); - System.out.println(response); outputStream.write(response.getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { From cd3776b9de802158cb69356c1926c13dfd47dce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:35:53 +0900 Subject: [PATCH 46/81] =?UTF-8?q?refactor(HttpRequestParser):=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=A0=95=EC=9D=98=EB=90=9C=20=EC=A1=B0=EA=B1=B4?= =?UTF-8?q?=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/http/request/HttpRequestParser.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java index d84f543251..326916e775 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java @@ -34,9 +34,6 @@ private static HttpHeader[] parseRequestHeaders(final BufferedReader bufferedRea String[] keyAndValue = header.split(": "); headers.add(new HttpHeader(keyAndValue[0], keyAndValue[1])); header = bufferedReader.readLine(); - if(header.isEmpty()) { - break; - } } return headers.toArray(HttpHeader[]::new); From a2c3b1f35d4b7addbcc61938974e5d4dca711bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:39:12 +0900 Subject: [PATCH 47/81] =?UTF-8?q?refactor:=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=20=EC=8B=9C=EC=9E=91=20=EC=A4=84=EC=97=90=20=EA=B0=9C=ED=96=89?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java | 1 + .../java/org/apache/http/response/HttpResponseGenerator.java | 1 + 2 files changed, 2 insertions(+) diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index b2d781929b..a7e5440221 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -15,6 +15,7 @@ import com.techcourse.model.User; public class LoginHandler extends Handler { + private static final LoginHandler INSTANCE = new LoginHandler(); private final SessionManager sessionManager = SessionManager.getInstance(); diff --git a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java index 3516a35e78..5bc9cc61f9 100644 --- a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java +++ b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java @@ -1,6 +1,7 @@ package org.apache.http.response; public class HttpResponseGenerator { + public static String getOkResponse(String mimeType, String responseBody) { return String.join("\r\n", "HTTP/1.1 200 OK ", From ef92ee3c21800aa47f86dbdd4b076611508aad42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:21:49 +0900 Subject: [PATCH 48/81] =?UTF-8?q?test(SessionManager):=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=B4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/catalina/SessionManagerTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java diff --git a/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java b/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java new file mode 100644 index 0000000000..a5fc14ca51 --- /dev/null +++ b/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java @@ -0,0 +1,61 @@ +package org.apache.catalina; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.apache.coyote.Session; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class SessionManagerTest { + + private final SessionManager sessionManager = SessionManager.getInstance(); + + @Test + @DisplayName("세션 추가 성공") + void add() { + // given + String sessionId = "1"; + + assertThat(sessionManager.findSession(sessionId)).isNull(); + Session session = new Session(sessionId); + sessionManager.add(session); + assertThat(sessionManager.findSession(sessionId)).isEqualTo(session); + + // after + sessionManager.remove(session); + } + + @Test + @DisplayName("세션 조회 성공: 존재하지 않는 세션인 경우 null을 반환") + void findSession() { + String existSessionId = "1"; + String notExistSessionId = "2"; + + Session existSession = new Session(existSessionId); + sessionManager.add(existSession); + + assertAll( + () -> assertThat(sessionManager.findSession(existSessionId)).isEqualTo(existSession), + () -> assertThat(sessionManager.findSession(notExistSessionId)).isNull() + ); + + // after + sessionManager.remove(existSession); + } + + @Test + @DisplayName("세션 삭제 성공") + void remove() { + // given + String existSessionId = "1"; + sessionManager.add(new Session(existSessionId)); + Session savedSession = sessionManager.findSession(existSessionId); + + // when + sessionManager.remove(savedSession); + + // then + assertThat(sessionManager.findSession(savedSession.getId())).isNull(); + } +} From 36dbef59fd7ab9f88203402955061034addd7da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:59:25 +0900 Subject: [PATCH 49/81] =?UTF-8?q?refactor(/catalina/session):=20session=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=EB=93=A4=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/catalina/{ => session}/Manager.java | 4 +--- .../java/org/apache/{coyote => catalina/session}/Session.java | 2 +- .../org/apache/catalina/{ => session}/SessionManager.java | 4 +--- .../src/main/java/org/apache/coyote/handler/LoginHandler.java | 4 ++-- .../src/test/java/org/apache/catalina/SessionManagerTest.java | 3 ++- 5 files changed, 7 insertions(+), 10 deletions(-) rename tomcat/src/main/java/org/apache/catalina/{ => session}/Manager.java (96%) rename tomcat/src/main/java/org/apache/{coyote => catalina/session}/Session.java (95%) rename tomcat/src/main/java/org/apache/catalina/{ => session}/SessionManager.java (91%) diff --git a/tomcat/src/main/java/org/apache/catalina/Manager.java b/tomcat/src/main/java/org/apache/catalina/session/Manager.java similarity index 96% rename from tomcat/src/main/java/org/apache/catalina/Manager.java rename to tomcat/src/main/java/org/apache/catalina/session/Manager.java index 7a3b32d401..41d4b152e9 100644 --- a/tomcat/src/main/java/org/apache/catalina/Manager.java +++ b/tomcat/src/main/java/org/apache/catalina/session/Manager.java @@ -1,9 +1,7 @@ -package org.apache.catalina; +package org.apache.catalina.session; import java.io.IOException; -import org.apache.coyote.Session; - /** * A Manager manages the pool of Sessions that are associated with a * particular Container. Different Manager implementations may support diff --git a/tomcat/src/main/java/org/apache/coyote/Session.java b/tomcat/src/main/java/org/apache/catalina/session/Session.java similarity index 95% rename from tomcat/src/main/java/org/apache/coyote/Session.java rename to tomcat/src/main/java/org/apache/catalina/session/Session.java index eb57a32f49..93c4d3357c 100644 --- a/tomcat/src/main/java/org/apache/coyote/Session.java +++ b/tomcat/src/main/java/org/apache/catalina/session/Session.java @@ -1,4 +1,4 @@ -package org.apache.coyote; +package org.apache.catalina.session; import java.util.HashMap; import java.util.Map; diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java similarity index 91% rename from tomcat/src/main/java/org/apache/catalina/SessionManager.java rename to tomcat/src/main/java/org/apache/catalina/session/SessionManager.java index 8667dd30b6..168055c1bb 100644 --- a/tomcat/src/main/java/org/apache/catalina/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java @@ -1,10 +1,8 @@ -package org.apache.catalina; +package org.apache.catalina.session; import java.util.HashMap; import java.util.Map; -import org.apache.coyote.Session; - public class SessionManager implements Manager { private static final Map SESSIONS = new HashMap<>(); private static final SessionManager INSTANCE = new SessionManager(); diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index a7e5440221..2e62645eaf 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -3,10 +3,10 @@ import java.util.Optional; import java.util.UUID; -import org.apache.catalina.SessionManager; +import org.apache.catalina.session.SessionManager; import org.apache.http.HttpCookie; import org.apache.http.HttpMethod; -import org.apache.coyote.Session; +import org.apache.catalina.session.Session; import org.apache.coyote.mapping.ResourceHandlerMapping; import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; diff --git a/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java b/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java index a5fc14ca51..c17ca4481d 100644 --- a/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java +++ b/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java @@ -3,7 +3,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import org.apache.coyote.Session; +import org.apache.catalina.session.Session; +import org.apache.catalina.session.SessionManager; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From e92d1911b4b260b920439ff59813b4ccdbcd8b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 21:55:26 +0900 Subject: [PATCH 50/81] =?UTF-8?q?refactor(Session):=20=EC=84=B8=EC=85=98?= =?UTF-8?q?=EC=97=90=20=EC=86=8D=EC=84=B1=EC=9D=84=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=EC=9D=98=20?= =?UTF-8?q?=EC=9D=B8=EC=9E=90=20=EC=9D=B4=EB=A6=84=20=EB=AA=85=ED=99=95?= =?UTF-8?q?=ED=95=98=EA=B2=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/catalina/session/Session.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/session/Session.java b/tomcat/src/main/java/org/apache/catalina/session/Session.java index 93c4d3357c..82cdf13ea9 100644 --- a/tomcat/src/main/java/org/apache/catalina/session/Session.java +++ b/tomcat/src/main/java/org/apache/catalina/session/Session.java @@ -29,7 +29,7 @@ public Map getValues() { return values; } - public void setAttribute(String sessionId, Object value) { - values.put(sessionId, value); + public void setAttribute(String name, Object value) { + values.put(name, value); } } From 91088694c042a8386e3c249be917728ddeef5d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 21:55:47 +0900 Subject: [PATCH 51/81] =?UTF-8?q?test(SessionTest):=20=EC=86=8D=EC=84=B1?= =?UTF-8?q?=EA=B0=92=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/catalina/session/SessionTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/catalina/session/SessionTest.java diff --git a/tomcat/src/test/java/org/apache/catalina/session/SessionTest.java b/tomcat/src/test/java/org/apache/catalina/session/SessionTest.java new file mode 100644 index 0000000000..030766964e --- /dev/null +++ b/tomcat/src/test/java/org/apache/catalina/session/SessionTest.java @@ -0,0 +1,22 @@ +package org.apache.catalina.session; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.UUID; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class SessionTest { + + @Test + @DisplayName("세션의 속성값 조회") + void getAttribute() { + Session session = new Session("1"); + session.setAttribute("1", "value1"); + session.setAttribute("2", "value2"); + + assertThat(session.getAttribute("1")).isEqualTo("value1"); + } +} From ab376fd98f093a49236ba25f7af317a44a036058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 22:35:38 +0900 Subject: [PATCH 52/81] =?UTF-8?q?refactor(ResourceHandlerMapping):=20conca?= =?UTF-8?q?t=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=B2=B4=EC=9D=B4?= =?UTF-8?q?=EB=8B=9D=EC=B2=98=EB=9F=BC=20=EA=B0=9C=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/mapping/ResourceHandlerMapping.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java index 9e47ea1f4f..8b7e141a0e 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java @@ -44,7 +44,9 @@ private String findResourcePath(final String resourcePath) { final String extension = fileNames[1]; if (STATIC_RESOURCE_EXTENSIONS.containsKey(extension)) { - return STATIC_RESOURCE_ROOT_PATH.concat(STATIC_RESOURCE_EXTENSIONS.get(extension)).concat(PATH_DELIMITER) + return STATIC_RESOURCE_ROOT_PATH + .concat(STATIC_RESOURCE_EXTENSIONS.get(extension)) + .concat(PATH_DELIMITER) .concat(resourcePath); } From fdb5ce978f71a44d344c30886b6ee3494eae8647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 22:47:03 +0900 Subject: [PATCH 53/81] =?UTF-8?q?refactor(UrlHandlerMapping):=20IllegalCal?= =?UTF-8?q?lerException=20=EB=8D=98=EC=A7=80=EC=A7=80=20=EC=95=8A=EA=B3=A0?= =?UTF-8?q?=20404=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/mapping/UrlHandlerMapping.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java index 0e14c55594..b8e93acd86 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java @@ -22,7 +22,7 @@ public String mapping(HttpRequest httpRequest) { return RegisterHandler.getInstance().handle(httpRequest); } - throw new IllegalCallerException("유효하지 않은 기능입니다."); + return ResourceHandlerMapping.getInstance().handleSimpleResource("404.html"); } public static UrlHandlerMapping getInstance() { From 03e7a205e35c81750d7ede26e5549e125a4ca04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 23:52:40 +0900 Subject: [PATCH 54/81] =?UTF-8?q?refactor(StaticResourceHandler):=20Handle?= =?UTF-8?q?r=20=EC=83=81=EC=86=8D=20=EB=B0=8F=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/RequestHandlerAdapter.java | 4 +-- .../org/apache/coyote/handler/Handler.java | 1 + .../apache/coyote/handler/LoginHandler.java | 11 +++---- .../coyote/handler/RegisterHandler.java | 5 ++- .../StaticResourceHandler.java} | 31 +++++++++++-------- .../coyote/mapping/UrlHandlerMapping.java | 13 ++++---- 6 files changed, 35 insertions(+), 30 deletions(-) rename tomcat/src/main/java/org/apache/coyote/{mapping/ResourceHandlerMapping.java => handler/StaticResourceHandler.java} (58%) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java b/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java index a99a28af1a..57ae22961e 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java @@ -1,6 +1,6 @@ package org.apache.coyote; -import org.apache.coyote.mapping.ResourceHandlerMapping; +import org.apache.coyote.handler.StaticResourceHandler; import org.apache.coyote.mapping.UrlHandlerMapping; import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; @@ -19,7 +19,7 @@ public String handle(final HttpRequest httpRequest) { final String resourceName = paths[paths.length - 1]; if (resourceName.contains(".")) { - return ResourceHandlerMapping.getInstance().handleSimpleResource(resourceName); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "404.html", "HTTP/1.1", null, null)); } return UrlHandlerMapping.getInstance().mapping(httpRequest); diff --git a/tomcat/src/main/java/org/apache/coyote/handler/Handler.java b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java index 1391da41e9..c2164f3dbc 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/Handler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java @@ -3,5 +3,6 @@ import org.apache.http.request.HttpRequest; public abstract class Handler { + // TODO: 반환타입 HttpResponse로 변경 abstract String handle(HttpRequest httpRequest); } diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 2e62645eaf..8fecc2d434 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -7,7 +7,6 @@ import org.apache.http.HttpCookie; import org.apache.http.HttpMethod; import org.apache.catalina.session.Session; -import org.apache.coyote.mapping.ResourceHandlerMapping; import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; @@ -36,19 +35,19 @@ public String handle(final HttpRequest httpRequest) { return processLoginPostRequest(httpRequest); } - return ResourceHandlerMapping.getInstance().handleSimpleResource("404.html"); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/404.html", "HTTP/1.1", null, null)); } private String processLoginGetRequest(final HttpRequest httpRequest) { HttpCookie httpCookie = httpRequest.getHttpCookie(); if (httpCookie == null) { - return ResourceHandlerMapping.getInstance().handleSimpleResource("login.html"); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/login.html", "HTTP/1.1", null, null)); } String sessionId = httpCookie.getValue("JSESSIONID="); if (sessionManager.findSession(sessionId) == null) { - return ResourceHandlerMapping.getInstance().handleSimpleResource("login.html"); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/login.html", "HTTP/1.1", null, null)); } return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } @@ -60,7 +59,7 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { final Optional userOptional = InMemoryUserRepository.findByAccount(account); if (userOptional.isEmpty()) { - return ResourceHandlerMapping.getInstance().handleSimpleResource("401.html"); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/401.html", "HTTP/1.1", null, null)); } final User user = userOptional.get(); @@ -73,7 +72,7 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { new HttpCookie("JSESSIONID=" + session.getId())); } - return ResourceHandlerMapping.getInstance().handleSimpleResource("404.html"); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/404.html", "HTTP/1.1", null, null)); } private String addCookie(final String response, final HttpCookie cookie) { diff --git a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java index 2747e79c97..e06d388e00 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java @@ -1,7 +1,6 @@ package org.apache.coyote.handler; import org.apache.http.HttpMethod; -import org.apache.coyote.mapping.ResourceHandlerMapping; import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; @@ -21,14 +20,14 @@ public static RegisterHandler getInstance() { public String handle(final HttpRequest httpRequest) { if (httpRequest.isSameMethod(HttpMethod.GET)) { - return ResourceHandlerMapping.getInstance().handleSimpleResource("register.html"); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/register.html", "HTTP/1.1", null, null)); } if (httpRequest.isSameMethod(HttpMethod.POST)) { return processRegisterPostRequest(httpRequest); } - return ResourceHandlerMapping.getInstance().handleSimpleResource("401.html"); + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/401.html", "HTTP/1.1", null, null)); } private String processRegisterPostRequest(final HttpRequest httpRequest) { diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java similarity index 58% rename from tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java rename to tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java index 8b7e141a0e..dd7886fcd1 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/ResourceHandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java @@ -1,4 +1,4 @@ -package org.apache.coyote.mapping; +package org.apache.coyote.handler; import java.io.IOException; import java.net.URL; @@ -6,9 +6,10 @@ import java.nio.file.Path; import java.util.Map; +import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; -public class ResourceHandlerMapping { +public class StaticResourceHandler extends Handler { private static final Map STATIC_RESOURCE_EXTENSIONS = Map.of( "css", "css", @@ -17,39 +18,43 @@ public class ResourceHandlerMapping { private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; private static final String PATH_DELIMITER = "/"; - private static final ResourceHandlerMapping INSTANCE = new ResourceHandlerMapping(); + private static final StaticResourceHandler INSTANCE = new StaticResourceHandler(); - private ResourceHandlerMapping() { + private StaticResourceHandler() { } - public static ResourceHandlerMapping getInstance() { + public static StaticResourceHandler getInstance() { return INSTANCE; } - public String handleSimpleResource(final String resourceName) { - final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(resourceName)); + public String handle(final HttpRequest httpRequest) { + final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(httpRequest.getPath())); final Path resourcePath = Path.of(resourceURL.getPath()); try { final String responseBody = Files.readString(resourcePath); final String mimeType = Files.probeContentType(resourcePath); return HttpResponseGenerator.getOkResponse(mimeType, responseBody); } catch (IOException e) { - e.printStackTrace(); return HttpResponseGenerator.getFoundResponse("404.html"); } } - private String findResourcePath(final String resourcePath) { - final String[] fileNames = resourcePath.split("\\."); - final String extension = fileNames[1]; + private String findResourcePath(final String path) { + final String[] resourceNames = findResourceName(path).split("\\."); + final String extension = resourceNames[1]; if (STATIC_RESOURCE_EXTENSIONS.containsKey(extension)) { return STATIC_RESOURCE_ROOT_PATH .concat(STATIC_RESOURCE_EXTENSIONS.get(extension)) .concat(PATH_DELIMITER) - .concat(resourcePath); + .concat(path); } - return STATIC_RESOURCE_ROOT_PATH.concat(resourcePath); + return STATIC_RESOURCE_ROOT_PATH.concat(path); + } + + private String findResourceName(final String path) { + final String[] paths = path.split(PATH_DELIMITER); + return paths[paths.length - 1]; } } diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java index b8e93acd86..e32addea85 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java @@ -2,6 +2,7 @@ import org.apache.coyote.handler.LoginHandler; import org.apache.coyote.handler.RegisterHandler; +import org.apache.coyote.handler.StaticResourceHandler; import org.apache.http.request.HttpRequest; public class UrlHandlerMapping extends HandlerMapping { @@ -11,9 +12,13 @@ public class UrlHandlerMapping extends HandlerMapping { private UrlHandlerMapping() { } + public static UrlHandlerMapping getInstance() { + return INSTANCE; + } + @Override public String mapping(HttpRequest httpRequest) { - final String uri = httpRequest.getUrl(); + final String uri = httpRequest.getPath(); if (uri.contains("login")) { return LoginHandler.getInstance().handle(httpRequest); } @@ -22,10 +27,6 @@ public String mapping(HttpRequest httpRequest) { return RegisterHandler.getInstance().handle(httpRequest); } - return ResourceHandlerMapping.getInstance().handleSimpleResource("404.html"); - } - - public static UrlHandlerMapping getInstance() { - return INSTANCE; + return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/404.html", "HTTP/1.1", null, null)); } } From 312cff6dfefc85ca6a417d20e9a86208a697972e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Mon, 9 Sep 2024 23:53:09 +0900 Subject: [PATCH 55/81] =?UTF-8?q?test(StaticResourceHandler):=20=EC=A0=95?= =?UTF-8?q?=EC=A0=81=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handler/StaticResourceHandlerTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java new file mode 100644 index 0000000000..802cbcc9b1 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java @@ -0,0 +1,41 @@ +package org.apache.coyote.handler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class StaticResourceHandlerTest { + + @Test + @DisplayName("정적 리소스 처리: 기본적으로 /static 경로에 있는 리소스를 반환") + void handle() throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource("static/404.html"); + final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + + final StaticResourceHandler handler = StaticResourceHandler.getInstance(); + final String response = handler.handle(new HttpRequest("GET", "404.html", "HTTP/1.1", null, null)); + + assertThat(response).contains(responseBody); + } + + @Test + @DisplayName("정적 리소스 처리: 확장자에 따라 다른 경로에 있는 리소스를 반환") + void handle_When_Different_Extension_Resource() throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource("static/css/styles.css"); + final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + + final StaticResourceHandler handler = StaticResourceHandler.getInstance(); + final String response = handler.handle(new HttpRequest("GET", "styles.css", "HTTP/1.1", null, null)); + + assertThat(response).contains(responseBody); + } +} From 1cfca7f892a9dbf16cc70bfe5d758de08a132e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 00:34:02 +0900 Subject: [PATCH 56/81] =?UTF-8?q?refactor(LoginHandler):=20Get=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/handler/LoginHandler.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 8fecc2d434..55d8873b6e 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -41,14 +41,10 @@ public String handle(final HttpRequest httpRequest) { private String processLoginGetRequest(final HttpRequest httpRequest) { HttpCookie httpCookie = httpRequest.getHttpCookie(); - if (httpCookie == null) { + if (httpCookie == null || ! sessionManager.existsById(httpCookie.getValue("JSESSIONID"))) { return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/login.html", "HTTP/1.1", null, null)); } - String sessionId = httpCookie.getValue("JSESSIONID="); - if (sessionManager.findSession(sessionId) == null) { - return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/login.html", "HTTP/1.1", null, null)); - } return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); } From c14cc75f943c6ad9ea5f045582e60440073ef5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 00:56:16 +0900 Subject: [PATCH 57/81] =?UTF-8?q?refactor(LoginHandler):=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EB=90=98=EC=97=88=EB=8A=94=EC=A7=80=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/handler/LoginHandler.java | 19 ++-- .../coyote/handler/LoginHandlerTest.java | 107 ++++++++++++++++++ 2 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 55d8873b6e..065374ba34 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -54,21 +54,16 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { final String password = params[1].split("=")[1]; final Optional userOptional = InMemoryUserRepository.findByAccount(account); - if (userOptional.isEmpty()) { + if (userOptional.isEmpty() || !userOptional.get().checkPassword(password)) { return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/401.html", "HTTP/1.1", null, null)); } - final User user = userOptional.get(); - if (user.checkPassword(password)) { - final Session session = new Session(UUID.randomUUID().toString()); - session.setAttribute("user", user); - sessionManager.add(session); - return addCookie( - HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), - new HttpCookie("JSESSIONID=" + session.getId())); - } - - return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/404.html", "HTTP/1.1", null, null)); + final Session session = new Session(UUID.randomUUID().toString()); + session.setAttribute("user", userOptional.get()); + sessionManager.add(session); + return addCookie( + HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), + new HttpCookie("JSESSIONID=" + session.getId())); } private String addCookie(final String response, final HttpCookie cookie) { diff --git a/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java new file mode 100644 index 0000000000..b7c7234c4d --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java @@ -0,0 +1,107 @@ +package org.apache.coyote.handler; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.UUID; + +import org.apache.catalina.session.Session; +import org.apache.catalina.session.SessionManager; +import org.apache.http.HttpHeader; +import org.apache.http.request.HttpRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class LoginHandlerTest { + + private LoginHandler loginHandler; + private SessionManager sessionManager; + + @BeforeEach + void setUp() { + loginHandler = LoginHandler.getInstance(); + sessionManager = SessionManager.getInstance(); + } + + @Test + @DisplayName("GET 요청 처리: 세션이 없는 경우 로그인 페이지를 반환") + void handle_GetRequest_Without_Session() throws IOException { + final HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", null, null); + + final URL resourceURL = getClass().getClassLoader().getResource("static/login.html"); + final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + + assertTrue(loginHandler.handle(request).contains(responseBody)); + } + + @Test + @DisplayName("GET 요청 처리: 세션이 있는 경우 index 페이지로 리다이렉트") + void handle_GetRequest_With_ValidSession() { + final String sessionId = UUID.randomUUID().toString(); + sessionManager.add(new Session(sessionId)); + final HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", + new HttpHeader[]{new HttpHeader("Cookie", "JSESSIONID=" + sessionId)}, null); + + assertTrue(loginHandler.handle(request).contains("302 FOUND")); + + sessionManager.remove(new Session(sessionId)); + } + + @Test + @DisplayName("POST 요청 처리: 유효한 계정 정보로 로그인 성공") + void handle_PostRequest_With_ValidCredentials() { + final HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, + "account=gugu&password=password"); + + final String result = loginHandler.handle(request); + + assertAll( + () -> assertTrue(result.contains("302 FOUND")), + () -> assertTrue(result.contains("http://localhost:8080/index.html")), + () -> assertTrue(result.contains("Set-Cookie: JSESSIONID=")) + ); + assertTrue(result.contains("http://localhost:8080/index.html")); + assertTrue(result.contains("Set-Cookie: JSESSIONID=")); + } + + @Test + @DisplayName("POST 요청 처리: 비밀번호가 올바르지 않는 경우 로그인 실패") + void handle_PostRequest_With_InvalidCredentials() throws IOException { + HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, + "account=gugu&password=wrongpassword"); + + final URL resourceURL = getClass().getClassLoader().getResource("static/401.html"); + final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + + assertThat(loginHandler.handle(request)).contains(responseBody); + } + + @Test + @DisplayName("POST 요청 처리: 존재하지 않는 계정 정보로 로그인 실패") + void handle_PostRequest_WithNonexistentUser() throws IOException { + final HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, + "account=nonexistent&password=anypassword"); + + final URL resourceURL = getClass().getClassLoader().getResource("static/401.html"); + final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + + assertThat(loginHandler.handle(request)).contains(responseBody); + } + + @Test + @DisplayName("지원하지 않는 메소드 처리: 404 페이지 반환") + void handle_UnsupportedMethod() throws IOException { + HttpRequest request = new HttpRequest("PUT", "/login", "HTTP/1.1", null, null); + + final URL resourceURL = getClass().getClassLoader().getResource("static/404.html"); + final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + + assertThat(loginHandler.handle(request)).contains(responseBody); + } +} From 62b2b3fee94e945400f152afa15ba4a3693c1a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 01:05:14 +0900 Subject: [PATCH 58/81] =?UTF-8?q?refactor(RootEndPointHandler):=20?= =?UTF-8?q?=EB=A3=A8=ED=8A=B8=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=9A=94=EC=B2=AD=EC=9D=84=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/handler/Handler.java | 2 +- .../coyote/handler/RootEndPointHandler.java | 21 ++++++++++++++++ .../apache/coyote/http11/Http11Processor.java | 4 ++- .../apache/coyote/mapping/HandlerMapping.java | 3 ++- .../handler/RootEndPointHandlerTest.java | 25 +++++++++++++++++++ 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/RootEndPointHandler.java create mode 100644 tomcat/src/test/java/org/apache/coyote/handler/RootEndPointHandlerTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/handler/Handler.java b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java index c2164f3dbc..6bf20e85b5 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/Handler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/Handler.java @@ -4,5 +4,5 @@ public abstract class Handler { // TODO: 반환타입 HttpResponse로 변경 - abstract String handle(HttpRequest httpRequest); + public abstract String handle(HttpRequest httpRequest); } diff --git a/tomcat/src/main/java/org/apache/coyote/handler/RootEndPointHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/RootEndPointHandler.java new file mode 100644 index 0000000000..eb090dd566 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/RootEndPointHandler.java @@ -0,0 +1,21 @@ +package org.apache.coyote.handler; + +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; + +public class RootEndPointHandler extends Handler{ + private static final RootEndPointHandler INSTANCE = new RootEndPointHandler(); + + private RootEndPointHandler() { + } + + public static RootEndPointHandler getInstance() { + return INSTANCE; + } + + @Override + public String handle(HttpRequest httpRequest) { + final String responseBody = "Hello world!"; + return HttpResponseGenerator.getOkResponse("text/html", responseBody); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 0aa22dd9ee..fc2b0d4a7c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -7,6 +7,7 @@ import java.io.OutputStream; import java.net.Socket; +import org.apache.coyote.handler.Handler; import org.apache.http.request.HttpRequest; import org.apache.http.request.HttpRequestParser; import org.apache.coyote.Processor; @@ -40,7 +41,8 @@ public void process(final Socket connection) { final HttpRequest httpRequest = HttpRequestParser.parseRequest(bufferedReader); final RequestHandlerAdapter requestHandlerAdapter = new RequestHandlerAdapter(); - final String response = requestHandlerAdapter.handle(httpRequest); + final Handler handler = requestHandlerAdapter.getHandler(httpRequest); + final String response = handler.handle(httpRequest); outputStream.write(response.getBytes()); outputStream.flush(); diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java index 8993039de5..b47c2e9ce3 100644 --- a/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java @@ -1,7 +1,8 @@ package org.apache.coyote.mapping; +import org.apache.coyote.handler.Handler; import org.apache.http.request.HttpRequest; public abstract class HandlerMapping { - abstract String mapping(HttpRequest httpRequest); + abstract Handler getHandler(HttpRequest httpRequest); } diff --git a/tomcat/src/test/java/org/apache/coyote/handler/RootEndPointHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/RootEndPointHandlerTest.java new file mode 100644 index 0000000000..6577c9b511 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/handler/RootEndPointHandlerTest.java @@ -0,0 +1,25 @@ +package org.apache.coyote.handler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.http.request.HttpRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RootEndPointHandlerTest { + + @Test + @DisplayName("루트 엔드포인트에 대한 요청 처리: 모든 요청에 대해 동일한 응답 반환") + void handle_OtherHttpMethods() { + final String[] httpMethods = {"PUT", "DELETE", "PATCH", "OPTIONS"}; + + for (String method : httpMethods) { + final HttpRequest request = new HttpRequest(method, "/", "HTTP/1.1", null, null); + + final String result = RootEndPointHandler.getInstance().handle(request); + + assertThat(result).contains("Hello world!"); + } + } + +} From 8ae6cac85c663de72048f7274652b8000ef732d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 01:14:48 +0900 Subject: [PATCH 59/81] =?UTF-8?q?test(RegisterHandlerTest):=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/handler/LoginHandlerTest.java | 34 ++++++------- .../coyote/handler/RegisterHandlerTest.java | 49 +++++++++++++++++++ .../handler/StaticResourceHandlerTest.java | 4 +- 3 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java index b7c7234c4d..9a3a1f011d 100644 --- a/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java @@ -32,12 +32,12 @@ void setUp() { @Test @DisplayName("GET 요청 처리: 세션이 없는 경우 로그인 페이지를 반환") void handle_GetRequest_Without_Session() throws IOException { - final HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", null, null); - final URL resourceURL = getClass().getClassLoader().getResource("static/login.html"); - final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + final String fileContent = Files.readString(Path.of(resourceURL.getPath())); + + final HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", null, null); - assertTrue(loginHandler.handle(request).contains(responseBody)); + assertTrue(loginHandler.handle(request).contains(fileContent)); } @Test @@ -73,35 +73,35 @@ void handle_PostRequest_With_ValidCredentials() { @Test @DisplayName("POST 요청 처리: 비밀번호가 올바르지 않는 경우 로그인 실패") void handle_PostRequest_With_InvalidCredentials() throws IOException { - HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, - "account=gugu&password=wrongpassword"); - final URL resourceURL = getClass().getClassLoader().getResource("static/401.html"); - final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + final String fileContent = Files.readString(Path.of(resourceURL.getPath())); - assertThat(loginHandler.handle(request)).contains(responseBody); + final HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, + "account=gugu&password=wrongpassword"); + + assertThat(loginHandler.handle(request)).contains(fileContent); } @Test @DisplayName("POST 요청 처리: 존재하지 않는 계정 정보로 로그인 실패") void handle_PostRequest_WithNonexistentUser() throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource("static/401.html"); + final String fileContent = Files.readString(Path.of(resourceURL.getPath())); + final HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, "account=nonexistent&password=anypassword"); - final URL resourceURL = getClass().getClassLoader().getResource("static/401.html"); - final String responseBody = Files.readString(Path.of(resourceURL.getPath())); - - assertThat(loginHandler.handle(request)).contains(responseBody); + assertThat(loginHandler.handle(request)).contains(fileContent); } @Test @DisplayName("지원하지 않는 메소드 처리: 404 페이지 반환") void handle_UnsupportedMethod() throws IOException { - HttpRequest request = new HttpRequest("PUT", "/login", "HTTP/1.1", null, null); - final URL resourceURL = getClass().getClassLoader().getResource("static/404.html"); - final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + final String fileContent = Files.readString(Path.of(resourceURL.getPath())); + + final HttpRequest request = new HttpRequest("PUT", "/login", "HTTP/1.1", null, null); - assertThat(loginHandler.handle(request)).contains(responseBody); + assertThat(loginHandler.handle(request)).contains(fileContent); } } diff --git a/tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java new file mode 100644 index 0000000000..cd8fe2e09a --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java @@ -0,0 +1,49 @@ +package org.apache.coyote.handler; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.apache.http.request.HttpRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RegisterHandlerTest { + + private RegisterHandler registerHandler; + + @BeforeEach + void setUp() { + registerHandler = RegisterHandler.getInstance(); + } + + @Test + @DisplayName("GET 요청 처리: 회원가입 페이지 반환") + void handle_GetRequest() throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource("static/register.html"); + final String expectedResponseBody = Files.readString(Path.of(resourceURL.getPath())); + + final HttpRequest request = new HttpRequest("GET", "/register", "HTTP/1.1", null, null); + + assertThat(registerHandler.handle(request)).contains(expectedResponseBody); + } + + @Test + @DisplayName("POST 요청 처리: 유효한 회원가입 정보로 회원가입 성공") + void handle_PostRequest_WithValidRegistration() { + final HttpRequest request = new HttpRequest("POST", "/register", "HTTP/1.1", null, + "account=newuser&email=newuser@example.com&password=password123"); + + final String result = registerHandler.handle(request); + + assertAll( + () -> assertThat(result).contains("302 FOUND"), + () -> assertThat(result).contains("http://localhost:8080/index.html") + ); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java index 802cbcc9b1..315b5b0c84 100644 --- a/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java @@ -31,11 +31,11 @@ void handle() throws IOException { @DisplayName("정적 리소스 처리: 확장자에 따라 다른 경로에 있는 리소스를 반환") void handle_When_Different_Extension_Resource() throws IOException { final URL resourceURL = getClass().getClassLoader().getResource("static/css/styles.css"); - final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + final String fileContent = Files.readString(Path.of(resourceURL.getPath())); final StaticResourceHandler handler = StaticResourceHandler.getInstance(); final String response = handler.handle(new HttpRequest("GET", "styles.css", "HTTP/1.1", null, null)); - assertThat(response).contains(responseBody); + assertThat(response).contains(fileContent); } } From 6027f47b3f40984342403a3d0e631c3e676210b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 01:33:55 +0900 Subject: [PATCH 60/81] =?UTF-8?q?refactor(HandlerMapping):=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=9F=AC=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=97=AD=ED=95=A0=20=EB=B6=80=EC=97=AC=20=EB=B0=8F?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/HandlerMapping.java | 30 +++++++++ .../apache/coyote/RequestHandlerAdapter.java | 32 ---------- .../apache/coyote/http11/Http11Processor.java | 6 +- .../apache/coyote/mapping/HandlerMapping.java | 8 --- .../coyote/mapping/UrlHandlerMapping.java | 32 ---------- .../org/apache/coyote/HandlerMappingTest.java | 63 +++++++++++++++++++ 6 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/HandlerMapping.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java create mode 100644 tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/HandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/HandlerMapping.java new file mode 100644 index 0000000000..92be9cd1c1 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/HandlerMapping.java @@ -0,0 +1,30 @@ +package org.apache.coyote; + +import org.apache.coyote.handler.Handler; +import org.apache.coyote.handler.LoginHandler; +import org.apache.coyote.handler.RegisterHandler; +import org.apache.coyote.handler.RootEndPointHandler; +import org.apache.coyote.handler.StaticResourceHandler; +import org.apache.http.request.HttpRequest; + +public class HandlerMapping { + private static final String PATH_DELIMITER = "/"; + + public Handler getHandler(final HttpRequest httpRequest) { + final String path = httpRequest.getPath(); + + if (path.equals(PATH_DELIMITER)) { + return RootEndPointHandler.getInstance(); + } + + if (path.contains("login")) { + return LoginHandler.getInstance(); + } + + if (path.contains("register")) { + return RegisterHandler.getInstance(); + } + + return StaticResourceHandler.getInstance(); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java b/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java deleted file mode 100644 index 57ae22961e..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandlerAdapter.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.apache.coyote; - -import org.apache.coyote.handler.StaticResourceHandler; -import org.apache.coyote.mapping.UrlHandlerMapping; -import org.apache.http.request.HttpRequest; -import org.apache.http.response.HttpResponseGenerator; - -public class RequestHandlerAdapter { - private static final String PATH_DELIMITER = "/"; - - // TODO: mapping handler method - public String handle(final HttpRequest httpRequest) { - final String path = httpRequest.getPath(); - final String[] paths = path.split(PATH_DELIMITER); - - if (paths.length == 0) { - return handleRoot(); - } - - final String resourceName = paths[paths.length - 1]; - if (resourceName.contains(".")) { - return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "404.html", "HTTP/1.1", null, null)); - } - - return UrlHandlerMapping.getInstance().mapping(httpRequest); - } - - private String handleRoot() { - final String responseBody = "Hello world!"; - return HttpResponseGenerator.getOkResponse("text/html", responseBody); - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index fc2b0d4a7c..6c18caa516 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -11,7 +11,7 @@ import org.apache.http.request.HttpRequest; import org.apache.http.request.HttpRequestParser; import org.apache.coyote.Processor; -import org.apache.coyote.RequestHandlerAdapter; +import org.apache.coyote.HandlerMapping; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,8 +40,8 @@ public void process(final Socket connection) { final OutputStream outputStream = connection.getOutputStream()) { final HttpRequest httpRequest = HttpRequestParser.parseRequest(bufferedReader); - final RequestHandlerAdapter requestHandlerAdapter = new RequestHandlerAdapter(); - final Handler handler = requestHandlerAdapter.getHandler(httpRequest); + final HandlerMapping handlerMapping = new HandlerMapping(); + final Handler handler = handlerMapping.getHandler(httpRequest); final String response = handler.handle(httpRequest); outputStream.write(response.getBytes()); diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java deleted file mode 100644 index b47c2e9ce3..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/mapping/HandlerMapping.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.apache.coyote.mapping; - -import org.apache.coyote.handler.Handler; -import org.apache.http.request.HttpRequest; - -public abstract class HandlerMapping { - abstract Handler getHandler(HttpRequest httpRequest); -} diff --git a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java deleted file mode 100644 index e32addea85..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/mapping/UrlHandlerMapping.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.apache.coyote.mapping; - -import org.apache.coyote.handler.LoginHandler; -import org.apache.coyote.handler.RegisterHandler; -import org.apache.coyote.handler.StaticResourceHandler; -import org.apache.http.request.HttpRequest; - -public class UrlHandlerMapping extends HandlerMapping { - - private static final UrlHandlerMapping INSTANCE = new UrlHandlerMapping(); - - private UrlHandlerMapping() { - } - - public static UrlHandlerMapping getInstance() { - return INSTANCE; - } - - @Override - public String mapping(HttpRequest httpRequest) { - final String uri = httpRequest.getPath(); - if (uri.contains("login")) { - return LoginHandler.getInstance().handle(httpRequest); - } - - if (uri.contains("register")) { - return RegisterHandler.getInstance().handle(httpRequest); - } - - return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/404.html", "HTTP/1.1", null, null)); - } -} diff --git a/tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java b/tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java new file mode 100644 index 0000000000..94c98e24ad --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java @@ -0,0 +1,63 @@ +package org.apache.coyote; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.coyote.handler.Handler; +import org.apache.coyote.handler.LoginHandler; +import org.apache.coyote.handler.RegisterHandler; +import org.apache.coyote.handler.RootEndPointHandler; +import org.apache.coyote.handler.StaticResourceHandler; +import org.apache.http.request.HttpRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class HandlerMappingTest { + + private HandlerMapping requestHandlerMapping; + + @BeforeEach + void setUp() { + requestHandlerMapping = new HandlerMapping(); + } + + @Test + @DisplayName("루트 경로를 포함하는 경로일 경우: RootEndPointHandler 반환") + void getHandler_RootPath_ReturnsRootEndPointHandler() { + HttpRequest request = new HttpRequest("GET", "/", "HTTP/1.1", null, null); + Handler handler = requestHandlerMapping.getHandler(request); + assertThat(handler).isInstanceOf(RootEndPointHandler.class); + } + + @Test + @DisplayName("login을 포함하는 경로일 경우: LoginHandler 반환") + void getHandler_LoginPath_ReturnsLoginHandler() { + HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", null, null); + Handler handler = requestHandlerMapping.getHandler(request); + assertThat(handler).isInstanceOf(LoginHandler.class); + } + + @Test + @DisplayName("register 포함하는 경로일 경우: RegisterHandler를 반환") + void getHandler_RegisterPath_ReturnsRegisterHandler() { + HttpRequest request = new HttpRequest("GET", "/register", "HTTP/1.1", null, null); + Handler handler = requestHandlerMapping.getHandler(request); + assertThat(handler).isInstanceOf(RegisterHandler.class); + } + + @Test + @DisplayName("정적 리소스 경로: StaticResourceHandler 반환") + void getHandler_StaticResourcePath_ReturnsStaticResourceHandler() { + HttpRequest request = new HttpRequest("GET", "/index.html", "HTTP/1.1", null, null); + Handler handler = requestHandlerMapping.getHandler(request); + assertThat(handler).isInstanceOf(StaticResourceHandler.class); + } + + @Test + @DisplayName("알 수 없는 경로: StaticResourceHandler를 반환") + void getHandler_UnknownPath_ReturnsStaticResourceHandler() { + HttpRequest request = new HttpRequest("GET", "/unknown/path", "HTTP/1.1", null, null); + Handler handler = requestHandlerMapping.getHandler(request); + assertThat(handler).isInstanceOf(StaticResourceHandler.class); + } +} From 0f88784983bd3fe26b8d6e2fcf2e13e971ee44da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 01:35:13 +0900 Subject: [PATCH 61/81] =?UTF-8?q?feat(SessionManager):=20=ED=8A=B9?= =?UTF-8?q?=EC=A0=95=20=EC=95=84=EC=9D=B4=EB=94=94=EC=9D=B8=20=EC=84=B8?= =?UTF-8?q?=EC=85=98=EC=9D=B4=20=EC=A1=B4=EC=9E=AC=ED=95=98=EB=8A=94?= =?UTF-8?q?=EC=A7=80=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/catalina/session/SessionManager.java | 4 ++++ .../org/apache/catalina/SessionManagerTest.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java index 168055c1bb..0f4423a4d9 100644 --- a/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java @@ -13,6 +13,10 @@ public static SessionManager getInstance() { return INSTANCE; } + public boolean existsById(final String id) { + return SESSIONS.containsKey(id); + } + @Override public void add(Session session) { SESSIONS.put(session.getId(), session); diff --git a/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java b/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java index c17ca4481d..f2c97edfc7 100644 --- a/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java +++ b/tomcat/src/test/java/org/apache/catalina/SessionManagerTest.java @@ -12,6 +12,20 @@ class SessionManagerTest { private final SessionManager sessionManager = SessionManager.getInstance(); + @Test + @DisplayName("세션 존재 여부 확인 성공") + void existsById() { + // given + String sessionId = "1"; + Session session = new Session(sessionId); + sessionManager.add(session); + + assertThat(sessionManager.existsById(sessionId)).isTrue(); + + // after + sessionManager.remove(session); + } + @Test @DisplayName("세션 추가 성공") void add() { From 7ed734e51d43f21e90826e7531707cabf414c6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 01:50:56 +0900 Subject: [PATCH 62/81] =?UTF-8?q?refactor(HttpCookie):=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=EC=99=80=20=EC=9D=B8=EC=9E=90=EA=B0=80=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EC=83=9D=EC=84=B1=EC=9E=90=EB=A5=BC=20=EC=A0=95?= =?UTF-8?q?=ED=8C=A9=EB=A9=94=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/handler/LoginHandler.java | 6 ++-- .../main/java/org/apache/http/HttpCookie.java | 33 ++++++++++--------- .../java/org/apache/http/HttpHeaderName.java | 2 ++ .../org/apache/http/request/HttpRequest.java | 25 ++++---------- 4 files changed, 29 insertions(+), 37 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/http/HttpHeaderName.java diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 065374ba34..2b7e72f302 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -63,10 +63,12 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { sessionManager.add(session); return addCookie( HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), - new HttpCookie("JSESSIONID=" + session.getId())); + HttpCookie.of("JSESSIONID=" + session.getId())); } private String addCookie(final String response, final HttpCookie cookie) { - return response.concat("\n").concat("Set-Cookie: " + cookie.toString()); + return response + .concat("\n") + .concat("Set-Cookie: " + cookie.toString()); } } diff --git a/tomcat/src/main/java/org/apache/http/HttpCookie.java b/tomcat/src/main/java/org/apache/http/HttpCookie.java index 4f80dab514..6d892ac580 100644 --- a/tomcat/src/main/java/org/apache/http/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/http/HttpCookie.java @@ -1,43 +1,44 @@ package org.apache.http; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; public class HttpCookie { + private static final String COOKIE_SEPARATOR = "; "; + private static final String KEY_VALUE_SEPARATOR = "="; + public final Map cookie; public HttpCookie(Map cookie) { this.cookie = cookie; } - public HttpCookie(String cookie) { - this.cookie = parseCookie(cookie); - } - - public String getValue(String key) { - return cookie.get(key); + public static HttpCookie of(String cookie) { + return new HttpCookie(parseCookie(cookie)); } - public static Map parseCookie(String cookie) { - String[] cookiePairs = cookie.split("; "); + private static Map parseCookie(String cookie) { + String[] cookiePairs = cookie.split(COOKIE_SEPARATOR); Map cookies = new HashMap<>(); - Arrays.stream(cookiePairs) - .forEach(pair -> { - String[] keyAndValue = pair.split("="); - cookies.put(keyAndValue[0], keyAndValue[1]); - }); + for (String pair : cookiePairs) { + String[] keyAndValue = pair.split(KEY_VALUE_SEPARATOR); + cookies.put(keyAndValue[0], keyAndValue[1]); + } return cookies; } + public String getValue(String key) { + return cookie.get(key); + } + @Override public String toString() { return cookie.entrySet() .stream() - .map(entry -> entry.getKey() + "=" + entry.getValue()) - .collect(Collectors.joining("; ")); + .map(entry -> entry.getKey() + KEY_VALUE_SEPARATOR + entry.getValue()) + .collect(Collectors.joining(COOKIE_SEPARATOR)); } } diff --git a/tomcat/src/main/java/org/apache/http/HttpHeaderName.java b/tomcat/src/main/java/org/apache/http/HttpHeaderName.java new file mode 100644 index 0000000000..085a63a90e --- /dev/null +++ b/tomcat/src/main/java/org/apache/http/HttpHeaderName.java @@ -0,0 +1,2 @@ +package org.apache.http;public enum HttpHeaderName { +} diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java index a07cdad966..d17ffaa8f4 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java @@ -1,6 +1,7 @@ package org.apache.http.request; import java.util.Arrays; +import java.util.Optional; import org.apache.http.HttpCookie; import org.apache.http.HttpHeader; @@ -8,7 +9,6 @@ public class HttpRequest { private final HttpMethod method; - private final String url; private final String path; private final String version; private final HttpHeader[] headers; @@ -20,25 +20,16 @@ public HttpRequest(String method, String path, String version, HttpHeader[] head this.path = path; this.version = version; this.headers = headers; - this.url = parseUrl(path); this.body = body; this.httpCookie = parseCookie(headers); } - private String parseUrl(final String path) { - HttpHeader hostHeader = Arrays.stream(headers) - .filter(header -> header.getKey().equalsIgnoreCase("host")) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Host 헤더가 존재하지 않습니다.")); - - return hostHeader.getValue() + path; - } - private HttpCookie parseCookie(HttpHeader[] headers) { - return Arrays.stream(headers) - .filter(header -> header.getKey().equalsIgnoreCase("Cookie")) - .findFirst() - .map(header -> new HttpCookie(header.getValue())) + return Optional.ofNullable(headers) + .flatMap(hs -> Arrays.stream(hs) + .filter(header -> header.getKey().equalsIgnoreCase("Cookie")) + .findFirst() + .map(header -> HttpCookie.of(header.getValue()))) .orElse(null); } @@ -50,10 +41,6 @@ public HttpMethod getMethod() { return method; } - public String getUrl() { - return url; - } - public String getPath() { return path; } From f5efceb960ef43c594b099f7f8571408c093b083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 01:57:15 +0900 Subject: [PATCH 63/81] =?UTF-8?q?test(HttpCookie):=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1=20=EB=B0=8F=20=ED=95=84=EB=93=9C?= =?UTF-8?q?=EB=A5=BC=20private=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/http/HttpCookie.java | 2 +- .../java/org/apache/http/HttpCookieTest.java | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tomcat/src/test/java/org/apache/http/HttpCookieTest.java diff --git a/tomcat/src/main/java/org/apache/http/HttpCookie.java b/tomcat/src/main/java/org/apache/http/HttpCookie.java index 6d892ac580..783ca2fbfc 100644 --- a/tomcat/src/main/java/org/apache/http/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/http/HttpCookie.java @@ -8,7 +8,7 @@ public class HttpCookie { private static final String COOKIE_SEPARATOR = "; "; private static final String KEY_VALUE_SEPARATOR = "="; - public final Map cookie; + private final Map cookie; public HttpCookie(Map cookie) { this.cookie = cookie; diff --git a/tomcat/src/test/java/org/apache/http/HttpCookieTest.java b/tomcat/src/test/java/org/apache/http/HttpCookieTest.java new file mode 100644 index 0000000000..b3ef3e4be6 --- /dev/null +++ b/tomcat/src/test/java/org/apache/http/HttpCookieTest.java @@ -0,0 +1,34 @@ +package org.apache.http; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class HttpCookieTest { + + @Test + @DisplayName("HttpCookie 생성: 문자열로부터 파싱") + void of() { + String cookieString = "name=value; session=12345"; + HttpCookie httpCookie = HttpCookie.of(cookieString); + + assertEquals("value", httpCookie.getValue("name")); + assertEquals("12345", httpCookie.getValue("session")); + } + + @Test + @DisplayName("특정 key에 대한 value 조회: 존재하지 않는 키일 경우 null 반환") + void getValue_For_NonexistentKey() { + HttpCookie httpCookie = HttpCookie.of("name=value"); + assertNull(httpCookie.getValue("nonexistent")); + } + + @Test + @DisplayName("특정 key에 대한 value 조회: 존재하지 않는 키일 경우 null 반환") + void testGetValueForNonexistentKey() { + HttpCookie httpCookie = HttpCookie.of("name=value"); + assertEquals("value", httpCookie.getValue("name")); + } +} From 6b297dbccab00d8026171974e29b5a1f97b12317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 02:00:39 +0900 Subject: [PATCH 64/81] =?UTF-8?q?refactor(HttpRequestReader):=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=B1=85=EC=9E=84=EC=97=90=20=EB=A7=A1=EA=B2=8C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http11/Http11Processor.java | 4 ++-- ...tpRequestParser.java => HttpRequestReader.java} | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) rename tomcat/src/main/java/org/apache/http/request/{HttpRequestParser.java => HttpRequestReader.java} (70%) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 6c18caa516..48daf140c5 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -9,7 +9,7 @@ import org.apache.coyote.handler.Handler; import org.apache.http.request.HttpRequest; -import org.apache.http.request.HttpRequestParser; +import org.apache.http.request.HttpRequestReader; import org.apache.coyote.Processor; import org.apache.coyote.HandlerMapping; import org.slf4j.Logger; @@ -39,7 +39,7 @@ public void process(final Socket connection) { final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); final OutputStream outputStream = connection.getOutputStream()) { - final HttpRequest httpRequest = HttpRequestParser.parseRequest(bufferedReader); + final HttpRequest httpRequest = HttpRequestReader.readHttpRequest(bufferedReader); final HandlerMapping handlerMapping = new HandlerMapping(); final Handler handler = handlerMapping.getHandler(httpRequest); final String response = handler.handle(httpRequest); diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java similarity index 70% rename from tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java rename to tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java index 326916e775..f5f367ae6e 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java @@ -9,12 +9,12 @@ import org.apache.http.HttpHeader; -public class HttpRequestParser { +public class HttpRequestReader { - private HttpRequestParser() { + private HttpRequestReader() { } - public static HttpRequest parseRequest(final BufferedReader bufferedReader) throws IOException { + public static HttpRequest readHttpRequest(final BufferedReader bufferedReader) throws IOException { final String request = bufferedReader.readLine(); final String[] requestStartLine = request.split(" "); @@ -22,11 +22,11 @@ public static HttpRequest parseRequest(final BufferedReader bufferedReader) thro final String path = requestStartLine[1]; final String version = requestStartLine[2]; - final HttpHeader[] headers = parseRequestHeaders(bufferedReader); - return new HttpRequest(method, path, version, headers, parseRequestBody(headers, bufferedReader)); + final HttpHeader[] headers = readRequestHeaders(bufferedReader); + return new HttpRequest(method, path, version, headers, readRequestBody(headers, bufferedReader)); } - private static HttpHeader[] parseRequestHeaders(final BufferedReader bufferedReader) throws IOException { + private static HttpHeader[] readRequestHeaders(final BufferedReader bufferedReader) throws IOException { String header = bufferedReader.readLine(); final List headers = new ArrayList<>(); @@ -39,7 +39,7 @@ private static HttpHeader[] parseRequestHeaders(final BufferedReader bufferedRea return headers.toArray(HttpHeader[]::new); } - private static String parseRequestBody(final HttpHeader[] headers, final BufferedReader bufferedReader) throws IOException { + private static String readRequestBody(final HttpHeader[] headers, final BufferedReader bufferedReader) throws IOException { Optional httpHeader = Arrays.stream(headers) .filter(header -> header.getKey().equalsIgnoreCase("Content-Length")) .findFirst(); From 7e936f48a87a05cf807c08bb3ad31b5c0fcf6d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 02:12:41 +0900 Subject: [PATCH 65/81] =?UTF-8?q?refactor(StandardHttpHeader):=20HTTP=20?= =?UTF-8?q?=EC=9D=BC=EB=B0=98=EC=A0=81=EC=9D=B8=20=ED=97=A4=EB=8D=94?= =?UTF-8?q?=EB=A5=BC=20=EB=82=98=ED=83=80=EB=82=B4=EB=8A=94=20=EC=9D=B4?= =?UTF-8?q?=EB=84=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/handler/LoginHandler.java | 3 +- .../java/org/apache/http/HttpHeaderName.java | 2 -- .../org/apache/http/StandardHttpHeader.java | 30 +++++++++++++++++++ .../http/request/HttpRequestReader.java | 3 +- .../apache/http/StandardHttpHeaderTest.java | 18 +++++++++++ 5 files changed, 52 insertions(+), 4 deletions(-) delete mode 100644 tomcat/src/main/java/org/apache/http/HttpHeaderName.java create mode 100644 tomcat/src/main/java/org/apache/http/StandardHttpHeader.java create mode 100644 tomcat/src/test/java/org/apache/http/StandardHttpHeaderTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 2b7e72f302..a0bde83c21 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -7,6 +7,7 @@ import org.apache.http.HttpCookie; import org.apache.http.HttpMethod; import org.apache.catalina.session.Session; +import org.apache.http.StandardHttpHeader; import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; @@ -69,6 +70,6 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { private String addCookie(final String response, final HttpCookie cookie) { return response .concat("\n") - .concat("Set-Cookie: " + cookie.toString()); + .concat(StandardHttpHeader.SET_COOKIE.getValue() + ": " + cookie.toString()); } } diff --git a/tomcat/src/main/java/org/apache/http/HttpHeaderName.java b/tomcat/src/main/java/org/apache/http/HttpHeaderName.java deleted file mode 100644 index 085a63a90e..0000000000 --- a/tomcat/src/main/java/org/apache/http/HttpHeaderName.java +++ /dev/null @@ -1,2 +0,0 @@ -package org.apache.http;public enum HttpHeaderName { -} diff --git a/tomcat/src/main/java/org/apache/http/StandardHttpHeader.java b/tomcat/src/main/java/org/apache/http/StandardHttpHeader.java new file mode 100644 index 0000000000..c194217e6b --- /dev/null +++ b/tomcat/src/main/java/org/apache/http/StandardHttpHeader.java @@ -0,0 +1,30 @@ +package org.apache.http; + +public enum StandardHttpHeader { + ACCEPT("Accept"), + ACCEPT_RANGES("Accept-Ranges"), + AUTHORIZATION("Authorization"), + CONNECTION("Connection"), + CONTENT_LENGTH("Content-Length"), + CONTENT_TYPE("Content-Type"), + COOKIE("Cookie"), + HOST("Host"), + LOCATION("Location"), + ORIGIN("Origin"), + SET_COOKIE("Set-Cookie"), + ; + + private final String value; + + StandardHttpHeader(String value) { + this.value = value; + } + + public boolean equalsIgnoreCase(String value) { + return this.value.equalsIgnoreCase(value); + } + + public String getValue() { + return value; + } +} diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java b/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java index f5f367ae6e..c37bd9eb4c 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java @@ -8,6 +8,7 @@ import java.util.Optional; import org.apache.http.HttpHeader; +import org.apache.http.StandardHttpHeader; public class HttpRequestReader { @@ -41,7 +42,7 @@ private static HttpHeader[] readRequestHeaders(final BufferedReader bufferedRead private static String readRequestBody(final HttpHeader[] headers, final BufferedReader bufferedReader) throws IOException { Optional httpHeader = Arrays.stream(headers) - .filter(header -> header.getKey().equalsIgnoreCase("Content-Length")) + .filter(header -> StandardHttpHeader.CONTENT_LENGTH.equalsIgnoreCase(header.getKey())) .findFirst(); if (httpHeader.isEmpty()) { diff --git a/tomcat/src/test/java/org/apache/http/StandardHttpHeaderTest.java b/tomcat/src/test/java/org/apache/http/StandardHttpHeaderTest.java new file mode 100644 index 0000000000..7c10a6d5c6 --- /dev/null +++ b/tomcat/src/test/java/org/apache/http/StandardHttpHeaderTest.java @@ -0,0 +1,18 @@ +package org.apache.http; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class StandardHttpHeaderTest { + + @Test + void equalsIgnoreCase() { + assertAll( + () -> assertTrue(StandardHttpHeader.COOKIE.equalsIgnoreCase("cookie")), + () -> assertTrue(StandardHttpHeader.COOKIE.equalsIgnoreCase("Cookie")), + () -> assertTrue(StandardHttpHeader.COOKIE.equalsIgnoreCase("COOKIE")) + ); + } +} From 7c4a23c859f1ac2ea76bbaf216680dda24731735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 02:17:18 +0900 Subject: [PATCH 66/81] =?UTF-8?q?refactor(/header):=20header=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/handler/LoginHandler.java | 2 +- .../main/java/org/apache/http/{ => header}/HttpHeader.java | 2 +- .../java/org/apache/http/{ => header}/StandardHttpHeader.java | 2 +- tomcat/src/main/java/org/apache/http/request/HttpRequest.java | 2 +- .../main/java/org/apache/http/request/HttpRequestReader.java | 4 ++-- .../test/java/org/apache/coyote/handler/LoginHandlerTest.java | 2 +- .../org/apache/http/{ => header}/StandardHttpHeaderTest.java | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) rename tomcat/src/main/java/org/apache/http/{ => header}/HttpHeader.java (92%) rename tomcat/src/main/java/org/apache/http/{ => header}/StandardHttpHeader.java (95%) rename tomcat/src/test/java/org/apache/http/{ => header}/StandardHttpHeaderTest.java (94%) diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index a0bde83c21..140ef700a3 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -7,7 +7,7 @@ import org.apache.http.HttpCookie; import org.apache.http.HttpMethod; import org.apache.catalina.session.Session; -import org.apache.http.StandardHttpHeader; +import org.apache.http.header.StandardHttpHeader; import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; diff --git a/tomcat/src/main/java/org/apache/http/HttpHeader.java b/tomcat/src/main/java/org/apache/http/header/HttpHeader.java similarity index 92% rename from tomcat/src/main/java/org/apache/http/HttpHeader.java rename to tomcat/src/main/java/org/apache/http/header/HttpHeader.java index d0f0f88e7d..b8d03c30aa 100644 --- a/tomcat/src/main/java/org/apache/http/HttpHeader.java +++ b/tomcat/src/main/java/org/apache/http/header/HttpHeader.java @@ -1,4 +1,4 @@ -package org.apache.http; +package org.apache.http.header; public class HttpHeader { private final String key; diff --git a/tomcat/src/main/java/org/apache/http/StandardHttpHeader.java b/tomcat/src/main/java/org/apache/http/header/StandardHttpHeader.java similarity index 95% rename from tomcat/src/main/java/org/apache/http/StandardHttpHeader.java rename to tomcat/src/main/java/org/apache/http/header/StandardHttpHeader.java index c194217e6b..8bfb023192 100644 --- a/tomcat/src/main/java/org/apache/http/StandardHttpHeader.java +++ b/tomcat/src/main/java/org/apache/http/header/StandardHttpHeader.java @@ -1,4 +1,4 @@ -package org.apache.http; +package org.apache.http.header; public enum StandardHttpHeader { ACCEPT("Accept"), diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java index d17ffaa8f4..4e3c64d3d4 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java @@ -4,7 +4,7 @@ import java.util.Optional; import org.apache.http.HttpCookie; -import org.apache.http.HttpHeader; +import org.apache.http.header.HttpHeader; import org.apache.http.HttpMethod; public class HttpRequest { diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java b/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java index c37bd9eb4c..58f0e29d0f 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequestReader.java @@ -7,8 +7,8 @@ import java.util.List; import java.util.Optional; -import org.apache.http.HttpHeader; -import org.apache.http.StandardHttpHeader; +import org.apache.http.header.HttpHeader; +import org.apache.http.header.StandardHttpHeader; public class HttpRequestReader { diff --git a/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java index 9a3a1f011d..1af5788add 100644 --- a/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java @@ -12,7 +12,7 @@ import org.apache.catalina.session.Session; import org.apache.catalina.session.SessionManager; -import org.apache.http.HttpHeader; +import org.apache.http.header.HttpHeader; import org.apache.http.request.HttpRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/tomcat/src/test/java/org/apache/http/StandardHttpHeaderTest.java b/tomcat/src/test/java/org/apache/http/header/StandardHttpHeaderTest.java similarity index 94% rename from tomcat/src/test/java/org/apache/http/StandardHttpHeaderTest.java rename to tomcat/src/test/java/org/apache/http/header/StandardHttpHeaderTest.java index 7c10a6d5c6..6c5e9fa15c 100644 --- a/tomcat/src/test/java/org/apache/http/StandardHttpHeaderTest.java +++ b/tomcat/src/test/java/org/apache/http/header/StandardHttpHeaderTest.java @@ -1,4 +1,4 @@ -package org.apache.http; +package org.apache.http.header; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertTrue; From e347bdf9144596bb45dfb7e9e61c8dc65058e0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 15:14:57 +0900 Subject: [PATCH 67/81] =?UTF-8?q?refactor(StaticResourceHandler):=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5=EC=9E=90=EA=B0=80=20=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20/static=20=EA=B2=BD=EB=A1=9C=EC=97=90=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20html=20=EB=A6=AC=EC=86=8C=EC=8A=A4?= =?UTF-8?q?=EB=A5=BC=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/UnauthorizedException.java | 7 +++++++ .../coyote/handler/StaticResourceHandler.java | 14 ++++++++++---- .../coyote/handler/StaticResourceHandlerTest.java | 12 ++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/UnauthorizedException.java diff --git a/tomcat/src/main/java/org/apache/coyote/UnauthorizedException.java b/tomcat/src/main/java/org/apache/coyote/UnauthorizedException.java new file mode 100644 index 0000000000..d051227157 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/UnauthorizedException.java @@ -0,0 +1,7 @@ +package org.apache.coyote; + +public class UnauthorizedException extends RuntimeException { + public UnauthorizedException(String message) { + super(message); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java index dd7886fcd1..b5f74c14d6 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java @@ -6,6 +6,7 @@ import java.nio.file.Path; import java.util.Map; +import org.apache.coyote.NotFoundException; import org.apache.http.request.HttpRequest; import org.apache.http.response.HttpResponseGenerator; @@ -16,6 +17,7 @@ public class StaticResourceHandler extends Handler { "js", "assets" ); private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; + private static final String DEFAULT_EXTENSION = ".html"; private static final String PATH_DELIMITER = "/"; private static final StaticResourceHandler INSTANCE = new StaticResourceHandler(); @@ -29,19 +31,21 @@ public static StaticResourceHandler getInstance() { public String handle(final HttpRequest httpRequest) { final URL resourceURL = getClass().getClassLoader().getResource(findResourcePath(httpRequest.getPath())); - final Path resourcePath = Path.of(resourceURL.getPath()); try { + final Path resourcePath = Path.of(resourceURL.getPath()); final String responseBody = Files.readString(resourcePath); final String mimeType = Files.probeContentType(resourcePath); return HttpResponseGenerator.getOkResponse(mimeType, responseBody); + } catch (NullPointerException e) { + throw new NotFoundException(e.getMessage()); } catch (IOException e) { - return HttpResponseGenerator.getFoundResponse("404.html"); + throw new RuntimeException(e); } } private String findResourcePath(final String path) { final String[] resourceNames = findResourceName(path).split("\\."); - final String extension = resourceNames[1]; + final String extension = resourceNames[resourceNames.length - 1]; if (STATIC_RESOURCE_EXTENSIONS.containsKey(extension)) { return STATIC_RESOURCE_ROOT_PATH @@ -50,7 +54,9 @@ private String findResourcePath(final String path) { .concat(path); } - return STATIC_RESOURCE_ROOT_PATH.concat(path); + return STATIC_RESOURCE_ROOT_PATH + .concat(path) + .concat(DEFAULT_EXTENSION); } private String findResourceName(final String path) { diff --git a/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java index 315b5b0c84..9b662fb3db 100644 --- a/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java @@ -38,4 +38,16 @@ void handle_When_Different_Extension_Resource() throws IOException { assertThat(response).contains(fileContent); } + + @Test + @DisplayName("정적 리소스 처리: 확장자가 없는 경우, /static 경로에 있는 html 리소스를 반환") + void handle_When_Extension_NotExist() throws IOException { + final URL resourceURL = getClass().getClassLoader().getResource("static/404.html"); + final String responseBody = Files.readString(Path.of(resourceURL.getPath())); + + final StaticResourceHandler handler = StaticResourceHandler.getInstance(); + final String response = handler.handle(new HttpRequest("GET", "404", "HTTP/1.1", null, null)); + + assertThat(response).contains(responseBody); + } } From 8e1dcff15a38db38787390a397a39da5061f6644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:01:01 +0900 Subject: [PATCH 68/81] =?UTF-8?q?refactor(NotFoundHandler):=20NotFoundExce?= =?UTF-8?q?ption=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=9F=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/NotFoundException.java | 7 +++++++ .../handler/exception/NotFoundHandler.java | 21 +++++++++++++++++++ .../exception/NotFoundHandlerTest.java | 19 +++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/NotFoundException.java create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/exception/NotFoundHandler.java create mode 100644 tomcat/src/test/java/org/apache/coyote/handler/exception/NotFoundHandlerTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/NotFoundException.java b/tomcat/src/main/java/org/apache/coyote/NotFoundException.java new file mode 100644 index 0000000000..ac525ef6fb --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/NotFoundException.java @@ -0,0 +1,7 @@ +package org.apache.coyote; + +public class NotFoundException extends RuntimeException { + public NotFoundException(String message) { + super(message); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/handler/exception/NotFoundHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/exception/NotFoundHandler.java new file mode 100644 index 0000000000..9370faf633 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/exception/NotFoundHandler.java @@ -0,0 +1,21 @@ +package org.apache.coyote.handler.exception; + +import org.apache.coyote.handler.Handler; +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; + +public class NotFoundHandler extends Handler { + private static final NotFoundHandler INSTANCE = new NotFoundHandler(); + + private NotFoundHandler() { + } + + public static NotFoundHandler getInstance() { + return INSTANCE; + } + + @Override + public String handle(final HttpRequest httpRequest) { + return HttpResponseGenerator.getNotFountResponse(); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/handler/exception/NotFoundHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/exception/NotFoundHandlerTest.java new file mode 100644 index 0000000000..e1f49725f3 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/handler/exception/NotFoundHandlerTest.java @@ -0,0 +1,19 @@ +package org.apache.coyote.handler.exception; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class NotFoundHandlerTest { + + @Test + @DisplayName("모든 요청 처리: 404 응답 반환") + void handle() { + HttpRequest httpRequest = new HttpRequest("GET", null, null, null, null); + assertThat(NotFoundHandler.getInstance().handle(httpRequest)).isEqualTo(HttpResponseGenerator.getNotFountResponse()); + } +} From 5b2f99f5c872074fbfebdcdf56519c08b89c7ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:03:11 +0900 Subject: [PATCH 69/81] =?UTF-8?q?refactor(UnAuthorizationHandler):=20UnAut?= =?UTF-8?q?horization=20=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=95=B8?= =?UTF-8?q?=EB=93=A4=EB=9F=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/UnAuthorizationHandler.java | 21 +++++++++++++++++++ .../exception/UnAuthorizationHandlerTest.java | 18 ++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/exception/UnAuthorizationHandler.java create mode 100644 tomcat/src/test/java/org/apache/coyote/handler/exception/UnAuthorizationHandlerTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/handler/exception/UnAuthorizationHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/exception/UnAuthorizationHandler.java new file mode 100644 index 0000000000..061c1c9432 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/exception/UnAuthorizationHandler.java @@ -0,0 +1,21 @@ +package org.apache.coyote.handler.exception; + +import org.apache.coyote.handler.Handler; +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; + +public class UnAuthorizationHandler extends Handler { + private static final UnAuthorizationHandler INSTANCE = new UnAuthorizationHandler(); + + private UnAuthorizationHandler() { + } + + public static UnAuthorizationHandler getInstance() { + return INSTANCE; + } + + @Override + public String handle(final HttpRequest httpRequest) { + return HttpResponseGenerator.getUnauthorizedResponse(); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/handler/exception/UnAuthorizationHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/exception/UnAuthorizationHandlerTest.java new file mode 100644 index 0000000000..0b57bd5222 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/handler/exception/UnAuthorizationHandlerTest.java @@ -0,0 +1,18 @@ +package org.apache.coyote.handler.exception; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class UnAuthorizationHandlerTest { + + @Test + @DisplayName("모든 요청 처리: 401 응답 반환") + void handle() { + HttpRequest httpRequest = new HttpRequest("GET", null, null, null, null); + assertThat(UnAuthorizationHandler.getInstance().handle(httpRequest)).isEqualTo(HttpResponseGenerator.getUnauthorizedResponse()); + } +} From bf65e8edd606c5d65ad1940a8a4190a6c33c48e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:06:00 +0900 Subject: [PATCH 70/81] =?UTF-8?q?refactor(/test):=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EB=90=9C=20=EC=9D=91=EB=8B=B5=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EA=B7=9C=EA=B2=A9=EC=97=90=20=EB=A7=9E=EA=B2=8C=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EA=B0=92=20=ED=98=95=EC=8B=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/response/HttpResponseGenerator.java | 20 ++++++++++++- .../coyote/handler/LoginHandlerTest.java | 28 ++++++------------- .../coyote/handler/RegisterHandlerTest.java | 14 ++-------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java index 5bc9cc61f9..2abe115a15 100644 --- a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java +++ b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java @@ -2,6 +2,9 @@ public class HttpResponseGenerator { + private HttpResponseGenerator() { + } + public static String getOkResponse(String mimeType, String responseBody) { return String.join("\r\n", "HTTP/1.1 200 OK ", @@ -13,7 +16,22 @@ public static String getOkResponse(String mimeType, String responseBody) { public static String getFoundResponse(String url) { return String.join("\r\n", - "HTTP/1.1 302 FOUND ", + "HTTP/1.1 302 Found ", "Location: " + url); } + + public static String getNotFountResponse() { + return String.join("\r\n", + "HTTP/1.1 404 Not Found "); + } + + public static String getUnauthorizedResponse() { + return String.join("\r\n", + "HTTP/1.1 401 Unauthorized "); + } + + public static String getInternalServerErrorResponse() { + return String.join("\r\n", + "HTTP/1.1 401 Internal Server Error "); + } } diff --git a/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java index 1af5788add..326d1ac432 100644 --- a/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/handler/LoginHandlerTest.java @@ -14,21 +14,11 @@ import org.apache.catalina.session.SessionManager; import org.apache.http.header.HttpHeader; import org.apache.http.request.HttpRequest; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class LoginHandlerTest { - private LoginHandler loginHandler; - private SessionManager sessionManager; - - @BeforeEach - void setUp() { - loginHandler = LoginHandler.getInstance(); - sessionManager = SessionManager.getInstance(); - } - @Test @DisplayName("GET 요청 처리: 세션이 없는 경우 로그인 페이지를 반환") void handle_GetRequest_Without_Session() throws IOException { @@ -37,20 +27,20 @@ void handle_GetRequest_Without_Session() throws IOException { final HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", null, null); - assertTrue(loginHandler.handle(request).contains(fileContent)); + assertTrue(LoginHandler.getInstance().handle(request).contains(fileContent)); } @Test @DisplayName("GET 요청 처리: 세션이 있는 경우 index 페이지로 리다이렉트") void handle_GetRequest_With_ValidSession() { final String sessionId = UUID.randomUUID().toString(); - sessionManager.add(new Session(sessionId)); + SessionManager.getInstance().add(new Session(sessionId)); final HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", new HttpHeader[]{new HttpHeader("Cookie", "JSESSIONID=" + sessionId)}, null); - assertTrue(loginHandler.handle(request).contains("302 FOUND")); + assertTrue(LoginHandler.getInstance().handle(request).contains("302 Found")); - sessionManager.remove(new Session(sessionId)); + SessionManager.getInstance().remove(new Session(sessionId)); } @Test @@ -59,10 +49,10 @@ void handle_PostRequest_With_ValidCredentials() { final HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, "account=gugu&password=password"); - final String result = loginHandler.handle(request); + final String result = LoginHandler.getInstance().handle(request); assertAll( - () -> assertTrue(result.contains("302 FOUND")), + () -> assertTrue(result.contains("302 Found")), () -> assertTrue(result.contains("http://localhost:8080/index.html")), () -> assertTrue(result.contains("Set-Cookie: JSESSIONID=")) ); @@ -79,7 +69,7 @@ void handle_PostRequest_With_InvalidCredentials() throws IOException { final HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, "account=gugu&password=wrongpassword"); - assertThat(loginHandler.handle(request)).contains(fileContent); + assertThat(LoginHandler.getInstance().handle(request)).contains(fileContent); } @Test @@ -91,7 +81,7 @@ void handle_PostRequest_WithNonexistentUser() throws IOException { final HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, "account=nonexistent&password=anypassword"); - assertThat(loginHandler.handle(request)).contains(fileContent); + assertThat(LoginHandler.getInstance().handle(request)).contains(fileContent); } @Test @@ -102,6 +92,6 @@ void handle_UnsupportedMethod() throws IOException { final HttpRequest request = new HttpRequest("PUT", "/login", "HTTP/1.1", null, null); - assertThat(loginHandler.handle(request)).contains(fileContent); + assertThat(LoginHandler.getInstance().handle(request)).contains(fileContent); } } diff --git a/tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java index cd8fe2e09a..c81118e85a 100644 --- a/tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/handler/RegisterHandlerTest.java @@ -9,19 +9,11 @@ import java.nio.file.Path; import org.apache.http.request.HttpRequest; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class RegisterHandlerTest { - private RegisterHandler registerHandler; - - @BeforeEach - void setUp() { - registerHandler = RegisterHandler.getInstance(); - } - @Test @DisplayName("GET 요청 처리: 회원가입 페이지 반환") void handle_GetRequest() throws IOException { @@ -30,7 +22,7 @@ void handle_GetRequest() throws IOException { final HttpRequest request = new HttpRequest("GET", "/register", "HTTP/1.1", null, null); - assertThat(registerHandler.handle(request)).contains(expectedResponseBody); + assertThat(RegisterHandler.getInstance().handle(request)).contains(expectedResponseBody); } @Test @@ -39,10 +31,10 @@ void handle_PostRequest_WithValidRegistration() { final HttpRequest request = new HttpRequest("POST", "/register", "HTTP/1.1", null, "account=newuser&email=newuser@example.com&password=password123"); - final String result = registerHandler.handle(request); + final String result = RegisterHandler.getInstance().handle(request); assertAll( - () -> assertThat(result).contains("302 FOUND"), + () -> assertThat(result).contains("302 Found"), () -> assertThat(result).contains("http://localhost:8080/index.html") ); } From 9b91b4bcf8c84923954926b22a23ffa6fd9913f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:06:25 +0900 Subject: [PATCH 71/81] =?UTF-8?q?refactor(InternalServerErrorHandler):=20?= =?UTF-8?q?=EC=B5=9C=EC=83=81=EC=9C=84=20Exception=20=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/InternalServerErrorHandler.java | 22 +++++++++++++++++++ .../InternalServerErrorHandlerTest.java | 18 +++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/handler/exception/InternalServerErrorHandler.java create mode 100644 tomcat/src/test/java/org/apache/coyote/handler/exception/InternalServerErrorHandlerTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/handler/exception/InternalServerErrorHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/exception/InternalServerErrorHandler.java new file mode 100644 index 0000000000..8997726f74 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/handler/exception/InternalServerErrorHandler.java @@ -0,0 +1,22 @@ +package org.apache.coyote.handler.exception; + +import org.apache.coyote.handler.Handler; +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; + +public class InternalServerErrorHandler extends Handler { + private static final InternalServerErrorHandler INSTANCE = new InternalServerErrorHandler(); + + private InternalServerErrorHandler() { + } + + public static InternalServerErrorHandler getInstance() { + return INSTANCE; + } + + @Override + public String handle(final HttpRequest httpRequest) { + return HttpResponseGenerator.getInternalServerErrorResponse(); + } +} + diff --git a/tomcat/src/test/java/org/apache/coyote/handler/exception/InternalServerErrorHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/exception/InternalServerErrorHandlerTest.java new file mode 100644 index 0000000000..949ce7194f --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/handler/exception/InternalServerErrorHandlerTest.java @@ -0,0 +1,18 @@ +package org.apache.coyote.handler.exception; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.http.request.HttpRequest; +import org.apache.http.response.HttpResponseGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class InternalServerErrorHandlerTest { + + @Test + @DisplayName("모든 요청 처리: 500 응답 반환") + void handle() { + HttpRequest httpRequest = new HttpRequest("GET", null, null, null, null); + assertThat(InternalServerErrorHandler.getInstance().handle(httpRequest)).isEqualTo(HttpResponseGenerator.getInternalServerErrorResponse()); + } +} From 126135943ab8507762d99cdb6da8dca3e81ee9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:07:35 +0900 Subject: [PATCH 72/81] =?UTF-8?q?refactor(HandlerMapping):=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=A7=81=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/HandlerMapping.java | 29 ++++++ .../org/apache/coyote/HandlerMappingTest.java | 94 +++++++++++-------- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/HandlerMapping.java b/tomcat/src/main/java/org/apache/coyote/HandlerMapping.java index 92be9cd1c1..2312982139 100644 --- a/tomcat/src/main/java/org/apache/coyote/HandlerMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/HandlerMapping.java @@ -5,12 +5,29 @@ import org.apache.coyote.handler.RegisterHandler; import org.apache.coyote.handler.RootEndPointHandler; import org.apache.coyote.handler.StaticResourceHandler; +import org.apache.coyote.handler.exception.InternalServerErrorHandler; +import org.apache.coyote.handler.exception.NotFoundHandler; +import org.apache.coyote.handler.exception.UnAuthorizationHandler; import org.apache.http.request.HttpRequest; + public class HandlerMapping { + + private static final HandlerMapping INSTANCE = new HandlerMapping(); private static final String PATH_DELIMITER = "/"; + private HandlerMapping() { + } + + public static HandlerMapping getInstance() { + return INSTANCE; + } + public Handler getHandler(final HttpRequest httpRequest) { + return getHandlerByEndPoint(httpRequest); + } + + private Handler getHandlerByEndPoint(final HttpRequest httpRequest) { final String path = httpRequest.getPath(); if (path.equals(PATH_DELIMITER)) { @@ -27,4 +44,16 @@ public Handler getHandler(final HttpRequest httpRequest) { return StaticResourceHandler.getInstance(); } + + public Handler getHandlerByException(final Exception exception) { + if (exception instanceof NotFoundException) { + return NotFoundHandler.getInstance(); + } + + if (exception instanceof UnauthorizedException) { + return UnAuthorizationHandler.getInstance(); + } + + return InternalServerErrorHandler.getInstance(); + } } diff --git a/tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java b/tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java index 94c98e24ad..04ac04e29f 100644 --- a/tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java +++ b/tomcat/src/test/java/org/apache/coyote/HandlerMappingTest.java @@ -7,57 +7,73 @@ import org.apache.coyote.handler.RegisterHandler; import org.apache.coyote.handler.RootEndPointHandler; import org.apache.coyote.handler.StaticResourceHandler; +import org.apache.coyote.handler.exception.InternalServerErrorHandler; +import org.apache.coyote.handler.exception.NotFoundHandler; +import org.apache.coyote.handler.exception.UnAuthorizationHandler; import org.apache.http.request.HttpRequest; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; class HandlerMappingTest { - private HandlerMapping requestHandlerMapping; + @Nested + class getHandler { + @Test + @DisplayName("루트 경로를 포함하는 경로일 경우: RootEndPointHandler 반환") + void getHandler_RootPath_ReturnsRootEndPointHandler() { + HttpRequest request = new HttpRequest("GET", "/", "HTTP/1.1", null, null); + Handler handler = HandlerMapping.getInstance().getHandler(request); + assertThat(handler).isInstanceOf(RootEndPointHandler.class); + } - @BeforeEach - void setUp() { - requestHandlerMapping = new HandlerMapping(); - } + @Test + @DisplayName("login을 포함하는 경로일 경우: LoginHandler 반환") + void getHandler_LoginPath_ReturnsLoginHandler() { + HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", null, null); + Handler handler = HandlerMapping.getInstance().getHandler(request); + assertThat(handler).isInstanceOf(LoginHandler.class); + } - @Test - @DisplayName("루트 경로를 포함하는 경로일 경우: RootEndPointHandler 반환") - void getHandler_RootPath_ReturnsRootEndPointHandler() { - HttpRequest request = new HttpRequest("GET", "/", "HTTP/1.1", null, null); - Handler handler = requestHandlerMapping.getHandler(request); - assertThat(handler).isInstanceOf(RootEndPointHandler.class); - } + @Test + @DisplayName("register 포함하는 경로일 경우: RegisterHandler를 반환") + void getHandler_RegisterPath_ReturnsRegisterHandler() { + HttpRequest request = new HttpRequest("GET", "/register", "HTTP/1.1", null, null); + Handler handler = HandlerMapping.getInstance().getHandler(request); + assertThat(handler).isInstanceOf(RegisterHandler.class); + } - @Test - @DisplayName("login을 포함하는 경로일 경우: LoginHandler 반환") - void getHandler_LoginPath_ReturnsLoginHandler() { - HttpRequest request = new HttpRequest("GET", "/login", "HTTP/1.1", null, null); - Handler handler = requestHandlerMapping.getHandler(request); - assertThat(handler).isInstanceOf(LoginHandler.class); + @Test + @DisplayName("정적 리소스 경로: StaticResourceHandler 반환") + void getHandler_StaticResourcePath_ReturnsStaticResourceHandler() { + HttpRequest request = new HttpRequest("GET", "/index.html", "HTTP/1.1", null, null); + Handler handler = HandlerMapping.getInstance().getHandler(request); + assertThat(handler).isInstanceOf(StaticResourceHandler.class); + } } - @Test - @DisplayName("register 포함하는 경로일 경우: RegisterHandler를 반환") - void getHandler_RegisterPath_ReturnsRegisterHandler() { - HttpRequest request = new HttpRequest("GET", "/register", "HTTP/1.1", null, null); - Handler handler = requestHandlerMapping.getHandler(request); - assertThat(handler).isInstanceOf(RegisterHandler.class); - } + @Nested + class getHandlerByException { - @Test - @DisplayName("정적 리소스 경로: StaticResourceHandler 반환") - void getHandler_StaticResourcePath_ReturnsStaticResourceHandler() { - HttpRequest request = new HttpRequest("GET", "/index.html", "HTTP/1.1", null, null); - Handler handler = requestHandlerMapping.getHandler(request); - assertThat(handler).isInstanceOf(StaticResourceHandler.class); - } + @Test + @DisplayName("UnauthorizedException 처리 : UnAuthorizationHandler 반환") + void getHandlerByException_UnauthorizedException() { + Handler handler = HandlerMapping.getInstance().getHandlerByException(new UnauthorizedException("권한이 없습니다.")); + assertThat(handler).isInstanceOf(UnAuthorizationHandler.class); + } + + @Test + @DisplayName("UnauthorizedException 처리 : UnAuthorizationHandler 반환") + void getHandlerByException_NotFoundException() { + Handler handler = HandlerMapping.getInstance().getHandlerByException(new NotFoundException("존재하지 않는 리소스입니다..")); + assertThat(handler).isInstanceOf(NotFoundHandler.class); + } - @Test - @DisplayName("알 수 없는 경로: StaticResourceHandler를 반환") - void getHandler_UnknownPath_ReturnsStaticResourceHandler() { - HttpRequest request = new HttpRequest("GET", "/unknown/path", "HTTP/1.1", null, null); - Handler handler = requestHandlerMapping.getHandler(request); - assertThat(handler).isInstanceOf(StaticResourceHandler.class); + @Test + @DisplayName("알 수 없는 에러: InternalServerErrornHandler 반환") + void getHandlerByException_UnknownPath_ReturnsStaticResourceHandler() { + Handler handler = HandlerMapping.getInstance().getHandlerByException(new Exception("에러")); + assertThat(handler).isInstanceOf(InternalServerErrorHandler.class); + } } } From 12c64e491ca73d526602845396241a539d2230c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:08:48 +0900 Subject: [PATCH 73/81] =?UTF-8?q?refactor(Http11Processor):=20=ED=95=B8?= =?UTF-8?q?=EB=93=A4=EB=A7=81=20=EB=8F=84=EC=A4=91=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=B0=9C=EC=83=9D=20=EC=8B=9C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http11/Http11Processor.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 48daf140c5..096c62b4aa 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -40,9 +40,7 @@ public void process(final Socket connection) { final OutputStream outputStream = connection.getOutputStream()) { final HttpRequest httpRequest = HttpRequestReader.readHttpRequest(bufferedReader); - final HandlerMapping handlerMapping = new HandlerMapping(); - final Handler handler = handlerMapping.getHandler(httpRequest); - final String response = handler.handle(httpRequest); + final String response = process(httpRequest); outputStream.write(response.getBytes()); outputStream.flush(); @@ -50,4 +48,15 @@ public void process(final Socket connection) { log.error(e.getMessage(), e); } } + + private String process(final HttpRequest httpRequest) { + final HandlerMapping handlerMapping = HandlerMapping.getInstance(); + final Handler handler = handlerMapping.getHandler(httpRequest); + + try { + return handler.handle(httpRequest); + } catch (Exception e) { + return handlerMapping.getHandlerByException(e).handle(httpRequest); + } + } } From 4557a2923a0bb80feffa107d67ca553b0c43b309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:30:32 +0900 Subject: [PATCH 74/81] =?UTF-8?q?refactor(HttpResponseGenerator):=20500=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/http/response/HttpResponseGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java index 2abe115a15..45ff1fc292 100644 --- a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java +++ b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java @@ -32,6 +32,6 @@ public static String getUnauthorizedResponse() { public static String getInternalServerErrorResponse() { return String.join("\r\n", - "HTTP/1.1 401 Internal Server Error "); + "HTTP/1.1 500 Internal Server Error "); } } From c5384c1bbe4f459b9d52e43a04eb745177d90cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:38:45 +0900 Subject: [PATCH 75/81] =?UTF-8?q?refactor(StaticResourceHandler):=20?= =?UTF-8?q?=EC=A0=95=EC=A0=81=20=ED=8C=8C=EC=9D=BC=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/handler/StaticResourceHandler.java | 9 ++++----- .../apache/coyote/handler/StaticResourceHandlerTest.java | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java index b5f74c14d6..cf66652f06 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/StaticResourceHandler.java @@ -13,10 +13,11 @@ public class StaticResourceHandler extends Handler { private static final Map STATIC_RESOURCE_EXTENSIONS = Map.of( - "css", "css", - "js", "assets" + "html", "", + "css", "/css", + "js", "/assets" ); - private static final String STATIC_RESOURCE_ROOT_PATH = "static/"; + private static final String STATIC_RESOURCE_ROOT_PATH = "static"; private static final String DEFAULT_EXTENSION = ".html"; private static final String PATH_DELIMITER = "/"; @@ -49,8 +50,6 @@ private String findResourcePath(final String path) { if (STATIC_RESOURCE_EXTENSIONS.containsKey(extension)) { return STATIC_RESOURCE_ROOT_PATH - .concat(STATIC_RESOURCE_EXTENSIONS.get(extension)) - .concat(PATH_DELIMITER) .concat(path); } diff --git a/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java index 9b662fb3db..9b5b8a0e53 100644 --- a/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/handler/StaticResourceHandlerTest.java @@ -22,7 +22,7 @@ void handle() throws IOException { final String responseBody = Files.readString(Path.of(resourceURL.getPath())); final StaticResourceHandler handler = StaticResourceHandler.getInstance(); - final String response = handler.handle(new HttpRequest("GET", "404.html", "HTTP/1.1", null, null)); + final String response = handler.handle(new HttpRequest("GET", "/404.html", "HTTP/1.1", null, null)); assertThat(response).contains(responseBody); } @@ -34,7 +34,7 @@ void handle_When_Different_Extension_Resource() throws IOException { final String fileContent = Files.readString(Path.of(resourceURL.getPath())); final StaticResourceHandler handler = StaticResourceHandler.getInstance(); - final String response = handler.handle(new HttpRequest("GET", "styles.css", "HTTP/1.1", null, null)); + final String response = handler.handle(new HttpRequest("GET", "/css/styles.css", "HTTP/1.1", null, null)); assertThat(response).contains(fileContent); } @@ -46,7 +46,7 @@ void handle_When_Extension_NotExist() throws IOException { final String responseBody = Files.readString(Path.of(resourceURL.getPath())); final StaticResourceHandler handler = StaticResourceHandler.getInstance(); - final String response = handler.handle(new HttpRequest("GET", "404", "HTTP/1.1", null, null)); + final String response = handler.handle(new HttpRequest("GET", "/404", "HTTP/1.1", null, null)); assertThat(response).contains(responseBody); } From 51103bf052d46fd1b210ae502488c366747a66e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:47:09 +0900 Subject: [PATCH 76/81] =?UTF-8?q?refactor(Http11ProcessorTest):=20?= =?UTF-8?q?=EA=B0=81=20http=20request=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/Http11ProcessorTest.java | 140 +++++++++++++++++- 1 file changed, 135 insertions(+), 5 deletions(-) diff --git a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java index d3397c7967..b2ff513c1f 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -1,18 +1,24 @@ package org.apache.coyote.http11; -import org.junit.jupiter.api.Test; -import support.StubSocket; +import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Files; -import static org.assertj.core.api.Assertions.assertThat; +import org.apache.catalina.session.Session; +import org.apache.catalina.session.SessionManager; +import org.apache.http.response.HttpResponseGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import support.StubSocket; class Http11ProcessorTest { @Test + @DisplayName("루트 Get 요청 처리") void process() { // given final var socket = new StubSocket(); @@ -33,9 +39,10 @@ void process() { } @Test + @DisplayName("index.html Get 요청 처리") void index() throws IOException { // given - final String httpRequest= String.join("\r\n", + final String httpRequest = String.join("\r\n", "GET /index.html HTTP/1.1 ", "Host: localhost:8080 ", "Connection: keep-alive ", @@ -53,9 +60,132 @@ void index() throws IOException { var expected = "HTTP/1.1 200 OK \r\n" + "Content-Type: text/html;charset=utf-8 \r\n" + "Content-Length: 5128 \r\n" + - "\r\n"+ + "\r\n" + + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + + assertThat(socket.output()).isEqualTo(expected); + } + + @Test + @DisplayName("login Get 요청 처리: 세션이 없는 경우 login html 반환") + void login_Get_WhenExistsSession() throws IOException { + // given + final String httpRequest = String.join("\r\n", + "GET /login HTTP/1.1 ", + "Host: localhost:8080 ", + "Connection: keep-alive ", + "", + ""); + + final var socket = new StubSocket(httpRequest); + final Http11Processor processor = new Http11Processor(socket); + + // when + processor.process(socket); + + // then + final URL resource = getClass().getClassLoader().getResource("static/login.html"); + var expected = "HTTP/1.1 200 OK \r\n" + + "Content-Type: text/html;charset=utf-8 \r\n" + + "Content-Length: 3797 \r\n" + + "\r\n" + + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + + assertThat(socket.output()).isEqualTo(expected); + } + + @Test + @DisplayName("login Get 요청 처리: 세션이 있는 경우 index html 리다이렉션") + void login_Get_WhenNotExistsSession() { + SessionManager sessionManager = SessionManager.getInstance(); + sessionManager.add(new Session("1")); + // given + final String httpRequest = String.join("\r\n", + "GET /login HTTP/1.1 ", + "Host: localhost:8080 ", + "Connection: keep-alive ", + "Cookie: JSESSIONID=1"); + + final var socket = new StubSocket(httpRequest); + final Http11Processor processor = new Http11Processor(socket); + + // when + processor.process(socket); + + assertThat(socket.output()).isEqualTo( + HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html")); + } + + @Test + @DisplayName("login Post 요청 처리: 성공 시 index html 리다이렉트 및 Set-Cookie 헤더에 세션값 추가") + void login_Post() { + // given + final String httpRequest = String.join("\r\n", + "POST /login HTTP/1.1", + "Host: localhost:8080", + "Content-Length: 30", + "Connection: keep-alive", + "", + "account=gugu&password=password"); + + final var socket = new StubSocket(httpRequest); + final Http11Processor processor = new Http11Processor(socket); + + // when + processor.process(socket); + + // then + assertThat(socket.output()).contains( + HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), + "Set-Cookie: JSESSIONID="); + } + + @Test + @DisplayName("register Get 요청 처리: 성공 시 register html") + void register_Get() throws IOException { + // given + final String httpRequest = String.join("\r\n", + "GET /register HTTP/1.1", + "Host: localhost:8080", + "Connection: keep-alive"); + + final var socket = new StubSocket(httpRequest); + final Http11Processor processor = new Http11Processor(socket); + + // when + processor.process(socket); + + // then + final URL resource = getClass().getClassLoader().getResource("static/register.html"); + var expected = "HTTP/1.1 200 OK \r\n" + + "Content-Type: text/html;charset=utf-8 \r\n" + + "Content-Length: 4319 \r\n" + + "\r\n" + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); assertThat(socket.output()).isEqualTo(expected); } + + @Test + @DisplayName("register Post 요청 처리: 성공 시 index html 리다이렉트") + void register_Post() { + // given + final String httpRequest = String.join("\r\n", + "POST /register HTTP/1.1", + "Host: localhost:8080", + "Content-Length: 49", + "Connection: keep-alive", + "", + "account=gugu&email=hi@naver.com&password=password"); + + final var socket = new StubSocket(httpRequest); + final Http11Processor processor = new Http11Processor(socket); + + // when + processor.process(socket); + + // then + assertThat(socket.output()).contains( + HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html")); + } } From 94cc5e9e35843ce9c7ceb0d73340c199e1fa6c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:22:59 +0900 Subject: [PATCH 77/81] =?UTF-8?q?test(HttpRequest):=20HttpRequest=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/http/request/HttpRequestTest.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/http/request/HttpRequestTest.java diff --git a/tomcat/src/test/java/org/apache/http/request/HttpRequestTest.java b/tomcat/src/test/java/org/apache/http/request/HttpRequestTest.java new file mode 100644 index 0000000000..6f00154419 --- /dev/null +++ b/tomcat/src/test/java/org/apache/http/request/HttpRequestTest.java @@ -0,0 +1,107 @@ +package org.apache.http.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.apache.http.HttpCookie; +import org.apache.http.HttpMethod; +import org.apache.http.header.HttpHeader; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class HttpRequestTest { + + @Test + @DisplayName("HttpRequest 객체 생성 및 기본 getter 메소드 테스트") + void createHttpRequest() { + // given + String method = "GET"; + String path = "/index.html"; + String version = "HTTP/1.1"; + HttpHeader[] headers = new HttpHeader[]{ + new HttpHeader("Host", "localhost:8080"), + new HttpHeader("Connection", "keep-alive") + }; + String body = "sample body"; + + // when + HttpRequest request = new HttpRequest(method, path, version, headers, body); + + // then + assertAll( + () -> assertThat(request.getMethod()).isEqualTo(HttpMethod.GET), + () -> assertThat(request.getPath()).isEqualTo(path), + () -> assertThat(request.getVersion()).isEqualTo(version), + () -> assertThat(request.getHeaders()).hasSize(2), + () -> assertThat(request.getBody()).isEqualTo(body) + + ); + } + + @Test + @DisplayName("isSameMethod 메소드 테스트") + void iSameMethod() { + // given + HttpRequest request = new HttpRequest("POST", "/login", "HTTP/1.1", null, null); + + // then + assertAll( + () -> assertThat(request.isSameMethod(HttpMethod.POST)).isTrue(), + () -> assertThat(request.isSameMethod(HttpMethod.GET)).isFalse() + ); + } + + @Test + @DisplayName("getHeader 메소드 테스트: 포함되지 않은 헤더인 경우 예외") + void testGetHeader() { + // given + HttpHeader[] headers = new HttpHeader[]{ + new HttpHeader("Content-Type", "application/json"), + new HttpHeader("Authorization", "Bearer token") + }; + HttpRequest request = new HttpRequest("GET", "/api", "HTTP/1.1", headers, null); + + // when & then + assertAll( + () -> assertThat(request.getHeader("Content-Type")).isEqualTo("application/json"), + () -> assertThat(request.getHeader("Authorization")).isEqualTo("Bearer token"), + () -> assertThatThrownBy(() -> request.getHeader("Non-Existent")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("존재 하지 않는 Header") + ); + } + + @Test + @DisplayName("HttpCookie 파싱 테스트") + void testParseCookie() { + // given + HttpHeader[] headers = new HttpHeader[]{ + new HttpHeader("Cookie", "sessionId=abc123; userId=john") + }; + HttpRequest request = new HttpRequest("GET", "/", "HTTP/1.1", headers, null); + + // when + HttpCookie cookie = request.getHttpCookie(); + + // then + assertAll( + () -> assertThat(cookie).isNotNull(), + () -> assertThat(cookie.getValue("sessionId")).isEqualTo("abc123"), + () -> assertThat(cookie.getValue("userId")).isEqualTo("john") + ); + } + + @Test + @DisplayName("Cookie 헤더가 없는 경우 HttpCookie null 테스트") + void testNoCookie() { + // given + HttpHeader[] headers = new HttpHeader[]{ + new HttpHeader("Content-Type", "text/html") + }; + HttpRequest request = new HttpRequest("GET", "/", "HTTP/1.1", headers, null); + + assertThat(request.getHttpCookie()).isNull(); + } +} + From 6199da296929e34d43f9d0d8e4c4e82113728556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:42:16 +0900 Subject: [PATCH 78/81] =?UTF-8?q?refactor(HttpRequest):=20application/x-ww?= =?UTF-8?q?w-form-urlencoded=20=ED=98=95=EC=8B=9D=EC=9D=98=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=EC=9D=B8=20=EA=B2=BD=EC=9A=B0=20=EB=B0=94=EB=94=94?= =?UTF-8?q?=EB=A5=BC=20key,=20value=EB=A1=9C=20=ED=8C=8C=EC=8B=B1=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=B1=85=EC=9E=84=20=EB=B6=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/handler/LoginHandler.java | 5 ++--- .../java/org/apache/http/request/HttpRequest.java | 13 ++++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 140ef700a3..923be5b3f9 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -50,9 +50,8 @@ private String processLoginGetRequest(final HttpRequest httpRequest) { } private String processLoginPostRequest(final HttpRequest httpRequest) { - final String[] params = httpRequest.getBody().split("&"); - final String account = params[0].split("=")[1]; - final String password = params[1].split("=")[1]; + final String account = httpRequest.getFormBody("account"); + final String password = httpRequest.getFormBody("password"); final Optional userOptional = InMemoryUserRepository.findByAccount(account); if (userOptional.isEmpty() || !userOptional.get().checkPassword(password)) { diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java index 4e3c64d3d4..84191216e7 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java @@ -4,8 +4,8 @@ import java.util.Optional; import org.apache.http.HttpCookie; -import org.apache.http.header.HttpHeader; import org.apache.http.HttpMethod; +import org.apache.http.header.HttpHeader; public class HttpRequest { private final HttpMethod method; @@ -33,6 +33,17 @@ private HttpCookie parseCookie(HttpHeader[] headers) { .orElse(null); } + public String getFormBody(String key) { + final String[] params = this.body.split("&"); + for (int i = 0; i < params.length; i++) { + String[] keyAndValue = params[i].split("="); + if (keyAndValue[0].equals(key)) { + return keyAndValue[1]; + } + } + return null; + } + public boolean isSameMethod(HttpMethod httpMethod) { return this.method == httpMethod; } From 78293509582ad977e60c330ffa9b59a92d5937cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:47:56 +0900 Subject: [PATCH 79/81] =?UTF-8?q?test(HttpRequestReader):=20HttpRequestRea?= =?UTF-8?q?der=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/request/HttpRequestReaderTest.java | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/http/request/HttpRequestReaderTest.java diff --git a/tomcat/src/test/java/org/apache/http/request/HttpRequestReaderTest.java b/tomcat/src/test/java/org/apache/http/request/HttpRequestReaderTest.java new file mode 100644 index 0000000000..11960e6c28 --- /dev/null +++ b/tomcat/src/test/java/org/apache/http/request/HttpRequestReaderTest.java @@ -0,0 +1,131 @@ +package org.apache.http.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class HttpRequestReaderTest { + + @Test + @DisplayName("GET 요청 읽기 테스트") + void readGetRequest() throws IOException { + // given + String rawRequest = String.join("\r\n", + "GET /index.html HTTP/1.1", + "Host: localhost:8080", + "Connection: keep-alive", + "", + ""); + BufferedReader reader = new BufferedReader(new StringReader(rawRequest)); + + // when + HttpRequest request = HttpRequestReader.readHttpRequest(reader); + + // then + assertAll( + () -> assertThat(request.getMethod().name()).isEqualTo("GET"), + () -> assertThat(request.getPath()).isEqualTo("/index.html"), + () -> assertThat(request.getVersion()).isEqualTo("HTTP/1.1"), + () -> assertThat(request.getHeaders()).hasSize(2), + () -> assertThat(request.getHeader("Host")).isEqualTo("localhost:8080"), + () -> assertThat(request.getBody()).isNull() + ); + } + + @Test + @DisplayName("POST 요청 읽기 테스트") + void readPostRequest() throws IOException { + // given + String rawRequest = String.join("\r\n", + "POST /login HTTP/1.1", + "Host: localhost:8080", + "Content-Type: application/x-www-form-urlencoded", + "Content-Length: 27", + "", + "username=john&password=pass"); + BufferedReader reader = new BufferedReader(new StringReader(rawRequest)); + + // when + HttpRequest request = HttpRequestReader.readHttpRequest(reader); + + // then + assertAll( + () -> assertThat(request.getMethod().name()).isEqualTo("POST"), + () -> assertThat(request.getPath()).isEqualTo("/login"), + () -> assertThat(request.getVersion()).isEqualTo("HTTP/1.1"), + () -> assertThat(request.getHeaders()).hasSize(3), + () -> assertThat(request.getHeader("Content-Type")).isEqualTo("application/x-www-form-urlencoded"), + () -> assertThat(request.getBody()).isEqualTo("username=john&password=pass") + ); + } + + @Test + @DisplayName("헤더가 없는 요청 읽기 테스트") + void readRequestWithoutHeaders() throws IOException { + // given + String rawRequest = String.join("\r\n", + "GET / HTTP/1.1", + "", + ""); + BufferedReader reader = new BufferedReader(new StringReader(rawRequest)); + + // when + HttpRequest request = HttpRequestReader.readHttpRequest(reader); + + // then + assertAll( + () -> assertThat(request.getMethod().name()).isEqualTo("GET"), + () -> assertThat(request.getPath()).isEqualTo("/"), + () -> assertThat(request.getVersion()).isEqualTo("HTTP/1.1"), + () -> assertThat(request.getHeaders()).isEmpty(), + () -> assertThat(request.getBody()).isNull() + + ); + } + + @Test + @DisplayName("Content-Length가 없는 POST 요청 읽기 테스트") + void readPostRequestWithoutContentLength() throws IOException { + // given + String rawRequest = String.join("\r\n", + "POST /hi HTTP/1.1", + "Host: localhost:8080", + "Content-Type: application/x-www-form-urlencoded", + "", + ""); + BufferedReader reader = new BufferedReader(new StringReader(rawRequest)); + + // when + HttpRequest request = HttpRequestReader.readHttpRequest(reader); + + // then + assertAll( + () -> assertThat(request.getMethod().name()).isEqualTo("POST"), + () -> assertThat(request.getPath()).isEqualTo("/hi"), + () -> assertThat(request.getVersion()).isEqualTo("HTTP/1.1"), + () -> assertThat(request.getHeaders()).hasSize(2), + () -> assertThat(request.getHeader("Content-Type")).isEqualTo("application/x-www-form-urlencoded"), + () -> assertThat(request.getBody()).isNull() + + ); + } + + @Test + @DisplayName("잘못된 형식의 요청 읽기 테스트") + void readMalformedRequest() { + // given + String rawRequest = "INVALID REQUEST"; + BufferedReader reader = new BufferedReader(new StringReader(rawRequest)); + + // when & then + assertThatThrownBy(() -> HttpRequestReader.readHttpRequest(reader)) + .isInstanceOf(ArrayIndexOutOfBoundsException.class); + } +} From b90b9aa7caf33b0b64a644d938bab80ea277b00e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 21:51:36 +0900 Subject: [PATCH 80/81] =?UTF-8?q?test(HttpResponseGenerator):=20host=20?= =?UTF-8?q?=EA=B3=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/handler/LoginHandler.java | 4 ++-- .../java/org/apache/coyote/handler/RegisterHandler.java | 2 +- .../org/apache/http/response/HttpResponseGenerator.java | 4 ++-- .../java/org/apache/coyote/http11/Http11ProcessorTest.java | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java index 923be5b3f9..1bd0b60a62 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java @@ -46,7 +46,7 @@ private String processLoginGetRequest(final HttpRequest httpRequest) { return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/login.html", "HTTP/1.1", null, null)); } - return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); + return HttpResponseGenerator.getFoundResponse("/index.html"); } private String processLoginPostRequest(final HttpRequest httpRequest) { @@ -62,7 +62,7 @@ private String processLoginPostRequest(final HttpRequest httpRequest) { session.setAttribute("user", userOptional.get()); sessionManager.add(session); return addCookie( - HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), + HttpResponseGenerator.getFoundResponse("/index.html"), HttpCookie.of("JSESSIONID=" + session.getId())); } diff --git a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java index e06d388e00..03226fddf0 100644 --- a/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/handler/RegisterHandler.java @@ -36,6 +36,6 @@ private String processRegisterPostRequest(final HttpRequest httpRequest) { String email = body[1].split("=")[1]; String password = body[2].split("=")[1]; InMemoryUserRepository.save(new User(account, password, email)); - return HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"); + return HttpResponseGenerator.getFoundResponse("/index.html"); } } diff --git a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java index 45ff1fc292..fdde4fa014 100644 --- a/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java +++ b/tomcat/src/main/java/org/apache/http/response/HttpResponseGenerator.java @@ -14,10 +14,10 @@ public static String getOkResponse(String mimeType, String responseBody) { responseBody); } - public static String getFoundResponse(String url) { + public static String getFoundResponse(String resourcePath) { return String.join("\r\n", "HTTP/1.1 302 Found ", - "Location: " + url); + "Location: http://localhost:8080" + resourcePath); } public static String getNotFountResponse() { diff --git a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java index b2ff513c1f..0931626e37 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -113,7 +113,7 @@ void login_Get_WhenNotExistsSession() { processor.process(socket); assertThat(socket.output()).isEqualTo( - HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html")); + HttpResponseGenerator.getFoundResponse("/index.html")); } @Test @@ -136,7 +136,7 @@ void login_Post() { // then assertThat(socket.output()).contains( - HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html"), + HttpResponseGenerator.getFoundResponse("/index.html"), "Set-Cookie: JSESSIONID="); } @@ -186,6 +186,6 @@ void register_Post() { // then assertThat(socket.output()).contains( - HttpResponseGenerator.getFoundResponse("http://localhost:8080/index.html")); + HttpResponseGenerator.getFoundResponse("/index.html")); } } From aff79b0ff56e35ca55635e6df757a7ae2af9ec5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98jminkkk=E2=80=99?= <102847513+jminkkk@users.noreply.github.com> Date: Tue, 10 Sep 2024 22:11:09 +0900 Subject: [PATCH 81/81] =?UTF-8?q?refacotr(HttpRequest):=20=ED=8A=B9?= =?UTF-8?q?=EC=A0=95=20=ED=97=A4=EB=8D=94=EC=9D=B8=EC=A7=80=20StandardHttp?= =?UTF-8?q?Header=20=EC=97=90=EA=B2=8C=20=EB=AC=BC=EC=96=B4=EB=B3=B4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/http/request/HttpRequest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java index 84191216e7..5314a0ad4d 100644 --- a/tomcat/src/main/java/org/apache/http/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/http/request/HttpRequest.java @@ -6,6 +6,7 @@ import org.apache.http.HttpCookie; import org.apache.http.HttpMethod; import org.apache.http.header.HttpHeader; +import org.apache.http.header.StandardHttpHeader; public class HttpRequest { private final HttpMethod method; @@ -27,7 +28,7 @@ public HttpRequest(String method, String path, String version, HttpHeader[] head private HttpCookie parseCookie(HttpHeader[] headers) { return Optional.ofNullable(headers) .flatMap(hs -> Arrays.stream(hs) - .filter(header -> header.getKey().equalsIgnoreCase("Cookie")) + .filter(header -> StandardHttpHeader.COOKIE.equalsIgnoreCase(header.getKey())) .findFirst() .map(header -> HttpCookie.of(header.getValue()))) .orElse(null);