From 9b1c64f6538e4b531f09e47ac44cc334e55df4d9 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Mon, 9 Sep 2024 17:25:55 +0900 Subject: [PATCH 01/22] =?UTF-8?q?feat:=20=EB=A6=AC=EB=8B=A4=EC=9D=B4?= =?UTF-8?q?=EB=A0=89=ED=8A=B8=20=EC=8B=9C=20302=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=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 --- .../apache/coyote/http11/Http11Processor.java | 22 +++++++++---------- .../coyote/http11/response/HttpResponse.java | 6 ++--- 2 files changed, 14 insertions(+), 14 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 5f5d21eddb..99ea1c8286 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -47,7 +47,7 @@ public void process(final Socket connection) { String responseBody; if (page.equals("/")) { responseBody = "Hello world!"; - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); } else if (page.startsWith("/login") && httpMethod.equals("POST")) { String requestBody = httpRequest.getBody(); String account = requestBody.split("&")[0].split("=")[1]; @@ -64,12 +64,12 @@ public void process(final Socket connection) { sessionManager.add(session); responseBody = new String(ResourceLoader.loadResource("static/index.html")); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 302, "FOUND", "text/html", responseBody); httpResponse.addHeader("Location", "/index.html"); httpResponse.addHeader("Set-Cookie", "JSESSIONID=" + jSessionId); } else { responseBody = new String(ResourceLoader.loadResource("static/401.html")); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 302, "FOUND", "text/html", responseBody); httpResponse.addHeader("Location", "/401.html"); } } else if (page.startsWith("/login") && httpMethod.equals("GET")) { @@ -82,14 +82,14 @@ public void process(final Socket connection) { if (session != null && session.getAttribute("user") != null) { responseBody = new String(ResourceLoader.loadResource("static/index.html")); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 302, "FOUND", "text/html", responseBody); } else { responseBody = new String(ResourceLoader.loadResource("static" + page + ".html")); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); } } else { responseBody = new String(ResourceLoader.loadResource("static" + page + ".html")); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); } } else if (page.equals("/register") && httpMethod.equals("POST")) { String requestBody = httpRequest.getBody(); @@ -98,20 +98,20 @@ public void process(final Socket connection) { String password = requestBody.split("&")[2].split("=")[1]; InMemoryUserRepository.save(new User(account, email, password)); responseBody = new String(ResourceLoader.loadResource("static/index.html")); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); httpResponse.addHeader("Location", "/index.html"); } else if (page.startsWith("/css/")) { responseBody = new String(ResourceLoader.loadResource("static" + page)); - httpResponse = HttpResponse.of(version, 200, "text/css", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/css", responseBody); } else if (page.contains(".js")) { responseBody = new String(ResourceLoader.loadResource("static" + page)); - httpResponse = HttpResponse.of(version, 200, "text/javascript", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/javascript", responseBody); } else if (page.endsWith(".html")) { responseBody = new String(ResourceLoader.loadResource("static" + page)); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); } else { responseBody = new String(ResourceLoader.loadResource("static" + page + ".html")); - httpResponse = HttpResponse.of(version, 200, "text/html", responseBody); + httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); } httpResponse.send(outputStream); } catch (IOException | UncheckedServletException e) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index 7eea9700d7..53332c6e03 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -23,13 +23,13 @@ public HttpResponse(String version, int statusCode, String statusMessage, Map headers = new HashMap<>(); headers.put("Content-Type", contentType + ";charset=utf-8"); headers.put("Content-Length", body.getBytes().length); - return new HttpResponse(version, statusCode, "OK", headers, body); + return new HttpResponse(version, statusCode, statusMessage, headers, body); } public void addHeader(String key, String value) { From eaf1aac136417b393f161f868f5ad6d9104b48be Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Mon, 9 Sep 2024 21:10:36 +0900 Subject: [PATCH 02/22] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20log?= =?UTF-8?q?inController=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AbstractController.java | 21 ++++ .../com/techcourse/controller/Controller.java | 8 ++ .../controller/LoginController.java | 98 +++++++++++++++++++ .../techcourse/controller/RequestMapping.java | 21 ++++ .../coyote/http11/request/HttpRequest.java | 18 ++++ .../coyote/http11/response/HttpResponse.java | 32 ++++-- 6 files changed, 192 insertions(+), 6 deletions(-) create mode 100644 tomcat/src/main/java/com/techcourse/controller/AbstractController.java create mode 100644 tomcat/src/main/java/com/techcourse/controller/Controller.java create mode 100644 tomcat/src/main/java/com/techcourse/controller/LoginController.java create mode 100644 tomcat/src/main/java/com/techcourse/controller/RequestMapping.java diff --git a/tomcat/src/main/java/com/techcourse/controller/AbstractController.java b/tomcat/src/main/java/com/techcourse/controller/AbstractController.java new file mode 100644 index 0000000000..2533c2982d --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/AbstractController.java @@ -0,0 +1,21 @@ +package com.techcourse.controller; + +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public abstract class AbstractController implements Controller { + + @Override + public void service(HttpRequest request, HttpResponse response) throws Exception { + if (request.isGet()) { + doGet(request, response); + } + if (request.isPost()) { + doPost(request, response); + } + } + + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } + + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } +} diff --git a/tomcat/src/main/java/com/techcourse/controller/Controller.java b/tomcat/src/main/java/com/techcourse/controller/Controller.java new file mode 100644 index 0000000000..b4388ebeca --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/Controller.java @@ -0,0 +1,8 @@ +package com.techcourse.controller; + +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public interface Controller { + void service(HttpRequest request, HttpResponse response) throws Exception; +} diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java new file mode 100644 index 0000000000..1041d01913 --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -0,0 +1,98 @@ +package com.techcourse.controller; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; +import org.apache.coyote.http11.Session; +import org.apache.coyote.http11.SessionManager; +import org.apache.coyote.http11.controller.ResourceLoader; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.UUID; + +public class LoginController extends AbstractController { + + private static final Logger log = LoggerFactory.getLogger(LoginController.class); + private static final SessionManager sessionManager = new SessionManager(); + + @Override + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { + String requestBody = request.getBody(); + String account = requestBody.split("&")[0].split("=")[1]; + String password = requestBody.split("&")[1].split("=")[1]; + + User user = InMemoryUserRepository.findByAccount(account).get(); + + String responseBody; + + if (user.checkPassword(password)) { + log.info("user : {}", user); + UUID jSessionId = UUID.randomUUID(); + Session session = new Session(jSessionId.toString()); + session.setAttribute("user", user); + sessionManager.add(session); + + responseBody = new String(ResourceLoader.loadResource("static/index.html")); + + response.addVersion(request.getVersion()); + response.addStatusCode(302); + response.addStatusMessage("FOUND"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader("Location", "/index.html"); + response.addHeader("Set-Cookie", "JSESSIONID=" + jSessionId); + response.addBody(responseBody); + + } else { + responseBody = new String(ResourceLoader.loadResource("static/401.html")); + + response.addVersion(request.getVersion()); + response.addStatusCode(302); + response.addStatusMessage("FOUND"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader("Location", "/401.html"); + response.addBody(responseBody); + } + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + Map headers = request.getHeaders(); + String responseBody; + if (headers.containsKey("Cookie") && + headers.get("Cookie").startsWith("JSESSIONID=")) { + String jSessionId = headers.get("Cookie").split("=")[1]; + Session session = sessionManager.findSession(jSessionId); + + if (session != null && session.getAttribute("user") != null) { + responseBody = new String(ResourceLoader.loadResource("static/index.html")); + response.addVersion(request.getVersion()); + response.addStatusCode(302); + response.addStatusMessage("FOUND"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader("Location", "/index.html"); + response.addBody(responseBody); + } else { + responseBody = new String(ResourceLoader.loadResource("static" + request.getPath() + ".html")); + response.addVersion(request.getVersion()); + response.addStatusCode(200); + response.addStatusMessage("OK"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addBody(responseBody); + } + } else { + responseBody = new String(ResourceLoader.loadResource("static" + request.getPath() + ".html")); + response.addVersion(request.getVersion()); + response.addStatusCode(200); + response.addStatusMessage("OK"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addBody(responseBody); + } + } +} diff --git a/tomcat/src/main/java/com/techcourse/controller/RequestMapping.java b/tomcat/src/main/java/com/techcourse/controller/RequestMapping.java new file mode 100644 index 0000000000..987e78b039 --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/RequestMapping.java @@ -0,0 +1,21 @@ +package com.techcourse.controller; + +import org.apache.coyote.http11.request.HttpRequest; +import java.util.HashMap; +import java.util.Map; + +public class RequestMapping { + + private static final Map requestMapper = new HashMap<>(); + + static { + requestMapper.put("/login", new LoginController()); + } + + public Controller getController(HttpRequest request) { + if(requestMapper.containsKey(request.getPath())) { + return requestMapper.get(request.getPath()); + } + return new StaticResourceController(); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index d2f95eedac..f133061c9a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -55,6 +55,24 @@ public static HttpRequest from(InputStream inputStream) throws IOException { return new HttpRequest(method, path, version, headers, null); } + public boolean isGet() { + return method.equals("GET"); + } + + public boolean isPost() { + return method.equals("POST"); + } + + public String getContentType() { + if (path.endsWith(".css")) { + return "text/css;charset=utf-8"; + } + if (path.endsWith(".js")) { + return "text/javascript"; + } + return "text/html"; + } + public String getHttpMethod() { return method; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index 53332c6e03..3d235fd025 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -8,11 +8,11 @@ public class HttpResponse { - private final String version; - private final int statusCode; - private final String statusMessage; - private final Map headers; - private final String body; + private String version; + private int statusCode; + private String statusMessage; + private Map headers; + private String body; public HttpResponse(String version, int statusCode, String statusMessage, Map headers, String body) { @@ -23,6 +23,10 @@ public HttpResponse(String version, int statusCode, String statusMessage, Map(); + } + public static HttpResponse of(String version, int statusCode, String statusMessage, String contentType, String body) { Map headers = new HashMap<>(); @@ -32,10 +36,26 @@ public static HttpResponse of(String version, int statusCode, String statusMessa return new HttpResponse(version, statusCode, statusMessage, headers, body); } - public void addHeader(String key, String value) { + public void addVersion(String version) { + this.version = version; + } + + public void addStatusCode(int statusCode) { + this.statusCode = statusCode; + } + + public void addStatusMessage(String statusMessage) { + this.statusMessage = statusMessage; + } + + public void addHeader(String key, Object value) { headers.put(key, value); } + public void addBody(String body) { + this.body = body; + } + public void send(OutputStream outputStream) { try { StringBuilder sb = new StringBuilder(); From 5a281de4428d6407fcafd6a8ff9cdebc4c744947 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Mon, 9 Sep 2024 21:48:55 +0900 Subject: [PATCH 03/22] =?UTF-8?q?feat:=20=EC=A0=95=EC=A0=81=20=EB=A6=AC?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=9A=94=EC=B2=AD=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20StaticResourceController=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 14 +++-------- .../controller/StaticResourceController.java | 19 ++++++++++++++ .../coyote/http11/request/HttpRequest.java | 25 +++++++++++++++++++ 3 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index 1041d01913..197cd2706c 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -4,7 +4,6 @@ import com.techcourse.model.User; import org.apache.coyote.http11.Session; import org.apache.coyote.http11.SessionManager; -import org.apache.coyote.http11.controller.ResourceLoader; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import org.slf4j.Logger; @@ -24,8 +23,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti String password = requestBody.split("&")[1].split("=")[1]; User user = InMemoryUserRepository.findByAccount(account).get(); - - String responseBody; + String responseBody = new String(request.toHttpResponseBody()); if (user.checkPassword(password)) { log.info("user : {}", user); @@ -34,8 +32,6 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti session.setAttribute("user", user); sessionManager.add(session); - responseBody = new String(ResourceLoader.loadResource("static/index.html")); - response.addVersion(request.getVersion()); response.addStatusCode(302); response.addStatusMessage("FOUND"); @@ -46,8 +42,6 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti response.addBody(responseBody); } else { - responseBody = new String(ResourceLoader.loadResource("static/401.html")); - response.addVersion(request.getVersion()); response.addStatusCode(302); response.addStatusMessage("FOUND"); @@ -61,14 +55,14 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti @Override protected void doGet(HttpRequest request, HttpResponse response) throws Exception { Map headers = request.getHeaders(); - String responseBody; + String responseBody = new String(request.toHttpResponseBody()); if (headers.containsKey("Cookie") && headers.get("Cookie").startsWith("JSESSIONID=")) { String jSessionId = headers.get("Cookie").split("=")[1]; Session session = sessionManager.findSession(jSessionId); if (session != null && session.getAttribute("user") != null) { - responseBody = new String(ResourceLoader.loadResource("static/index.html")); + response.addVersion(request.getVersion()); response.addStatusCode(302); response.addStatusMessage("FOUND"); @@ -77,7 +71,6 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio response.addHeader("Location", "/index.html"); response.addBody(responseBody); } else { - responseBody = new String(ResourceLoader.loadResource("static" + request.getPath() + ".html")); response.addVersion(request.getVersion()); response.addStatusCode(200); response.addStatusMessage("OK"); @@ -86,7 +79,6 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio response.addBody(responseBody); } } else { - responseBody = new String(ResourceLoader.loadResource("static" + request.getPath() + ".html")); response.addVersion(request.getVersion()); response.addStatusCode(200); response.addStatusMessage("OK"); diff --git a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java new file mode 100644 index 0000000000..6aa4c81cc6 --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java @@ -0,0 +1,19 @@ +package com.techcourse.controller; + +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public class StaticResourceController extends AbstractController { + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + String responseBody = new String(request.toHttpResponseBody()); + + response.addVersion(request.getVersion()); + response.addStatusCode(200); + response.addStatusMessage("OK"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addBody(responseBody); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index f133061c9a..cf0e0ead9c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,9 +1,14 @@ package org.apache.coyote.http11.request; +import org.apache.coyote.http11.controller.ResourceLoader; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; @@ -63,6 +68,26 @@ public boolean isPost() { return method.equals("POST"); } + public byte[] toHttpResponseBody() throws URISyntaxException, IOException { + URL url = ResourceLoader.class.getClassLoader().getResource(loadResourceName(path)); + if (url == null) { + throw new IllegalArgumentException("존재하지 않는 리소스 입니다." + path); + } + + Path path = Path.of(url.toURI()); + return Files.readAllBytes(path); + } + + private String loadResourceName(String path) { + if (path.equals("/")) { + return "static/index.html"; + } + if (!path.endsWith(".html") && !path.contains(".")) { + return "static" + path + ".html"; + } + return "static" + path; + } + public String getContentType() { if (path.endsWith(".css")) { return "text/css;charset=utf-8"; From 46bbe0a55df7c49ac4a770ca542361dea51b32e4 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Tue, 10 Sep 2024 16:00:17 +0900 Subject: [PATCH 04/22] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=9A=94=EC=B2=AD=20=EC=B2=98=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20RegisterController=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RegisterController.java | 40 ++++++++ .../techcourse/controller/RequestMapping.java | 3 +- .../apache/coyote/http11/Http11Processor.java | 93 ++----------------- .../coyote/http11/request/HttpRequest.java | 4 +- .../coyote/http11/Http11ProcessorTest.java | 25 +---- 5 files changed, 55 insertions(+), 110 deletions(-) create mode 100644 tomcat/src/main/java/com/techcourse/controller/RegisterController.java diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java new file mode 100644 index 0000000000..6fc65746dc --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -0,0 +1,40 @@ +package com.techcourse.controller; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public class RegisterController extends AbstractController { + + @Override + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { + String requestBody = request.getBody(); + String account = requestBody.split("&")[0].split("=")[1]; + String email = requestBody.split("&")[1].split("=")[1]; + String password = requestBody.split("&")[2].split("=")[1]; + + InMemoryUserRepository.save(new User(account, password, email)); + String responseBody = new String(request.toHttpResponseBody()); + + response.addVersion(request.getVersion()); + response.addStatusCode(302); + response.addStatusMessage("FOUND"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader("Location", "/index.html"); + response.addBody(responseBody); + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + String responseBody = new String(request.toHttpResponseBody()); + + response.addVersion(request.getVersion()); + response.addStatusCode(200); + response.addStatusMessage("OK"); + response.addHeader("Content-Type", request.getContentType()); + response.addHeader("Content-Length", responseBody.getBytes().length); + response.addBody(responseBody); + } +} diff --git a/tomcat/src/main/java/com/techcourse/controller/RequestMapping.java b/tomcat/src/main/java/com/techcourse/controller/RequestMapping.java index 987e78b039..7d5f8ef35b 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RequestMapping.java +++ b/tomcat/src/main/java/com/techcourse/controller/RequestMapping.java @@ -10,10 +10,11 @@ public class RequestMapping { static { requestMapper.put("/login", new LoginController()); + requestMapper.put("/register", new RegisterController()); } public Controller getController(HttpRequest request) { - if(requestMapper.containsKey(request.getPath())) { + if (requestMapper.containsKey(request.getPath())) { return requestMapper.get(request.getPath()); } return new StaticResourceController(); 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 99ea1c8286..3c70244fc9 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,23 +1,20 @@ package org.apache.coyote.http11; -import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.controller.Controller; +import com.techcourse.controller.RequestMapping; import com.techcourse.exception.UncheckedServletException; -import com.techcourse.model.User; import org.apache.coyote.Processor; -import org.apache.coyote.http11.controller.ResourceLoader; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.Socket; -import java.net.URISyntaxException; -import java.util.Map; -import java.util.UUID; public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); + private static final RequestMapping requestMapping = new RequestMapping(); private final Socket connection; @@ -35,88 +32,16 @@ public void run() { public void process(final Socket connection) { try (final var inputStream = connection.getInputStream(); final var outputStream = connection.getOutputStream()) { + HttpRequest request = HttpRequest.from(inputStream); + HttpResponse response = new HttpResponse(); - HttpRequest httpRequest = HttpRequest.from(inputStream); + Controller controller = requestMapping.getController(request); + controller.service(request, response); - String version = httpRequest.getVersion(); - Map httpRequestHeaders = httpRequest.getHeaders(); - String httpMethod = httpRequest.getHttpMethod(); - String page = httpRequest.getPath(); - HttpResponse httpResponse; - - String responseBody; - if (page.equals("/")) { - responseBody = "Hello world!"; - httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); - } else if (page.startsWith("/login") && httpMethod.equals("POST")) { - String requestBody = httpRequest.getBody(); - String account = requestBody.split("&")[0].split("=")[1]; - String password = requestBody.split("&")[1].split("=")[1]; - - User user = InMemoryUserRepository.findByAccount(account).get(); - - if (user.checkPassword(password)) { - log.info("user : {}", user); - SessionManager sessionManager = new SessionManager(); - UUID jSessionId = UUID.randomUUID(); - Session session = new Session(jSessionId.toString()); - session.setAttribute("user", user); - sessionManager.add(session); - - responseBody = new String(ResourceLoader.loadResource("static/index.html")); - httpResponse = HttpResponse.of(version, 302, "FOUND", "text/html", responseBody); - httpResponse.addHeader("Location", "/index.html"); - httpResponse.addHeader("Set-Cookie", "JSESSIONID=" + jSessionId); - } else { - responseBody = new String(ResourceLoader.loadResource("static/401.html")); - httpResponse = HttpResponse.of(version, 302, "FOUND", "text/html", responseBody); - httpResponse.addHeader("Location", "/401.html"); - } - } else if (page.startsWith("/login") && httpMethod.equals("GET")) { - SessionManager sessionManager = new SessionManager(); - - if (httpRequestHeaders.containsKey("Cookie") && - httpRequestHeaders.get("Cookie").startsWith("JSESSIONID=")) { - String jSessionId = httpRequestHeaders.get("Cookie").split("=")[1]; - Session session = sessionManager.findSession(jSessionId); - - if (session != null && session.getAttribute("user") != null) { - responseBody = new String(ResourceLoader.loadResource("static/index.html")); - httpResponse = HttpResponse.of(version, 302, "FOUND", "text/html", responseBody); - } else { - responseBody = new String(ResourceLoader.loadResource("static" + page + ".html")); - httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); - } - } else { - responseBody = new String(ResourceLoader.loadResource("static" + page + ".html")); - httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); - } - } else if (page.equals("/register") && httpMethod.equals("POST")) { - String requestBody = httpRequest.getBody(); - String account = requestBody.split("&")[0].split("=")[1]; - String email = requestBody.split("&")[1].split("=")[1]; - String password = requestBody.split("&")[2].split("=")[1]; - InMemoryUserRepository.save(new User(account, email, password)); - responseBody = new String(ResourceLoader.loadResource("static/index.html")); - httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); - httpResponse.addHeader("Location", "/index.html"); - } else if (page.startsWith("/css/")) { - responseBody = new String(ResourceLoader.loadResource("static" + page)); - httpResponse = HttpResponse.of(version, 200, "OK", "text/css", responseBody); - } else if (page.contains(".js")) { - responseBody = new String(ResourceLoader.loadResource("static" + page)); - httpResponse = HttpResponse.of(version, 200, "OK", "text/javascript", responseBody); - } else if (page.endsWith(".html")) { - responseBody = new String(ResourceLoader.loadResource("static" + page)); - httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); - } else { - responseBody = new String(ResourceLoader.loadResource("static" + page + ".html")); - httpResponse = HttpResponse.of(version, 200, "OK", "text/html", responseBody); - } - httpResponse.send(outputStream); + response.send(outputStream); } catch (IOException | UncheckedServletException e) { log.error(e.getMessage(), e); - } catch (URISyntaxException e) { + } catch (Exception e) { throw new RuntimeException(e); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index cf0e0ead9c..6afe840f0e 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -90,12 +90,12 @@ private String loadResourceName(String path) { public String getContentType() { if (path.endsWith(".css")) { - return "text/css;charset=utf-8"; + return "text/css"; } if (path.endsWith(".js")) { return "text/javascript"; } - return "text/html"; + return "text/html;charset=utf-8"; } public String getHttpMethod() { 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 fe20ebd29f..83a9a813b6 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.Test; import support.StubSocket; - import java.io.File; import java.io.IOException; import java.net.URL; @@ -12,30 +11,10 @@ class Http11ProcessorTest { - @Test - void process() { - // given - final var socket = new StubSocket(); - final var processor = new Http11Processor(socket); - - // when - processor.process(socket); - - // then - var expected = String.join("\r\n", - "HTTP/1.1 200 OK ", - "Content-Length: 12 ", - "Content-Type: text/html;charset=utf-8 ", - "", - "Hello world!"); - - assertThat(socket.output()).isEqualTo(expected); - } - @Test 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,7 +32,7 @@ void index() throws IOException { var expected = "HTTP/1.1 200 OK \r\n" + "Content-Length: 5564 \r\n" + "Content-Type: text/html;charset=utf-8 \r\n" + - "\r\n"+ + "\r\n" + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); assertThat(socket.output()).isEqualTo(expected); From c7932ca5fe7aa02bd10a68c72140f5af026ef26b Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Tue, 10 Sep 2024 16:03:39 +0900 Subject: [PATCH 05/22] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=20REsourceLoader=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http11/controller/ResourceLoader.java | 20 ------------------- .../coyote/http11/request/HttpRequest.java | 3 +-- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 tomcat/src/main/java/org/apache/coyote/http11/controller/ResourceLoader.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/controller/ResourceLoader.java b/tomcat/src/main/java/org/apache/coyote/http11/controller/ResourceLoader.java deleted file mode 100644 index bce0bb3c39..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http11/controller/ResourceLoader.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.apache.coyote.http11.controller; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; - -public class ResourceLoader { - - public static byte[] loadResource(String resourceName) throws URISyntaxException, IOException { - URL url = ResourceLoader.class.getClassLoader().getResource(resourceName); - if (url == null) { - throw new IllegalArgumentException("존재하지 않는 리소스 입니다." + resourceName); - } - - Path path = Path.of(url.toURI()); - return Files.readAllBytes(path); - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 6afe840f0e..90ebbf0580 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,6 +1,5 @@ package org.apache.coyote.http11.request; -import org.apache.coyote.http11.controller.ResourceLoader; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -69,7 +68,7 @@ public boolean isPost() { } public byte[] toHttpResponseBody() throws URISyntaxException, IOException { - URL url = ResourceLoader.class.getClassLoader().getResource(loadResourceName(path)); + URL url = getClass().getClassLoader().getResource(loadResourceName(path)); if (url == null) { throw new IllegalArgumentException("존재하지 않는 리소스 입니다." + path); } From 6dc09d89c3b320b1c03ce398737f9cf843075ff8 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Tue, 10 Sep 2024 18:42:06 +0900 Subject: [PATCH 06/22] =?UTF-8?q?feat:=20HttpHeaders=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 35 ++++++++++--------- .../controller/RegisterController.java | 11 +++--- .../controller/StaticResourceController.java | 5 +-- .../org/apache/coyote/http11/HttpHeaders.java | 10 ++++++ .../coyote/http11/request/HttpRequest.java | 3 +- .../coyote/http11/response/HttpResponse.java | 9 ----- 6 files changed, 39 insertions(+), 34 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index 197cd2706c..d06c3170ad 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -2,6 +2,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; +import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.Session; import org.apache.coyote.http11.SessionManager; import org.apache.coyote.http11.request.HttpRequest; @@ -35,19 +36,19 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti response.addVersion(request.getVersion()); response.addStatusCode(302); response.addStatusMessage("FOUND"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); - response.addHeader("Location", "/index.html"); - response.addHeader("Set-Cookie", "JSESSIONID=" + jSessionId); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); + response.addHeader(HttpHeaders.LOCATION, "/index.html"); + response.addHeader(HttpHeaders.SET_COOKIE, "JSESSIONID=" + jSessionId); response.addBody(responseBody); } else { response.addVersion(request.getVersion()); response.addStatusCode(302); response.addStatusMessage("FOUND"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); - response.addHeader("Location", "/401.html"); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); + response.addHeader(HttpHeaders.LOCATION, "/401.html"); response.addBody(responseBody); } } @@ -56,9 +57,9 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti protected void doGet(HttpRequest request, HttpResponse response) throws Exception { Map headers = request.getHeaders(); String responseBody = new String(request.toHttpResponseBody()); - if (headers.containsKey("Cookie") && - headers.get("Cookie").startsWith("JSESSIONID=")) { - String jSessionId = headers.get("Cookie").split("=")[1]; + if (headers.containsKey(HttpHeaders.COOKIE) && + headers.get(HttpHeaders.COOKIE).startsWith("JSESSIONID=")) { + String jSessionId = headers.get(HttpHeaders.COOKIE).split("=")[1]; Session session = sessionManager.findSession(jSessionId); if (session != null && session.getAttribute("user") != null) { @@ -66,24 +67,24 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio response.addVersion(request.getVersion()); response.addStatusCode(302); response.addStatusMessage("FOUND"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); - response.addHeader("Location", "/index.html"); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); + response.addHeader(HttpHeaders.LOCATION, "/index.html"); response.addBody(responseBody); } else { response.addVersion(request.getVersion()); response.addStatusCode(200); response.addStatusMessage("OK"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); } } else { response.addVersion(request.getVersion()); response.addStatusCode(200); response.addStatusMessage("OK"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); } } diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java index 6fc65746dc..f299049cfb 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -2,6 +2,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; +import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -20,9 +21,9 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti response.addVersion(request.getVersion()); response.addStatusCode(302); response.addStatusMessage("FOUND"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); - response.addHeader("Location", "/index.html"); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); + response.addHeader(HttpHeaders.LOCATION, "/index.html"); response.addBody(responseBody); } @@ -33,8 +34,8 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio response.addVersion(request.getVersion()); response.addStatusCode(200); response.addStatusMessage("OK"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); } } diff --git a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java index 6aa4c81cc6..22dbd6f258 100644 --- a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java +++ b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java @@ -1,5 +1,6 @@ package com.techcourse.controller; +import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -12,8 +13,8 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio response.addVersion(request.getVersion()); response.addStatusCode(200); response.addStatusMessage("OK"); - response.addHeader("Content-Type", request.getContentType()); - response.addHeader("Content-Length", responseBody.getBytes().length); + response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); + response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java new file mode 100644 index 0000000000..317dbadf0e --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java @@ -0,0 +1,10 @@ +package org.apache.coyote.http11; + +public class HttpHeaders { + + public static String CONTENT_LENGTH = "Content-Length"; + public static String CONTENT_TYPE = "Content-Type"; + public static String COOKIE = "Cookie"; + public static String LOCATION = "Location"; + public static String SET_COOKIE = "Set-Cookie"; +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 90ebbf0580..0704a25b9b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,5 +1,6 @@ package org.apache.coyote.http11.request; +import org.apache.coyote.http11.HttpHeaders; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -49,7 +50,7 @@ public static HttpRequest from(InputStream inputStream) throws IOException { } if (method.equals("POST")) { - int contentLength = Integer.parseInt(headers.get("Content-Length")); + int contentLength = Integer.parseInt(headers.get(HttpHeaders.CONTENT_LENGTH)); char[] buffer = new char[contentLength]; bufferedReader.read(buffer, 0, contentLength); String body = new String(buffer); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index 3d235fd025..d715871cc2 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -27,15 +27,6 @@ public HttpResponse() { headers = new HashMap<>(); } - public static HttpResponse of(String version, int statusCode, String statusMessage, - String contentType, String body) { - Map headers = new HashMap<>(); - headers.put("Content-Type", contentType + ";charset=utf-8"); - headers.put("Content-Length", body.getBytes().length); - - return new HttpResponse(version, statusCode, statusMessage, headers, body); - } - public void addVersion(String version) { this.version = version; } From 424b3a830ed8b33348374d32d99d69aa5db5eaaf Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Tue, 10 Sep 2024 18:52:38 +0900 Subject: [PATCH 07/22] =?UTF-8?q?feat:=20HttpMethod=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http11/HttpMethod.java | 32 +++++++++++++++++++ .../coyote/http11/request/HttpRequest.java | 15 +++++---- 2 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/HttpMethod.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpMethod.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpMethod.java new file mode 100644 index 0000000000..ca1447799a --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpMethod.java @@ -0,0 +1,32 @@ +package org.apache.coyote.http11; + +import java.util.Arrays; + +public enum HttpMethod { + + GET("GET"), + POST("POST"), + PUT("PUT"), + DELETE("DELETE"); + + private final String method; + + HttpMethod(String method) { + this.method = method; + } + + public static HttpMethod from(String method) { + return Arrays.stream(HttpMethod.values()) + .filter(hm -> hm.method.equals(method)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("알 수 없는 HttpMethod 입니다." + method)); + } + + public boolean isPost() { + return this.equals(POST); + } + + public boolean isGet() { + return this.equals(GET); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 0704a25b9b..1893ad730c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,6 +1,7 @@ package org.apache.coyote.http11.request; import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.HttpMethod; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -16,13 +17,13 @@ public class HttpRequest { private static final String HEADER_SPLIT_DELIMITER = ": "; - private final String method; + private final HttpMethod method; private final String path; private final String version; private final Map headers; private final String body; - public HttpRequest(String method, String path, String version, Map headers, String body) { + public HttpRequest(HttpMethod method, String path, String version, Map headers, String body) { this.method = method; this.path = path; this.version = version; @@ -35,7 +36,7 @@ public static HttpRequest from(InputStream inputStream) throws IOException { String startLine = bufferedReader.readLine(); String[] parsedStartLine = HttpRequestParser.parseStartLine(startLine); - String method = parsedStartLine[0]; + HttpMethod method = HttpMethod.from(parsedStartLine[0]); String path = parsedStartLine[1]; String version = parsedStartLine[2]; @@ -49,7 +50,7 @@ public static HttpRequest from(InputStream inputStream) throws IOException { headers.put(headerParts[0], headerParts[1]); } - if (method.equals("POST")) { + if (method.isPost()) { int contentLength = Integer.parseInt(headers.get(HttpHeaders.CONTENT_LENGTH)); char[] buffer = new char[contentLength]; bufferedReader.read(buffer, 0, contentLength); @@ -61,11 +62,11 @@ public static HttpRequest from(InputStream inputStream) throws IOException { } public boolean isGet() { - return method.equals("GET"); + return method.isGet(); } public boolean isPost() { - return method.equals("POST"); + return method.isPost(); } public byte[] toHttpResponseBody() throws URISyntaxException, IOException { @@ -98,7 +99,7 @@ public String getContentType() { return "text/html;charset=utf-8"; } - public String getHttpMethod() { + public HttpMethod getHttpMethod() { return method; } From 716f7fc0a28a12c37adafa6ff45b89bb5ef996e8 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Tue, 10 Sep 2024 19:04:51 +0900 Subject: [PATCH 08/22] =?UTF-8?q?feat:=20HttpStatus=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 16 +++++-------- .../controller/RegisterController.java | 7 +++--- .../controller/StaticResourceController.java | 4 ++-- .../java/org/apache/coyote/HttpStatus.java | 24 +++++++++++++++++++ .../coyote/http11/response/HttpResponse.java | 21 +++++++--------- 5 files changed, 43 insertions(+), 29 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/HttpStatus.java diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index d06c3170ad..48dbf24cc3 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -2,6 +2,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; +import org.apache.coyote.HttpStatus; import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.Session; import org.apache.coyote.http11.SessionManager; @@ -34,8 +35,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti sessionManager.add(session); response.addVersion(request.getVersion()); - response.addStatusCode(302); - response.addStatusMessage("FOUND"); + response.addHttpStatus(HttpStatus.FOUND); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/index.html"); @@ -44,8 +44,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti } else { response.addVersion(request.getVersion()); - response.addStatusCode(302); - response.addStatusMessage("FOUND"); + response.addHttpStatus(HttpStatus.FOUND); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/401.html"); @@ -65,24 +64,21 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio if (session != null && session.getAttribute("user") != null) { response.addVersion(request.getVersion()); - response.addStatusCode(302); - response.addStatusMessage("FOUND"); + response.addHttpStatus(HttpStatus.FOUND); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/index.html"); response.addBody(responseBody); } else { response.addVersion(request.getVersion()); - response.addStatusCode(200); - response.addStatusMessage("OK"); + response.addHttpStatus(HttpStatus.OK); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); } } else { response.addVersion(request.getVersion()); - response.addStatusCode(200); - response.addStatusMessage("OK"); + response.addHttpStatus(HttpStatus.OK); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java index f299049cfb..6c09f6c87d 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -2,6 +2,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; +import org.apache.coyote.HttpStatus; import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -19,8 +20,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti String responseBody = new String(request.toHttpResponseBody()); response.addVersion(request.getVersion()); - response.addStatusCode(302); - response.addStatusMessage("FOUND"); + response.addHttpStatus(HttpStatus.FOUND); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/index.html"); @@ -32,8 +32,7 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio String responseBody = new String(request.toHttpResponseBody()); response.addVersion(request.getVersion()); - response.addStatusCode(200); - response.addStatusMessage("OK"); + response.addHttpStatus(HttpStatus.OK); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); diff --git a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java index 22dbd6f258..eed551247c 100644 --- a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java +++ b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java @@ -1,5 +1,6 @@ package com.techcourse.controller; +import org.apache.coyote.HttpStatus; import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -11,8 +12,7 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio String responseBody = new String(request.toHttpResponseBody()); response.addVersion(request.getVersion()); - response.addStatusCode(200); - response.addStatusMessage("OK"); + response.addHttpStatus(HttpStatus.OK); response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addBody(responseBody); diff --git a/tomcat/src/main/java/org/apache/coyote/HttpStatus.java b/tomcat/src/main/java/org/apache/coyote/HttpStatus.java new file mode 100644 index 0000000000..cb9514968f --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/HttpStatus.java @@ -0,0 +1,24 @@ +package org.apache.coyote; + +public enum HttpStatus { + + OK(200, "OK"), + FOUND(302, "FOUND"); + + private final int code; + private final String message; + + + HttpStatus(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index d715871cc2..aee4437aba 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -1,5 +1,6 @@ package org.apache.coyote.http11.response; +import org.apache.coyote.HttpStatus; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; @@ -9,16 +10,13 @@ public class HttpResponse { private String version; - private int statusCode; - private String statusMessage; + private HttpStatus httpStatus; private Map headers; private String body; - public HttpResponse(String version, int statusCode, String statusMessage, Map headers, - String body) { + public HttpResponse(String version, HttpStatus httpStatus, Map headers, String body) { this.version = version; - this.statusCode = statusCode; - this.statusMessage = statusMessage; + this.httpStatus = httpStatus; this.headers = headers; this.body = body; } @@ -31,12 +29,8 @@ public void addVersion(String version) { this.version = version; } - public void addStatusCode(int statusCode) { - this.statusCode = statusCode; - } - - public void addStatusMessage(String statusMessage) { - this.statusMessage = statusMessage; + public void addHttpStatus(HttpStatus httpStatus) { + this.httpStatus = httpStatus; } public void addHeader(String key, Object value) { @@ -50,7 +44,8 @@ public void addBody(String body) { public void send(OutputStream outputStream) { try { StringBuilder sb = new StringBuilder(); - sb.append(version).append(" ").append(statusCode).append(" ").append(statusMessage).append(" \r\n"); + sb.append(version).append(" ").append(httpStatus.getCode()) + .append(" ").append(httpStatus.getMessage()).append(" \r\n"); for (Entry entry : headers.entrySet()) { sb.append(entry.getKey()); sb.append(": "); From 7463dad4890c53531d3ed93054701eab8cd77fd4 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Tue, 10 Sep 2024 19:06:07 +0900 Subject: [PATCH 09/22] =?UTF-8?q?feat:=20jSessionId=20=EC=83=81=EC=88=98?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/controller/LoginController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index 48dbf24cc3..cd58b1f6c7 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -17,6 +17,7 @@ public class LoginController extends AbstractController { private static final Logger log = LoggerFactory.getLogger(LoginController.class); private static final SessionManager sessionManager = new SessionManager(); + private static final String JSESSIONID = "JSESSIONID="; @Override protected void doPost(HttpRequest request, HttpResponse response) throws Exception { @@ -39,7 +40,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/index.html"); - response.addHeader(HttpHeaders.SET_COOKIE, "JSESSIONID=" + jSessionId); + response.addHeader(HttpHeaders.SET_COOKIE, JSESSIONID + jSessionId); response.addBody(responseBody); } else { @@ -57,7 +58,7 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio Map headers = request.getHeaders(); String responseBody = new String(request.toHttpResponseBody()); if (headers.containsKey(HttpHeaders.COOKIE) && - headers.get(HttpHeaders.COOKIE).startsWith("JSESSIONID=")) { + headers.get(HttpHeaders.COOKIE).startsWith(JSESSIONID)) { String jSessionId = headers.get(HttpHeaders.COOKIE).split("=")[1]; Session session = sessionManager.findSession(jSessionId); From 9382bcb04409f3f0d95bbf5e496b2d46ff25e351 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Wed, 11 Sep 2024 11:26:45 +0900 Subject: [PATCH 10/22] =?UTF-8?q?refactor:=20request=EB=A5=BC=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=20response=EC=9D=98=20=EA=B0=92=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 28 ++++--------------- .../controller/RegisterController.java | 13 ++------- .../controller/StaticResourceController.java | 8 +----- .../coyote/http11/response/HttpResponse.java | 22 ++++++--------- 4 files changed, 17 insertions(+), 54 deletions(-) diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index cd58b1f6c7..0b4f2da2d3 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -26,7 +26,6 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti String password = requestBody.split("&")[1].split("=")[1]; User user = InMemoryUserRepository.findByAccount(account).get(); - String responseBody = new String(request.toHttpResponseBody()); if (user.checkPassword(password)) { log.info("user : {}", user); @@ -35,54 +34,37 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti session.setAttribute("user", user); sessionManager.add(session); - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/index.html"); response.addHeader(HttpHeaders.SET_COOKIE, JSESSIONID + jSessionId); - response.addBody(responseBody); } else { - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/401.html"); - response.addBody(responseBody); } } @Override protected void doGet(HttpRequest request, HttpResponse response) throws Exception { Map headers = request.getHeaders(); - String responseBody = new String(request.toHttpResponseBody()); if (headers.containsKey(HttpHeaders.COOKIE) && headers.get(HttpHeaders.COOKIE).startsWith(JSESSIONID)) { String jSessionId = headers.get(HttpHeaders.COOKIE).split("=")[1]; Session session = sessionManager.findSession(jSessionId); if (session != null && session.getAttribute("user") != null) { - - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/index.html"); - response.addBody(responseBody); } else { - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.OK); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); - response.addBody(responseBody); } } else { - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.OK); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); - response.addBody(responseBody); } } } diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java index 6c09f6c87d..ec01125cac 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -17,24 +17,15 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti String password = requestBody.split("&")[2].split("=")[1]; InMemoryUserRepository.save(new User(account, password, email)); - String responseBody = new String(request.toHttpResponseBody()); - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); response.addHeader(HttpHeaders.LOCATION, "/index.html"); - response.addBody(responseBody); } @Override protected void doGet(HttpRequest request, HttpResponse response) throws Exception { - String responseBody = new String(request.toHttpResponseBody()); - - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.OK); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); - response.addBody(responseBody); } } diff --git a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java index eed551247c..7e83c07da5 100644 --- a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java +++ b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java @@ -1,7 +1,6 @@ package com.techcourse.controller; import org.apache.coyote.HttpStatus; -import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -9,12 +8,7 @@ public class StaticResourceController extends AbstractController { @Override protected void doGet(HttpRequest request, HttpResponse response) throws Exception { - String responseBody = new String(request.toHttpResponseBody()); - - response.addVersion(request.getVersion()); + response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.OK); - response.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType()); - response.addHeader(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); - response.addBody(responseBody); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index aee4437aba..644010275d 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -1,8 +1,11 @@ package org.apache.coyote.http11.response; import org.apache.coyote.HttpStatus; +import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; import java.io.IOException; import java.io.OutputStream; +import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -14,19 +17,16 @@ public class HttpResponse { private Map headers; private String body; - public HttpResponse(String version, HttpStatus httpStatus, Map headers, String body) { - this.version = version; - this.httpStatus = httpStatus; - this.headers = headers; - this.body = body; - } - public HttpResponse() { headers = new HashMap<>(); } - public void addVersion(String version) { - this.version = version; + public void setResponseFromRequest(HttpRequest request) throws URISyntaxException, IOException { + String responseBody = new String(request.toHttpResponseBody()); + version = request.getVersion(); + headers.put(HttpHeaders.CONTENT_TYPE, request.getContentType()); + headers.put(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); + body = responseBody; } public void addHttpStatus(HttpStatus httpStatus) { @@ -37,10 +37,6 @@ public void addHeader(String key, Object value) { headers.put(key, value); } - public void addBody(String body) { - this.body = body; - } - public void send(OutputStream outputStream) { try { StringBuilder sb = new StringBuilder(); From dfaa460399e3b16e5e9d03ce7c520b2836890a1b Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Wed, 11 Sep 2024 12:38:01 +0900 Subject: [PATCH 11/22] =?UTF-8?q?refactor:=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/request/HttpRequest.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 1893ad730c..9988654961 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -16,6 +16,10 @@ public class HttpRequest { private static final String HEADER_SPLIT_DELIMITER = ": "; + private static final String STATIC = "static"; + private static final String CSS = ".css"; + private static final String JS = ".js"; + private static final String HTML = ".html"; private final HttpMethod method; private final String path; @@ -81,19 +85,19 @@ public byte[] toHttpResponseBody() throws URISyntaxException, IOException { private String loadResourceName(String path) { if (path.equals("/")) { - return "static/index.html"; + return STATIC + "/index.html"; } - if (!path.endsWith(".html") && !path.contains(".")) { - return "static" + path + ".html"; + if (!path.endsWith(HTML) && !path.contains(".")) { + return STATIC + path + ".html"; } - return "static" + path; + return STATIC + path; } public String getContentType() { - if (path.endsWith(".css")) { + if (path.endsWith(CSS)) { return "text/css"; } - if (path.endsWith(".js")) { + if (path.endsWith(JS)) { return "text/javascript"; } return "text/html;charset=utf-8"; From 8c04db9dbd8ce9d77153b1283aff8f562608d82a Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Wed, 11 Sep 2024 12:41:16 +0900 Subject: [PATCH 12/22] =?UTF-8?q?feat:=20contentType=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/http11/ContentType.java | 8 ++++++++ .../org/apache/coyote/http11/request/HttpRequest.java | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/ContentType.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/ContentType.java b/tomcat/src/main/java/org/apache/coyote/http11/ContentType.java new file mode 100644 index 0000000000..991303b15c --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/ContentType.java @@ -0,0 +1,8 @@ +package org.apache.coyote.http11; + +public class ContentType { + + public static final String CSS = "text/css"; + public static final String HTML = "text/html;charset=utf-8"; + public static final String JAVASCRIPT = "text/javascript"; +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 9988654961..2f845afc3f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -95,12 +95,12 @@ private String loadResourceName(String path) { public String getContentType() { if (path.endsWith(CSS)) { - return "text/css"; + return ContentType.CSS; } if (path.endsWith(JS)) { - return "text/javascript"; + return ContentType.JAVASCRIPT; } - return "text/html;charset=utf-8"; + return ContentType.HTML; } public HttpMethod getHttpMethod() { From a3b53db1e041f1d8b7272b6316ae6dfed7674544 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Wed, 11 Sep 2024 12:41:43 +0900 Subject: [PATCH 13/22] =?UTF-8?q?refactor:=20HttpStatus=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4=EC=A7=80=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 --- .../main/java/com/techcourse/controller/LoginController.java | 2 +- .../main/java/com/techcourse/controller/RegisterController.java | 2 +- .../com/techcourse/controller/StaticResourceController.java | 2 +- .../main/java/org/apache/coyote/{ => http11}/HttpStatus.java | 2 +- .../main/java/org/apache/coyote/http11/request/HttpRequest.java | 1 + .../java/org/apache/coyote/http11/response/HttpResponse.java | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) rename tomcat/src/main/java/org/apache/coyote/{ => http11}/HttpStatus.java (91%) diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index 0b4f2da2d3..2959bece79 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -2,7 +2,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -import org.apache.coyote.HttpStatus; +import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.Session; import org.apache.coyote.http11.SessionManager; diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java index ec01125cac..89202a4918 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -2,7 +2,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -import org.apache.coyote.HttpStatus; +import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; diff --git a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java index 7e83c07da5..0b00071e41 100644 --- a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java +++ b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java @@ -1,6 +1,6 @@ package com.techcourse.controller; -import org.apache.coyote.HttpStatus; +import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; diff --git a/tomcat/src/main/java/org/apache/coyote/HttpStatus.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpStatus.java similarity index 91% rename from tomcat/src/main/java/org/apache/coyote/HttpStatus.java rename to tomcat/src/main/java/org/apache/coyote/http11/HttpStatus.java index cb9514968f..6634e5ccaa 100644 --- a/tomcat/src/main/java/org/apache/coyote/HttpStatus.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpStatus.java @@ -1,4 +1,4 @@ -package org.apache.coyote; +package org.apache.coyote.http11; public enum HttpStatus { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 2f845afc3f..d92e660f22 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,5 +1,6 @@ package org.apache.coyote.http11.request; +import org.apache.coyote.http11.ContentType; import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.HttpMethod; import java.io.BufferedReader; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index 644010275d..a6e5c2465f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -1,6 +1,6 @@ package org.apache.coyote.http11.response; -import org.apache.coyote.HttpStatus; +import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import java.io.IOException; From 2b6c49b9639eb459ef4612668a637f2ec46bd162 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Thu, 12 Sep 2024 14:17:25 +0900 Subject: [PATCH 14/22] =?UTF-8?q?refactor:=20httpRequest=EC=9D=98=20reques?= =?UTF-8?q?tLine=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/request/HttpRequest.java | 47 +++++++---------- .../http11/request/HttpRequestLine.java | 52 +++++++++++++++++++ .../http11/request/HttpRequestParser.java | 12 ----- 3 files changed, 70 insertions(+), 41 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index d92e660f22..545005026b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -22,62 +22,51 @@ public class HttpRequest { private static final String JS = ".js"; private static final String HTML = ".html"; - private final HttpMethod method; - private final String path; - private final String version; + private final HttpRequestLine httpRequestLine; private final Map headers; private final String body; - public HttpRequest(HttpMethod method, String path, String version, Map headers, String body) { - this.method = method; - this.path = path; - this.version = version; + public HttpRequest(HttpRequestLine httpRequestLine, Map headers, String body) { + this.httpRequestLine = httpRequestLine; this.headers = headers; this.body = body; } public static HttpRequest from(InputStream inputStream) throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); - String startLine = bufferedReader.readLine(); - String[] parsedStartLine = HttpRequestParser.parseStartLine(startLine); - HttpMethod method = HttpMethod.from(parsedStartLine[0]); - String path = parsedStartLine[1]; - String version = parsedStartLine[2]; + HttpRequestLine requestLine = HttpRequestLine.from(bufferedReader.readLine()); Map headers = new HashMap<>(); - while (!startLine.isEmpty()) { - String line = bufferedReader.readLine(); - if (line.isEmpty()) { - break; - } + String line; + while ((line = bufferedReader.readLine()) != null && !line.isEmpty()) { String[] headerParts = line.split(HEADER_SPLIT_DELIMITER, 2); headers.put(headerParts[0], headerParts[1]); } - if (method.isPost()) { + if (requestLine.isPost()) { int contentLength = Integer.parseInt(headers.get(HttpHeaders.CONTENT_LENGTH)); char[] buffer = new char[contentLength]; bufferedReader.read(buffer, 0, contentLength); String body = new String(buffer); - return new HttpRequest(method, path, version, headers, body); + return new HttpRequest(requestLine, headers, body); } - return new HttpRequest(method, path, version, headers, null); + return new HttpRequest(requestLine, headers, null); } public boolean isGet() { - return method.isGet(); + return httpRequestLine.isGet(); } public boolean isPost() { - return method.isPost(); + return httpRequestLine.isPost(); } public byte[] toHttpResponseBody() throws URISyntaxException, IOException { - URL url = getClass().getClassLoader().getResource(loadResourceName(path)); + URL url = getClass().getClassLoader().getResource(loadResourceName(httpRequestLine.getPath())); if (url == null) { - throw new IllegalArgumentException("존재하지 않는 리소스 입니다." + path); + throw new IllegalArgumentException("존재하지 않는 리소스 입니다." + httpRequestLine.getPath()); } Path path = Path.of(url.toURI()); @@ -95,25 +84,25 @@ private String loadResourceName(String path) { } public String getContentType() { - if (path.endsWith(CSS)) { + if (httpRequestLine.getPath().endsWith(CSS)) { return ContentType.CSS; } - if (path.endsWith(JS)) { + if (httpRequestLine.getPath().endsWith(JS)) { return ContentType.JAVASCRIPT; } return ContentType.HTML; } public HttpMethod getHttpMethod() { - return method; + return httpRequestLine.getMethod(); } public String getPath() { - return path; + return httpRequestLine.getPath(); } public String getVersion() { - return version; + return httpRequestLine.getVersion(); } public Map getHeaders() { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java new file mode 100644 index 0000000000..9d36df9ed3 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java @@ -0,0 +1,52 @@ +package org.apache.coyote.http11.request; + +import org.apache.coyote.http11.HttpMethod; + +public class HttpRequestLine { + + private final HttpMethod method; + private final String path; + private final String version; + + public HttpRequestLine(HttpMethod method, String path, String version) { + this.method = method; + this.path = path; + this.version = version; + } + + public static HttpRequestLine from(String requestLine) { + String[] parsedStartLine = parseRequestLine(requestLine); + HttpMethod method = HttpMethod.from(parsedStartLine[0]); + String path = parsedStartLine[1]; + String version = parsedStartLine[2]; + return new HttpRequestLine(method, path, version); + } + + private static String[] parseRequestLine(String requestLine) { + String[] parsedRequestLine = requestLine.split(" "); + if (parsedRequestLine.length != 3) { + throw new IllegalArgumentException("Invalid request line: " + requestLine); + } + return parsedRequestLine; + } + + public boolean isGet() { + return method == HttpMethod.GET; + } + + public boolean isPost() { + return method == HttpMethod.POST; + } + + public HttpMethod getMethod() { + return method; + } + + public String getPath() { + return path; + } + + public String getVersion() { + return version; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java deleted file mode 100644 index 9e04e37860..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.apache.coyote.http11.request; - -public class HttpRequestParser { - - public static String[] parseStartLine(String startLine) { - String[] parsedStartLine = startLine.split(" "); - if (parsedStartLine.length != 3) { - throw new IllegalArgumentException("Invalid start line: " + startLine); - } - return parsedStartLine; - } -} From 9e0f1bb60ebf83d5d0013a42cdee0c3245fad7b7 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Thu, 12 Sep 2024 19:42:23 +0900 Subject: [PATCH 15/22] =?UTF-8?q?test:=20FileTest,=20IOStreamTest=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 --- study/src/test/java/study/FileTest.java | 14 ++- study/src/test/java/study/IOStreamTest.java | 126 ++++++++++---------- 2 files changed, 73 insertions(+), 67 deletions(-) diff --git a/study/src/test/java/study/FileTest.java b/study/src/test/java/study/FileTest.java index e1b6cca042..7e10aa4cba 100644 --- a/study/src/test/java/study/FileTest.java +++ b/study/src/test/java/study/FileTest.java @@ -3,7 +3,11 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; import java.util.List; @@ -28,7 +32,7 @@ class FileTest { final String fileName = "nextstep.txt"; // todo - final String actual = ""; + final String actual = getClass().getClassLoader().getResource(fileName).getFile(); assertThat(actual).endsWith(fileName); } @@ -40,14 +44,16 @@ class FileTest { * File, Files 클래스를 사용하여 파일의 내용을 읽어보자. */ @Test - void 파일의_내용을_읽는다() { + void 파일의_내용을_읽는다() throws IOException { final String fileName = "nextstep.txt"; // todo - final Path path = null; + URL url = getClass().getClassLoader().getResource(fileName); + final Path path = Path.of(url.getPath()); // todo - final List actual = Collections.emptyList(); + final List actual = Files.readAllLines(path); + assertThat(actual).containsOnly("nextstep"); } diff --git a/study/src/test/java/study/IOStreamTest.java b/study/src/test/java/study/IOStreamTest.java index 47a79356b6..9176fa64dc 100644 --- a/study/src/test/java/study/IOStreamTest.java +++ b/study/src/test/java/study/IOStreamTest.java @@ -3,43 +3,48 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; - -import java.io.*; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; /** - * 자바는 스트림(Stream)으로부터 I/O를 사용한다. - * 입출력(I/O)은 하나의 시스템에서 다른 시스템으로 데이터를 이동 시킬 때 사용한다. - * - * InputStream은 데이터를 읽고, OutputStream은 데이터를 쓴다. - * FilterStream은 InputStream이나 OutputStream에 연결될 수 있다. - * FilterStream은 읽거나 쓰는 데이터를 수정할 때 사용한다. (e.g. 암호화, 압축, 포맷 변환) - * - * Stream은 데이터를 바이트로 읽고 쓴다. - * 바이트가 아닌 텍스트(문자)를 읽고 쓰려면 Reader와 Writer 클래스를 연결한다. - * Reader, Writer는 다양한 문자 인코딩(e.g. UTF-8)을 처리할 수 있다. + * 자바는 스트림(Stream)으로부터 I/O를 사용한다. 입출력(I/O)은 하나의 시스템에서 다른 시스템으로 데이터를 이동 시킬 때 사용한다. + *

+ * InputStream은 데이터를 읽고, OutputStream은 데이터를 쓴다. FilterStream은 InputStream이나 OutputStream에 연결될 수 있다. FilterStream은 읽거나 쓰는 + * 데이터를 수정할 때 사용한다. (e.g. 암호화, 압축, 포맷 변환) + *

+ * Stream은 데이터를 바이트로 읽고 쓴다. 바이트가 아닌 텍스트(문자)를 읽고 쓰려면 Reader와 Writer 클래스를 연결한다. Reader, Writer는 다양한 문자 인코딩(e.g. UTF-8)을 + * 처리할 수 있다. */ @DisplayName("Java I/O Stream 클래스 학습 테스트") class IOStreamTest { /** * OutputStream 학습하기 - * - * 자바의 기본 출력 클래스는 java.io.OutputStream이다. - * OutputStream의 write(int b) 메서드는 기반 메서드이다. + *

+ * 자바의 기본 출력 클래스는 java.io.OutputStream이다. OutputStream의 write(int b) 메서드는 기반 메서드이다. * public abstract void write(int b) throws IOException; */ @Nested class OutputStream_학습_테스트 { /** - * OutputStream은 다른 매체에 바이트로 데이터를 쓸 때 사용한다. - * OutputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 쓰기 위해 write(int b) 메서드를 사용한다. - * 예를 들어, FilterOutputStream은 파일로 데이터를 쓸 때, - * 또는 DataOutputStream은 자바의 primitive type data를 다른 매체로 데이터를 쓸 때 사용한다. - * + * OutputStream은 다른 매체에 바이트로 데이터를 쓸 때 사용한다. OutputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 쓰기 위해 write(int b) 메서드를 + * 사용한다. 예를 들어, FilterOutputStream은 파일로 데이터를 쓸 때, 또는 DataOutputStream은 자바의 primitive type data를 다른 매체로 데이터를 쓸 때 + * 사용한다. + *

* write 메서드는 데이터를 바이트로 출력하기 때문에 비효율적이다. * write(byte[] data)write(byte b[], int off, int len) 메서드는 * 1바이트 이상을 한 번에 전송 할 수 있어 훨씬 효율적이다. @@ -53,7 +58,7 @@ class OutputStream_학습_테스트 { * todo * OutputStream 객체의 write 메서드를 사용해서 테스트를 통과시킨다 */ - + outputStream.write(bytes); final String actual = outputStream.toString(); assertThat(actual).isEqualTo("nextstep"); @@ -61,13 +66,10 @@ class OutputStream_학습_테스트 { } /** - * 효율적인 전송을 위해 스트림에서 버퍼링을 사용 할 수 있다. - * BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다. - * - * 버퍼링을 사용하면 OutputStream을 사용할 때 flush를 사용하자. - * flush() 메서드는 버퍼가 아직 가득 차지 않은 상황에서 강제로 버퍼의 내용을 전송한다. - * Stream은 동기(synchronous)로 동작하기 때문에 버퍼가 찰 때까지 기다리면 - * 데드락(deadlock) 상태가 되기 때문에 flush로 해제해야 한다. + * 효율적인 전송을 위해 스트림에서 버퍼링을 사용 할 수 있다. BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다. + *

+ * 버퍼링을 사용하면 OutputStream을 사용할 때 flush를 사용하자. flush() 메서드는 버퍼가 아직 가득 차지 않은 상황에서 강제로 버퍼의 내용을 전송한다. Stream은 + * 동기(synchronous)로 동작하기 때문에 버퍼가 찰 때까지 기다리면 데드락(deadlock) 상태가 되기 때문에 flush로 해제해야 한다. */ @Test void BufferedOutputStream을_사용하면_버퍼링이_가능하다() throws IOException { @@ -77,15 +79,15 @@ class OutputStream_학습_테스트 { * todo * flush를 사용해서 테스트를 통과시킨다. * ByteArrayOutputStream과 어떤 차이가 있을까? - */ + */; + outputStream.flush(); verify(outputStream, atLeastOnce()).flush(); outputStream.close(); } /** - * 스트림 사용이 끝나면 항상 close() 메서드를 호출하여 스트림을 닫는다. - * 장시간 스트림을 닫지 않으면 파일, 포트 등 다양한 리소스에서 누수(leak)가 발생한다. + * 스트림 사용이 끝나면 항상 close() 메서드를 호출하여 스트림을 닫는다. 장시간 스트림을 닫지 않으면 파일, 포트 등 다양한 리소스에서 누수(leak)가 발생한다. */ @Test void OutputStream은_사용하고_나서_close_처리를_해준다() throws IOException { @@ -97,26 +99,25 @@ class OutputStream_학습_테스트 { * java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다. */ + outputStream.close(); verify(outputStream, atLeastOnce()).close(); } } /** * InputStream 학습하기 - * - * 자바의 기본 입력 클래스는 java.io.InputStream이다. - * InputStream은 다른 매체로부터 바이트로 데이터를 읽을 때 사용한다. - * InputStream의 read() 메서드는 기반 메서드이다. + *

+ * 자바의 기본 입력 클래스는 java.io.InputStream이다. InputStream은 다른 매체로부터 바이트로 데이터를 읽을 때 사용한다. InputStream의 read() 메서드는 기반 + * 메서드이다. * public abstract int read() throws IOException; - * + *

* InputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 읽기 위해 read() 메서드를 사용한다. */ @Nested class InputStream_학습_테스트 { /** - * read() 메서드는 매체로부터 단일 바이트를 읽는데, 0부터 255 사이의 값을 int 타입으로 반환한다. - * int 값을 byte 타입으로 변환하면 -128부터 127 사이의 값으로 변환된다. + * read() 메서드는 매체로부터 단일 바이트를 읽는데, 0부터 255 사이의 값을 int 타입으로 반환한다. int 값을 byte 타입으로 변환하면 -128부터 127 사이의 값으로 변환된다. * 그리고 Stream 끝에 도달하면 -1을 반환한다. */ @Test @@ -128,7 +129,8 @@ class InputStream_학습_테스트 { * todo * inputStream에서 바이트로 반환한 값을 문자열로 어떻게 바꿀까? */ - final String actual = ""; + + String actual = new String(inputStream.readAllBytes()); assertThat(actual).isEqualTo("🤩"); assertThat(inputStream.read()).isEqualTo(-1); @@ -136,8 +138,7 @@ class InputStream_학습_테스트 { } /** - * 스트림 사용이 끝나면 항상 close() 메서드를 호출하여 스트림을 닫는다. - * 장시간 스트림을 닫지 않으면 파일, 포트 등 다양한 리소스에서 누수(leak)가 발생한다. + * 스트림 사용이 끝나면 항상 close() 메서드를 호출하여 스트림을 닫는다. 장시간 스트림을 닫지 않으면 파일, 포트 등 다양한 리소스에서 누수(leak)가 발생한다. */ @Test void InputStream은_사용하고_나서_close_처리를_해준다() throws IOException { @@ -148,33 +149,32 @@ class InputStream_학습_테스트 { * try-with-resources를 사용한다. * java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다. */ - + inputStream.close(); verify(inputStream, atLeastOnce()).close(); } } /** * FilterStream 학습하기 - * - * 필터는 필터 스트림, reader, writer로 나뉜다. - * 필터는 바이트를 다른 데이터 형식으로 변환 할 때 사용한다. - * reader, writer는 UTF-8, ISO 8859-1 같은 형식으로 인코딩된 텍스트를 처리하는 데 사용된다. + *

+ * 필터는 필터 스트림, reader, writer로 나뉜다. 필터는 바이트를 다른 데이터 형식으로 변환 할 때 사용한다. reader, writer는 UTF-8, ISO 8859-1 같은 형식으로 인코딩된 + * 텍스트를 처리하는 데 사용된다. */ @Nested class FilterStream_학습_테스트 { /** - * BufferedInputStream은 데이터 처리 속도를 높이기 위해 데이터를 버퍼에 저장한다. - * InputStream 객체를 생성하고 필터 생성자에 전달하면 필터에 연결된다. - * 버퍼 크기를 지정하지 않으면 버퍼의 기본 사이즈는 얼마일까? + * BufferedInputStream은 데이터 처리 속도를 높이기 위해 데이터를 버퍼에 저장한다. InputStream 객체를 생성하고 필터 생성자에 전달하면 필터에 연결된다. 버퍼 크기를 지정하지 + * 않으면 버퍼의 기본 사이즈는 얼마일까? */ @Test - void 필터인_BufferedInputStream를_사용해보자() { + void 필터인_BufferedInputStream를_사용해보자() throws IOException { final String text = "필터에 연결해보자."; final InputStream inputStream = new ByteArrayInputStream(text.getBytes()); - final InputStream bufferedInputStream = null; + final InputStream bufferedInputStream = new BufferedInputStream(inputStream); - final byte[] actual = new byte[0]; + final byte[] actual = new byte[text.getBytes().length]; + bufferedInputStream.read(actual); assertThat(bufferedInputStream).isInstanceOf(FilterInputStream.class); assertThat(actual).isEqualTo("필터에 연결해보자.".getBytes()); @@ -182,31 +182,31 @@ class FilterStream_학습_테스트 { } /** - * 자바의 기본 문자열은 UTF-16 유니코드 인코딩을 사용한다. - * 문자열이 아닌 바이트 단위로 처리하려니 불편하다. - * 그리고 바이트를 문자(char)로 처리하려면 인코딩을 신경 써야 한다. - * reader, writer를 사용하면 입출력 스트림을 바이트가 아닌 문자 단위로 데이터를 처리하게 된다. - * 그리고 InputStreamReader를 사용하면 지정된 인코딩에 따라 유니코드 문자로 변환할 수 있다. + * 자바의 기본 문자열은 UTF-16 유니코드 인코딩을 사용한다. 문자열이 아닌 바이트 단위로 처리하려니 불편하다. 그리고 바이트를 문자(char)로 처리하려면 인코딩을 신경 써야 한다. reader, + * writer를 사용하면 입출력 스트림을 바이트가 아닌 문자 단위로 데이터를 처리하게 된다. 그리고 InputStreamReader를 사용하면 지정된 인코딩에 따라 유니코드 문자로 변환할 수 있다. */ @Nested class InputStreamReader_학습_테스트 { /** - * InputStreamReader를 사용해서 바이트를 문자(char)로 읽어온다. - * 읽어온 문자(char)를 문자열(String)로 처리하자. - * 필터인 BufferedReader를 사용하면 readLine 메서드를 사용해서 문자열(String)을 한 줄 씩 읽어올 수 있다. + * InputStreamReader를 사용해서 바이트를 문자(char)로 읽어온다. 읽어온 문자(char)를 문자열(String)로 처리하자. 필터인 BufferedReader를 사용하면 + * readLine 메서드를 사용해서 문자열(String)을 한 줄 씩 읽어올 수 있다. */ @Test - void BufferedReader를_사용하여_문자열을_읽어온다() { + void BufferedReader를_사용하여_문자열을_읽어온다() throws IOException { final String emoji = String.join("\r\n", "😀😃😄😁😆😅😂🤣🥲☺️😊", "😇🙂🙃😉😌😍🥰😘😗😙😚", "😋😛😝😜🤪🤨🧐🤓😎🥸🤩", ""); final InputStream inputStream = new ByteArrayInputStream(emoji.getBytes()); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); final StringBuilder actual = new StringBuilder(); - + String line; + while ((line = bufferedReader.readLine()) != null) { + actual.append(line).append("\r\n"); + } assertThat(actual).hasToString(emoji); } } From 91a4818ca6c9c1231b84c6d67161a324502759b7 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Thu, 12 Sep 2024 20:21:37 +0900 Subject: [PATCH 16/22] =?UTF-8?q?test:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20Get?= =?UTF-8?q?=20=EC=9A=94=EC=B2=AD=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 --- .../coyote/http11/Http11ProcessorTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) 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 83a9a813b6..959240fb50 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -1,5 +1,6 @@ package org.apache.coyote.http11; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import support.StubSocket; import java.io.File; @@ -11,6 +12,7 @@ class Http11ProcessorTest { + @DisplayName("index 페이지 이동 성공") @Test void index() throws IOException { // given @@ -37,4 +39,60 @@ void index() throws IOException { assertThat(socket.output()).isEqualTo(expected); } + + @DisplayName("login 페이지 이동 성공") + @Test + void login() 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-Length: 3797 \r\n" + + "Content-Type: text/html;charset=utf-8 \r\n" + + "\r\n" + + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + + assertThat(socket.output()).isEqualTo(expected); + } + + @DisplayName("register 페이지 이동 성공") + @Test + void register() 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-Length: 4319 \r\n" + + "Content-Type: text/html;charset=utf-8 \r\n" + + "\r\n" + + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + + assertThat(socket.output()).isEqualTo(expected); + } } From c739854cbcaec8133ac294b1fef9037600e81c6d Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Thu, 12 Sep 2024 21:27:43 +0900 Subject: [PATCH 17/22] =?UTF-8?q?feat:=20httpRequestBody=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A1=9C=20body=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 7 +++--- .../controller/RegisterController.java | 16 ++++++------ .../coyote/http11/request/HttpRequest.java | 20 ++++++++++----- .../http11/request/HttpRequestBody.java | 25 +++++++++++++++++++ 4 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestBody.java diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index 2959bece79..0ef69ca415 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -2,8 +2,8 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.Session; import org.apache.coyote.http11.SessionManager; import org.apache.coyote.http11.request.HttpRequest; @@ -21,9 +21,8 @@ public class LoginController extends AbstractController { @Override protected void doPost(HttpRequest request, HttpResponse response) throws Exception { - String requestBody = request.getBody(); - String account = requestBody.split("&")[0].split("=")[1]; - String password = requestBody.split("&")[1].split("=")[1]; + String account = request.findRequestBodyValue("account"); + String password = request.findRequestBodyValue("password"); User user = InMemoryUserRepository.findByAccount(account).get(); diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java index 89202a4918..ce5c79d41e 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -2,8 +2,8 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -11,18 +11,20 @@ public class RegisterController extends AbstractController { @Override protected void doPost(HttpRequest request, HttpResponse response) throws Exception { - String requestBody = request.getBody(); - String account = requestBody.split("&")[0].split("=")[1]; - String email = requestBody.split("&")[1].split("=")[1]; - String password = requestBody.split("&")[2].split("=")[1]; - - InMemoryUserRepository.save(new User(account, password, email)); + InMemoryUserRepository.save(createUser(request)); response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); response.addHeader(HttpHeaders.LOCATION, "/index.html"); } + private User createUser(HttpRequest request) { + String account = request.findRequestBodyValue("account"); + String email = request.findRequestBodyValue("email"); + String password = request.findRequestBodyValue("password"); + return new User(account, password, email); + } + @Override protected void doGet(HttpRequest request, HttpResponse response) throws Exception { response.setResponseFromRequest(request); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 545005026b..074f0b7735 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -24,12 +24,12 @@ public class HttpRequest { private final HttpRequestLine httpRequestLine; private final Map headers; - private final String body; + private final HttpRequestBody httpRequestBody; - public HttpRequest(HttpRequestLine httpRequestLine, Map headers, String body) { + public HttpRequest(HttpRequestLine httpRequestLine, Map headers, HttpRequestBody httpRequestBody) { this.httpRequestLine = httpRequestLine; this.headers = headers; - this.body = body; + this.httpRequestBody = httpRequestBody; } public static HttpRequest from(InputStream inputStream) throws IOException { @@ -49,7 +49,7 @@ public static HttpRequest from(InputStream inputStream) throws IOException { char[] buffer = new char[contentLength]; bufferedReader.read(buffer, 0, contentLength); String body = new String(buffer); - return new HttpRequest(requestLine, headers, body); + return new HttpRequest(requestLine, headers, HttpRequestBody.from(body)); } return new HttpRequest(requestLine, headers, null); @@ -93,6 +93,10 @@ public String getContentType() { return ContentType.HTML; } + public String findRequestBodyValue(String name) { + return httpRequestBody.getValue(name); + } + public HttpMethod getHttpMethod() { return httpRequestLine.getMethod(); } @@ -109,7 +113,11 @@ public Map getHeaders() { return headers; } - public String getBody() { - return body; + public HttpRequestLine getHttpRequestLine() { + return httpRequestLine; + } + + public HttpRequestBody getHttpRequestBody() { + return httpRequestBody; } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestBody.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestBody.java new file mode 100644 index 0000000000..be49ca87e6 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestBody.java @@ -0,0 +1,25 @@ +package org.apache.coyote.http11.request; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public class HttpRequestBody { + + private final Map body; + + public HttpRequestBody(Map body) { + this.body = body; + } + + public static HttpRequestBody from(String requestBody) { + Map body = Arrays.stream(requestBody.split("&")) + .map(s -> s.split("=")) + .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1])); + return new HttpRequestBody(body); + } + + public String getValue(String name) { + return body.get(name); + } +} From 8dc2b1293e157fcb079b48efd14bfe8bd731a9e3 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Fri, 13 Sep 2024 12:28:56 +0900 Subject: [PATCH 18/22] =?UTF-8?q?test:=20Thread=20=ED=95=99=EC=8A=B5?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/main/resources/application.yml | 8 ++++---- .../src/test/java/thread/stage0/SynchronizationTest.java | 2 +- study/src/test/java/thread/stage0/ThreadPoolsTest.java | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml index 7277616bc7..37175ef611 100644 --- a/study/src/main/resources/application.yml +++ b/study/src/main/resources/application.yml @@ -3,11 +3,11 @@ handlebars: server: tomcat: - accept-count: 1 - max-connections: 1 + accept-count: 0 # max-connections 이상의 요청이 들어 왔을 때 사용하는 요청 대기열 큐의 사이즈 + max-connections: 2 # Tomcat 서버가 '동시에 처리할 수 있는 최대 클라이언트 연결 수' threads: - min-spare: 2 - max: 2 + min-spare: 2 # 톰캣 스레드 풀에 대기 상태로 있는 스레드 개수 + max: 2 # 스레드 풀이 '동시에' 사용할 수 있는 최대 스레드 개수 compression: enabled: true min-response-size: 10 \ No newline at end of file diff --git a/study/src/test/java/thread/stage0/SynchronizationTest.java b/study/src/test/java/thread/stage0/SynchronizationTest.java index 0333c18e3b..b463c2b984 100644 --- a/study/src/test/java/thread/stage0/SynchronizationTest.java +++ b/study/src/test/java/thread/stage0/SynchronizationTest.java @@ -41,7 +41,7 @@ private static final class SynchronizedMethods { private int sum = 0; - public void calculate() { + public synchronized void calculate() { setSum(getSum() + 1); } diff --git a/study/src/test/java/thread/stage0/ThreadPoolsTest.java b/study/src/test/java/thread/stage0/ThreadPoolsTest.java index 238611ebfe..03efdabc8d 100644 --- a/study/src/test/java/thread/stage0/ThreadPoolsTest.java +++ b/study/src/test/java/thread/stage0/ThreadPoolsTest.java @@ -31,8 +31,8 @@ void testNewFixedThreadPool() { executor.submit(logWithSleep("hello fixed thread pools")); // 올바른 값으로 바꿔서 테스트를 통과시키자. - final int expectedPoolSize = 0; - final int expectedQueueSize = 0; + final int expectedPoolSize = 2; + final int expectedQueueSize = 1; assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize()); assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size()); @@ -46,7 +46,7 @@ void testNewCachedThreadPool() { executor.submit(logWithSleep("hello cached thread pools")); // 올바른 값으로 바꿔서 테스트를 통과시키자. - final int expectedPoolSize = 0; + final int expectedPoolSize = 3; final int expectedQueueSize = 0; assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize()); From 952952173f38888227c723914aa4d4dd461bf16e Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Fri, 13 Sep 2024 14:33:59 +0900 Subject: [PATCH 19/22] =?UTF-8?q?feat:=20HttpHeader=EC=99=80=20HttpCookies?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 35 +++++++++++-------- .../controller/RegisterController.java | 4 +-- ...{HttpHeaders.java => HttpHeaderNames.java} | 2 +- .../coyote/http11/request/HttpCookies.java | 29 +++++++++++++++ .../coyote/http11/request/HttpHeaders.java | 34 ++++++++++++++++++ .../coyote/http11/request/HttpRequest.java | 20 ++++++----- .../coyote/http11/response/HttpResponse.java | 6 ++-- 7 files changed, 100 insertions(+), 30 deletions(-) rename tomcat/src/main/java/org/apache/coyote/http11/{HttpHeaders.java => HttpHeaderNames.java} (90%) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/HttpCookies.java create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/HttpHeaders.java diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index 0ef69ca415..7374eb8a0d 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -2,22 +2,22 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.HttpHeaderNames; import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.Session; import org.apache.coyote.http11.SessionManager; +import org.apache.coyote.http11.request.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Map; import java.util.UUID; public class LoginController extends AbstractController { private static final Logger log = LoggerFactory.getLogger(LoginController.class); private static final SessionManager sessionManager = new SessionManager(); - private static final String JSESSIONID = "JSESSIONID="; + private static final String JSESSIONID = "JSESSIONID"; @Override protected void doPost(HttpRequest request, HttpResponse response) throws Exception { @@ -28,35 +28,40 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti if (user.checkPassword(password)) { log.info("user : {}", user); - UUID jSessionId = UUID.randomUUID(); - Session session = new Session(jSessionId.toString()); - session.setAttribute("user", user); - sessionManager.add(session); + UUID jSessionId = saveUUID(user); response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.LOCATION, "/index.html"); - response.addHeader(HttpHeaders.SET_COOKIE, JSESSIONID + jSessionId); + response.addHeader(HttpHeaderNames.LOCATION, "/index.html"); + response.addHeader(HttpHeaderNames.SET_COOKIE, JSESSIONID + "=" + jSessionId); } else { response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.LOCATION, "/401.html"); + response.addHeader(HttpHeaderNames.LOCATION, "/401.html"); } } + private UUID saveUUID(User user) { + UUID jSessionId = UUID.randomUUID(); + Session session = new Session(jSessionId.toString()); + session.setAttribute("user", user); + sessionManager.add(session); + return jSessionId; + } + @Override protected void doGet(HttpRequest request, HttpResponse response) throws Exception { - Map headers = request.getHeaders(); - if (headers.containsKey(HttpHeaders.COOKIE) && - headers.get(HttpHeaders.COOKIE).startsWith(JSESSIONID)) { - String jSessionId = headers.get(HttpHeaders.COOKIE).split("=")[1]; + HttpHeaders headers = request.getHttpHeaders(); + + if (headers.isCookieExistBy(JSESSIONID)) { + String jSessionId = headers.getCookieBy(JSESSIONID); Session session = sessionManager.findSession(jSessionId); if (session != null && session.getAttribute("user") != null) { response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.LOCATION, "/index.html"); + response.addHeader(HttpHeaderNames.LOCATION, "/index.html"); } else { response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.OK); diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java index ce5c79d41e..d247359bc6 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -2,7 +2,7 @@ import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; -import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.HttpHeaderNames; import org.apache.coyote.http11.HttpStatus; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -15,7 +15,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti response.setResponseFromRequest(request); response.addHttpStatus(HttpStatus.FOUND); - response.addHeader(HttpHeaders.LOCATION, "/index.html"); + response.addHeader(HttpHeaderNames.LOCATION, "/index.html"); } private User createUser(HttpRequest request) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderNames.java similarity index 90% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java rename to tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderNames.java index 317dbadf0e..b9960f2b2e 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderNames.java @@ -1,6 +1,6 @@ package org.apache.coyote.http11; -public class HttpHeaders { +public class HttpHeaderNames { public static String CONTENT_LENGTH = "Content-Length"; public static String CONTENT_TYPE = "Content-Type"; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpCookies.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpCookies.java new file mode 100644 index 0000000000..a86aa3ca9e --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpCookies.java @@ -0,0 +1,29 @@ +package org.apache.coyote.http11.request; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public class HttpCookies { + + private final Map cookies; + + public HttpCookies(Map cookies) { + this.cookies = cookies; + } + + public static HttpCookies from(String cookie) { + Map cookies = Arrays.stream(cookie.split(";")) + .map(c -> c.split("=")) + .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1])); + return new HttpCookies(cookies); + } + + public boolean isExist(String name) { + return cookies.containsKey(name); + } + + public String get(String name) { + return cookies.get(name); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpHeaders.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpHeaders.java new file mode 100644 index 0000000000..9bd865be31 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpHeaders.java @@ -0,0 +1,34 @@ +package org.apache.coyote.http11.request; + +import java.util.Map; + +public class HttpHeaders { + + private final Map headers; + private final HttpCookies httpCookies; + + private HttpHeaders(Map headers, HttpCookies httpCookies) { + this.headers = headers; + this.httpCookies = httpCookies; + } + + public static HttpHeaders from(Map headers) { + String cookie = headers.get("Cookie"); + if (cookie == null) { + return new HttpHeaders(headers, null); + } + return new HttpHeaders(headers, HttpCookies.from(cookie)); + } + + public String getCookieBy(String name) { + return httpCookies.get(name); + } + + public boolean isCookieExistBy(String name) { + return httpCookies != null && httpCookies.isExist(name); + } + + public Map getHeaders() { + return headers; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 074f0b7735..0c1d85e27a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,7 +1,7 @@ package org.apache.coyote.http11.request; import org.apache.coyote.http11.ContentType; -import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.HttpHeaderNames; import org.apache.coyote.http11.HttpMethod; import java.io.BufferedReader; import java.io.IOException; @@ -23,12 +23,12 @@ public class HttpRequest { private static final String HTML = ".html"; private final HttpRequestLine httpRequestLine; - private final Map headers; + private final HttpHeaders httpHeaders; private final HttpRequestBody httpRequestBody; - public HttpRequest(HttpRequestLine httpRequestLine, Map headers, HttpRequestBody httpRequestBody) { + public HttpRequest(HttpRequestLine httpRequestLine, HttpHeaders httpHeaders, HttpRequestBody httpRequestBody) { this.httpRequestLine = httpRequestLine; - this.headers = headers; + this.httpHeaders = httpHeaders; this.httpRequestBody = httpRequestBody; } @@ -44,15 +44,17 @@ public static HttpRequest from(InputStream inputStream) throws IOException { headers.put(headerParts[0], headerParts[1]); } + HttpHeaders httpHeaders = HttpHeaders.from(headers); + if (requestLine.isPost()) { - int contentLength = Integer.parseInt(headers.get(HttpHeaders.CONTENT_LENGTH)); + int contentLength = Integer.parseInt(headers.get(HttpHeaderNames.CONTENT_LENGTH)); char[] buffer = new char[contentLength]; bufferedReader.read(buffer, 0, contentLength); String body = new String(buffer); - return new HttpRequest(requestLine, headers, HttpRequestBody.from(body)); + return new HttpRequest(requestLine, httpHeaders, HttpRequestBody.from(body)); } - return new HttpRequest(requestLine, headers, null); + return new HttpRequest(requestLine, httpHeaders, null); } public boolean isGet() { @@ -109,8 +111,8 @@ public String getVersion() { return httpRequestLine.getVersion(); } - public Map getHeaders() { - return headers; + public HttpHeaders getHttpHeaders() { + return httpHeaders; } public HttpRequestLine getHttpRequestLine() { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index a6e5c2465f..33c6e50802 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -1,7 +1,7 @@ package org.apache.coyote.http11.response; +import org.apache.coyote.http11.HttpHeaderNames; import org.apache.coyote.http11.HttpStatus; -import org.apache.coyote.http11.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; import java.io.IOException; import java.io.OutputStream; @@ -24,8 +24,8 @@ public HttpResponse() { public void setResponseFromRequest(HttpRequest request) throws URISyntaxException, IOException { String responseBody = new String(request.toHttpResponseBody()); version = request.getVersion(); - headers.put(HttpHeaders.CONTENT_TYPE, request.getContentType()); - headers.put(HttpHeaders.CONTENT_LENGTH, responseBody.getBytes().length); + headers.put(HttpHeaderNames.CONTENT_TYPE, request.getContentType()); + headers.put(HttpHeaderNames.CONTENT_LENGTH, responseBody.getBytes().length); body = responseBody; } From 4fea376b0af2cf9c0139dd16677165234acb5edf Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Fri, 13 Sep 2024 15:18:25 +0900 Subject: [PATCH 20/22] =?UTF-8?q?test:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=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 --- .../coyote/http11/response/HttpResponse.java | 4 + .../controller/LoginControllerTest.java | 137 ++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 tomcat/src/test/java/com/techcourse/controller/LoginControllerTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index 33c6e50802..ab9a3a346a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -56,4 +56,8 @@ public void send(OutputStream outputStream) { throw new RuntimeException(e); } } + + public int getHttpStatus() { + return httpStatus.getCode(); + } } diff --git a/tomcat/src/test/java/com/techcourse/controller/LoginControllerTest.java b/tomcat/src/test/java/com/techcourse/controller/LoginControllerTest.java new file mode 100644 index 0000000000..acfa42004e --- /dev/null +++ b/tomcat/src/test/java/com/techcourse/controller/LoginControllerTest.java @@ -0,0 +1,137 @@ +package com.techcourse.controller; + +import com.techcourse.model.User; +import org.apache.coyote.http11.Session; +import org.apache.coyote.http11.SessionManager; +import org.apache.coyote.http11.request.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestBody; +import org.apache.coyote.http11.request.HttpRequestLine; +import org.apache.coyote.http11.response.HttpResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class LoginControllerTest { + + private final SessionManager sessionManager = new SessionManager(); + + @DisplayName("쿠키 없이 로그인 페이지로 Get 요청 시 200 반환") + @Test + void login_noCookie() throws Exception { + //given + LoginController controller = new LoginController(); + HttpRequestLine requestLine = HttpRequestLine.from("GET /login HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequest request = new HttpRequest(requestLine, httpHeaders, null); + HttpResponse response = new HttpResponse(); + + //when + controller.doGet(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(200); + } + + @DisplayName("쿠키와 함께 로그인 페이지로 Get 요청 시 302 반환") + @Test + void login_Cookie() throws Exception { + //given + LoginController controller = new LoginController(); + Session session = new Session("sessionId"); + session.setAttribute("user", new User(1L, "account", "password", "email")); + sessionManager.add(session); + + HttpRequestLine requestLine = HttpRequestLine.from("GET /login HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + headers.put("Cookie", "JSESSIONID=sessionId"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequest request = new HttpRequest(requestLine, httpHeaders, null); + HttpResponse response = new HttpResponse(); + + //when + controller.doGet(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(302); + } + + @DisplayName("다른 세션을 저장한 쿠키와 함께 로그인 페이지로 Get 요청 시 200 반환") + @Test + void login_differentCookie() throws Exception { + //given + LoginController controller = new LoginController(); + Session session = new Session("sessionId"); + session.setAttribute("user", new User(1L, "account", "password", "email")); + sessionManager.add(session); + + HttpRequestLine requestLine = HttpRequestLine.from("GET /login HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + headers.put("Cookie", "JSESSIONID=differentSessionId"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequest request = new HttpRequest(requestLine, httpHeaders, null); + HttpResponse response = new HttpResponse(); + + //when + controller.doGet(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(200); + } + + @DisplayName("로그인 Post 요청 로그인 성공 시 302 반환") + @Test + void login_success() throws Exception { + //given + LoginController controller = new LoginController(); + HttpRequestLine requestLine = HttpRequestLine.from("POST /login HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequestBody httpRequestBody = HttpRequestBody.from( + "account=gugu&password=password&email=hkkang%40woowahan.com"); + + HttpRequest request = new HttpRequest(requestLine, httpHeaders, httpRequestBody); + HttpResponse response = new HttpResponse(); + + //when + controller.doPost(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(302); + } + + @DisplayName("로그인 잘못된 비밀번호 요청 시 302 반환") + @Test + void login_failure() throws Exception { + //given + LoginController controller = new LoginController(); + HttpRequestLine requestLine = HttpRequestLine.from("POST /login HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequestBody httpRequestBody = HttpRequestBody.from( + "account=gugu&password=wrong&email=hkkang%40woowahan.com"); + + HttpRequest request = new HttpRequest(requestLine, httpHeaders, httpRequestBody); + HttpResponse response = new HttpResponse(); + + //when + controller.doPost(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(302); + } +} \ No newline at end of file From a74eae62e6d4bbf16d0bf1ea866f4bf1e86566d5 Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Fri, 13 Sep 2024 15:25:16 +0900 Subject: [PATCH 21/22] =?UTF-8?q?test:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=ED=85=8C?= =?UTF-8?q?=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 --- .../controller/RegisterControllerTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tomcat/src/test/java/com/techcourse/controller/RegisterControllerTest.java diff --git a/tomcat/src/test/java/com/techcourse/controller/RegisterControllerTest.java b/tomcat/src/test/java/com/techcourse/controller/RegisterControllerTest.java new file mode 100644 index 0000000000..cf5dc31817 --- /dev/null +++ b/tomcat/src/test/java/com/techcourse/controller/RegisterControllerTest.java @@ -0,0 +1,58 @@ +package com.techcourse.controller; + +import org.apache.coyote.http11.request.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestBody; +import org.apache.coyote.http11.request.HttpRequestLine; +import org.apache.coyote.http11.response.HttpResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class RegisterControllerTest { + + @DisplayName("회원가입 페이지로 Get 요청 시 200 반환") + @Test + void register_page() throws Exception { + //given + RegisterController registerController = new RegisterController(); + HttpRequestLine requestLine = HttpRequestLine.from("GET /register HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequest request = new HttpRequest(requestLine, httpHeaders, null); + HttpResponse response = new HttpResponse(); + + //when + registerController.doGet(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(200); + } + + @DisplayName("회원가입 POST 요청 성공 시 302 반환") + @Test + void register_success() throws Exception { + //given + RegisterController registerController = new RegisterController(); + HttpRequestLine requestLine = HttpRequestLine.from("GET /register HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequestBody httpRequestBody = HttpRequestBody.from( + "account=gugu&password=password&email=hkkang%40woowahan.com"); + HttpRequest request = new HttpRequest(requestLine, httpHeaders, httpRequestBody); + HttpResponse response = new HttpResponse(); + + //when + registerController.doPost(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(302); + } +} \ No newline at end of file From 2f6d020b440cc8768494fffa9f06bdc9a614630c Mon Sep 17 00:00:00 2001 From: tkdgur0906 Date: Fri, 13 Sep 2024 15:37:28 +0900 Subject: [PATCH 22/22] =?UTF-8?q?test:=20=EC=A0=95=EC=A0=81=20=EB=A6=AC?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=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 --- .../StaticResourceControllerTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tomcat/src/test/java/com/techcourse/controller/StaticResourceControllerTest.java diff --git a/tomcat/src/test/java/com/techcourse/controller/StaticResourceControllerTest.java b/tomcat/src/test/java/com/techcourse/controller/StaticResourceControllerTest.java new file mode 100644 index 0000000000..91d71f60f4 --- /dev/null +++ b/tomcat/src/test/java/com/techcourse/controller/StaticResourceControllerTest.java @@ -0,0 +1,37 @@ +package com.techcourse.controller; + +import org.apache.coyote.http11.request.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestLine; +import org.apache.coyote.http11.response.HttpResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class StaticResourceControllerTest { + + @DisplayName("정적 리소스 페이지로 Get 요청 시 200 반환") + @ParameterizedTest + @CsvSource(value = {"/css/styles.css", "/js/scripts.js"}) + void staticResource_css(String path) throws Exception { + //given + StaticResourceController staticResourceController = new StaticResourceController(); + HttpRequestLine requestLine = HttpRequestLine.from("GET " + path + " HTTP/1.1"); + Map headers = new HashMap<>(); + headers.put("Host", "localhost:8080"); + headers.put("Connection", "keep-alive"); + HttpHeaders httpHeaders = HttpHeaders.from(headers); + HttpRequest request = new HttpRequest(requestLine, httpHeaders, null); + HttpResponse response = new HttpResponse(); + + //when + staticResourceController.doGet(request, response); + + //then + assertThat(response.getHttpStatus()).isEqualTo(200); + } +} \ No newline at end of file