From fb1a684ebec30850728a155a75484632db72548b Mon Sep 17 00:00:00 2001 From: jjongwa Date: Sat, 9 Sep 2023 15:29:49 +0900 Subject: [PATCH 01/16] =?UTF-8?q?refactor:=20response=EC=97=90=20=EC=BF=A0?= =?UTF-8?q?=ED=82=A4=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8A=94=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=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/RequestHandler.java | 8 ++++++-- .../coyote/http11/response/HttpResponse.java | 9 +-------- .../http11/response/HttpResponseTest.java | 17 ----------------- 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java index 75f267ff99..67226948b4 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java @@ -35,7 +35,9 @@ public static HttpResponse handleRequest(final HttpRequest httpRequest) throws I final HttpCookie cookie = HttpCookie.from(httpRequest.getRequestHeaders().geHeaderValue("Cookie")); if (cookie.contains("JSESSIONID")) { final ResponseBody responseBody = FileExtractor.extractHtmlFile("/index"); - return HttpResponse.withCookie(HttpStatusCode.FOUND, responseBody, cookie); + final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); + httpResponse.addCookie(cookie); + return httpResponse; } final ResponseBody responseBody = FileExtractor.extractHtmlFile(requestResource); return HttpResponse.of(HttpStatusCode.OK, responseBody); @@ -60,7 +62,9 @@ public static HttpResponse handleRequest(final HttpRequest httpRequest) throws I cookie.setCookie("JSESSIONID", UUID.randomUUID().toString()); } final ResponseBody responseBody = FileExtractor.extractHtmlFile("/index"); - return HttpResponse.withCookie(HttpStatusCode.FOUND, responseBody, cookie); + final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); + httpResponse.addCookie(cookie); + return httpResponse; } throw new LoginException(); } catch (LoginException exception) { 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 20db9a2a64..025bf3303f 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,8 @@ public static HttpResponse of(final HttpStatusCode httpStatusCode, final Respons return new HttpResponse(statusLine, responseHeader, responseBody); } - public static HttpResponse withCookie( - final HttpStatusCode httpStatusCode, - final ResponseBody responseBody, - final HttpCookie httpCookie - ) { - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + public void addCookie(final HttpCookie httpCookie) { responseHeader.addCookie(httpCookie); - final StatusLine statusLine = new StatusLine(httpStatusCode); - return new HttpResponse(statusLine, responseHeader, responseBody); } public StatusLine getStatusLine() { diff --git a/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java b/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java index f116f8f1b3..476e99ba0e 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import org.apache.coyote.http11.HttpCookie; import org.apache.coyote.http11.HttpStatusCode; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -29,20 +28,4 @@ void of() { () -> assertThat(httpResponse.getResponseBody()).isEqualTo(responseBody) ); } - - @DisplayName("원하는 Cookie 정보를 추가한 Response를 만들 수 있다.") - @Test - void withCookie() { - // given - final ResponseBody responseBody = ResponseBody.of("index.html", "/index.html"); - final HttpStatusCode httpStatusCode = HttpStatusCode.OK; - final String cookieHeader = "cookie1=one;cookie2=two;cookie3=three"; - final HttpCookie cookie = HttpCookie.from(cookieHeader); - - // when - final HttpResponse httpResponse = HttpResponse.withCookie(httpStatusCode, responseBody, cookie); - - // then - assertThat(httpResponse.getResponseHeaders().getValue("Set-Cookie")).isEqualTo(cookieHeader); - } } From c8b8685f0a64354e6fd9b6a06dadc231d4d73d12 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Sun, 10 Sep 2023 02:12:18 +0900 Subject: [PATCH 02/16] =?UTF-8?q?refactor:=20controller=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 --- .../java/nextstep/jwp/DefaultController.java | 19 ++++ .../java/nextstep/jwp/HomeController.java | 20 ++++ .../java/nextstep/jwp/LoginController.java | 80 ++++++++++++++ .../java/nextstep/jwp/RegisterController.java | 52 +++++++++ .../exception/NotAllowedMethodException.java | 2 +- .../apache/catalina/AbstractController.java | 29 +++++ .../java/org/apache/catalina/Controller.java | 10 ++ .../org/apache/catalina/RequestMapping.java | 26 +++++ .../http11 => catalina}/SessionManager.java | 8 +- .../apache/coyote/http11/FileExtractor.java | 11 +- .../apache/coyote/http11/Http11Processor.java | 8 +- .../org/apache/coyote/http11/HttpCookie.java | 6 + .../coyote/http11/HttpExtensionType.java | 11 +- .../apache/coyote/http11/HttpStatusCode.java | 5 +- .../apache/coyote/http11/RequestHandler.java | 104 ------------------ .../coyote/http11/request/HttpRequest.java | 6 + .../coyote/http11/request/RequestHeader.java | 6 + tomcat/src/main/resources/static/400.html | 50 +++++++++ .../coyote/http11/HttpExtensionTypeTest.java | 4 +- .../coyote/http11/SessionManagerTest.java | 1 + 20 files changed, 333 insertions(+), 125 deletions(-) create mode 100644 tomcat/src/main/java/nextstep/jwp/DefaultController.java create mode 100644 tomcat/src/main/java/nextstep/jwp/HomeController.java create mode 100644 tomcat/src/main/java/nextstep/jwp/LoginController.java create mode 100644 tomcat/src/main/java/nextstep/jwp/RegisterController.java create mode 100644 tomcat/src/main/java/org/apache/catalina/AbstractController.java create mode 100644 tomcat/src/main/java/org/apache/catalina/Controller.java create mode 100644 tomcat/src/main/java/org/apache/catalina/RequestMapping.java rename tomcat/src/main/java/org/apache/{coyote/http11 => catalina}/SessionManager.java (74%) delete mode 100644 tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java create mode 100644 tomcat/src/main/resources/static/400.html diff --git a/tomcat/src/main/java/nextstep/jwp/DefaultController.java b/tomcat/src/main/java/nextstep/jwp/DefaultController.java new file mode 100644 index 0000000000..f33b424aba --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/DefaultController.java @@ -0,0 +1,19 @@ +package nextstep.jwp; + +import java.io.IOException; +import org.apache.catalina.AbstractController; +import org.apache.coyote.http11.FileExtractor; +import org.apache.coyote.http11.HttpStatusCode; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.ResponseBody; + +public class DefaultController extends AbstractController { + + @Override + protected HttpResponse doGet(final HttpRequest request) throws IOException { + final String resource = request.getRequestPath().getResource(); + final ResponseBody responseBody = FileExtractor.extractFile(resource); + return HttpResponse.of(HttpStatusCode.OK, responseBody); + } +} diff --git a/tomcat/src/main/java/nextstep/jwp/HomeController.java b/tomcat/src/main/java/nextstep/jwp/HomeController.java new file mode 100644 index 0000000000..c5b664a1f0 --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/HomeController.java @@ -0,0 +1,20 @@ +package nextstep.jwp; + +import java.io.IOException; +import org.apache.catalina.AbstractController; +import org.apache.coyote.http11.HttpExtensionType; +import org.apache.coyote.http11.HttpStatusCode; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.ResponseBody; + +public class HomeController extends AbstractController { + + private static final String DEFAULT_CONTENT = "Hello world!"; + + @Override + protected HttpResponse doGet(final HttpRequest request) throws IOException { + final ResponseBody responseBody = ResponseBody.of(HttpExtensionType.HTML.getExtension(), DEFAULT_CONTENT); + return HttpResponse.of(HttpStatusCode.OK, responseBody); + } +} diff --git a/tomcat/src/main/java/nextstep/jwp/LoginController.java b/tomcat/src/main/java/nextstep/jwp/LoginController.java new file mode 100644 index 0000000000..7162fccdc5 --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/LoginController.java @@ -0,0 +1,80 @@ +package nextstep.jwp; + +import static org.reflections.Reflections.log; + +import java.io.IOException; +import java.util.UUID; +import nextstep.jwp.db.InMemoryUserRepository; +import nextstep.jwp.exception.LoginException; +import nextstep.jwp.model.User; +import org.apache.catalina.AbstractController; +import org.apache.catalina.SessionManager; +import org.apache.coyote.http11.FileExtractor; +import org.apache.coyote.http11.HttpCookie; +import org.apache.coyote.http11.HttpStatusCode; +import org.apache.coyote.http11.Session; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.ResponseBody; + +public class LoginController extends AbstractController { + + private static final SessionManager sessionManager = new SessionManager(); + + private static final String JSESSIONID = "JSESSIONID"; + private static final String INDEX = "/index"; + private static final String ACCOUNT = "account"; + private static final String PASSWORD = "password"; + private static final String COOKIE = "Cookie"; + private static final String USER = "user"; + private static final String UNAUTHORIZED = "/401"; + + @Override + protected HttpResponse doPost(final HttpRequest request) throws IOException { + try { + final String userName = request.getRequestBody().get(ACCOUNT); + final String password = request.getRequestBody().get(PASSWORD); + + final User user = InMemoryUserRepository.findByAccount(userName) + .orElseThrow(LoginException::new); + + if (user.checkPassword(password)) { + log.info(user.toString()); + final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); + checkSession(user, cookie); + final ResponseBody responseBody = FileExtractor.extractFile(INDEX); + final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); + httpResponse.addCookie(cookie); + return httpResponse; + } + throw new LoginException(); + } catch (LoginException exception) { + final ResponseBody responseBody = FileExtractor.extractFile(UNAUTHORIZED); + return HttpResponse.of(HttpStatusCode.UNAUTHORIZED, responseBody); + } + } + + private void checkSession(final User user, final HttpCookie cookie) { + if (!cookie.contains(JSESSIONID)) { + final Session session = new Session(UUID.randomUUID().toString()); + session.setAttribute(USER, user); + sessionManager.add(session); + cookie.setCookie(JSESSIONID, session.getId()); + } + } + + @Override + protected HttpResponse doGet(final HttpRequest request) throws IOException { + final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); + final String requestResource = request.getRequestPath().getResource(); + + if (cookie.contains(JSESSIONID)) { + final ResponseBody responseBody = FileExtractor.extractFile(INDEX); + final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); + httpResponse.addCookie(cookie); + return httpResponse; + } + final ResponseBody responseBody = FileExtractor.extractFile(requestResource); + return HttpResponse.of(HttpStatusCode.OK, responseBody); + } +} diff --git a/tomcat/src/main/java/nextstep/jwp/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/RegisterController.java new file mode 100644 index 0000000000..f7f9b72744 --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/RegisterController.java @@ -0,0 +1,52 @@ +package nextstep.jwp; + +import java.io.IOException; +import java.util.Map; +import nextstep.jwp.db.InMemoryUserRepository; +import nextstep.jwp.model.User; +import org.apache.catalina.AbstractController; +import org.apache.coyote.http11.FileExtractor; +import org.apache.coyote.http11.HttpStatusCode; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.ResponseBody; + +public class RegisterController extends AbstractController { + + private static final String BAD_REQUEST = "/400"; + private static final String CONFLICT = "/409"; + private static final String INDEX = "/index"; + private static final String REGISTER = "/register"; + private static final String ACCOUNT = "account"; + private static final String PASSWORD = "password"; + private static final String EMAIL = "email"; + + @Override + protected HttpResponse doPost(final HttpRequest request) throws IOException { + final Map requestBody = request.getRequestBody(); + + final String account = requestBody.get(ACCOUNT); + final String password = requestBody.get(PASSWORD); + final String email = requestBody.get(EMAIL); + + if (account.isBlank() || password.isBlank() || email.isBlank()) { + final ResponseBody responseBody = FileExtractor.extractFile(BAD_REQUEST); + return HttpResponse.of(HttpStatusCode.BAD_REQUEST, responseBody); + } + + if (InMemoryUserRepository.checkExistingId(account)) { + final ResponseBody responseBody = FileExtractor.extractFile(CONFLICT); + return HttpResponse.of(HttpStatusCode.OK, responseBody); + } + final User user = new User(account, password, email); + InMemoryUserRepository.save(user); + final ResponseBody responseBody = FileExtractor.extractFile(INDEX); + return HttpResponse.of(HttpStatusCode.OK, responseBody); + } + + @Override + protected HttpResponse doGet(final HttpRequest request) throws IOException { + final ResponseBody responseBody = FileExtractor.extractFile(REGISTER); + return HttpResponse.of(HttpStatusCode.OK, responseBody); + } +} diff --git a/tomcat/src/main/java/nextstep/jwp/exception/NotAllowedMethodException.java b/tomcat/src/main/java/nextstep/jwp/exception/NotAllowedMethodException.java index b88ff897e4..3ba3f89942 100644 --- a/tomcat/src/main/java/nextstep/jwp/exception/NotAllowedMethodException.java +++ b/tomcat/src/main/java/nextstep/jwp/exception/NotAllowedMethodException.java @@ -3,6 +3,6 @@ public class NotAllowedMethodException extends RuntimeException { public NotAllowedMethodException() { - super("해당하는 HttpMethod가 존재하지 않습니다."); + super("해당하는 Method가 존재하지 않습니다."); } } diff --git a/tomcat/src/main/java/org/apache/catalina/AbstractController.java b/tomcat/src/main/java/org/apache/catalina/AbstractController.java new file mode 100644 index 0000000000..3d993e61eb --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/AbstractController.java @@ -0,0 +1,29 @@ +package org.apache.catalina; + +import java.io.IOException; +import org.apache.coyote.http11.request.HttpMethod; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public class AbstractController implements Controller { + + @Override + public HttpResponse service(final HttpRequest request) throws IOException { + if (request.getHttpMethod().equals(HttpMethod.GET)) { + return doGet(request); + } + if (request.getHttpMethod().equals(HttpMethod.POST)) { + return doPost(request); + } + throw new UnsupportedOperationException(); + } + + + protected HttpResponse doPost(final HttpRequest request) throws IOException { + return null; + } + + protected HttpResponse doGet(final HttpRequest request) throws IOException { + return null; + } +} diff --git a/tomcat/src/main/java/org/apache/catalina/Controller.java b/tomcat/src/main/java/org/apache/catalina/Controller.java new file mode 100644 index 0000000000..00af3297e3 --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/Controller.java @@ -0,0 +1,10 @@ +package org.apache.catalina; + +import java.io.IOException; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public interface Controller { + + HttpResponse service(final HttpRequest request) throws IOException; +} diff --git a/tomcat/src/main/java/org/apache/catalina/RequestMapping.java b/tomcat/src/main/java/org/apache/catalina/RequestMapping.java new file mode 100644 index 0000000000..ee17e8431e --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/RequestMapping.java @@ -0,0 +1,26 @@ +package org.apache.catalina; + +import nextstep.jwp.DefaultController; +import nextstep.jwp.HomeController; +import nextstep.jwp.LoginController; +import nextstep.jwp.RegisterController; +import org.apache.coyote.http11.request.HttpRequest; + +public class RequestMapping { + + public Controller getController(final HttpRequest request) { + final String resource = request.getRequestPath().getResource(); + + if (resource.equals("/")) { + return new HomeController(); + } + if (resource.equals("/login")) { + return new LoginController(); + } + if (resource.equals("/register")) { + return new RegisterController(); + } + + return new DefaultController(); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/SessionManager.java similarity index 74% rename from tomcat/src/main/java/org/apache/coyote/http11/SessionManager.java rename to tomcat/src/main/java/org/apache/catalina/SessionManager.java index 04bde2f48a..b5f5da3eb9 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/SessionManager.java @@ -1,17 +1,19 @@ -package org.apache.coyote.http11; +package org.apache.catalina; import java.util.HashMap; import java.util.Map; -import org.apache.catalina.Manager; +import org.apache.coyote.http11.Session; -public class SessionManager implements Manager{ +public class SessionManager implements Manager { private static final Map SESSIONS = new HashMap<>(); + @Override public void add(final Session session) { SESSIONS.put(session.getId(), session); } + @Override public Session findSession(final String id) { return SESSIONS.get(id); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java b/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java index c1aed7085b..eeaeac0251 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java @@ -10,17 +10,22 @@ public class FileExtractor { private static final ClassLoader CLASSLOADER = ClassLoader.getSystemClassLoader(); + private static final String STATIC = "static"; + private static final String TYPE_SEPARATOR = "."; private FileExtractor() { } public static ResponseBody extractFile(final String resource) throws IOException { - final URL url = CLASSLOADER.getResource("static" + resource); + if (!resource.contains(TYPE_SEPARATOR)) { + return extractHtmlFile(resource); + } + final URL url = CLASSLOADER.getResource(STATIC + resource); return ResponseBody.of(HttpExtensionType.from(resource).getExtension(), makeBodyContent(url)); } - public static ResponseBody extractHtmlFile(final String resource) throws IOException { - final URL url = CLASSLOADER.getResource("static" + resource + HttpExtensionType.HTML.getExtension()); + private static ResponseBody extractHtmlFile(final String resource) throws IOException { + final URL url = CLASSLOADER.getResource(STATIC + resource + HttpExtensionType.HTML.getExtension()); return ResponseBody.of(HttpExtensionType.HTML.getExtension(), makeBodyContent(url)); } 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 eb32836154..127d0fddec 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -5,6 +5,8 @@ import java.io.InputStreamReader; import java.net.Socket; import nextstep.jwp.exception.UncheckedServletException; +import org.apache.catalina.Controller; +import org.apache.catalina.RequestMapping; import org.apache.coyote.Processor; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -34,8 +36,10 @@ public void process(final Socket connection) { final var bufferedReader = new BufferedReader(new InputStreamReader(inputStream)) ) { final HttpRequest httpRequest = HttpRequest.parse(bufferedReader); - final HttpResponse httpResponse = RequestHandler.handleRequest(httpRequest); - final var response = httpResponse.toString(); + final RequestMapping requestMapping = new RequestMapping(); + final Controller controller = requestMapping.getController(httpRequest); + final HttpResponse httpResponse = controller.service(httpRequest); + final String response = httpResponse.toString(); outputStream.write(response.getBytes()); outputStream.flush(); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java index 7dc0ff638b..6d18a8380d 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java @@ -12,6 +12,8 @@ public class HttpCookie { private static final String DELIMITER = "; "; private static final String EQUAL = "="; + private static final String JSESSIONID = "JSESSIONID"; + private static final String EMPTY_STRING = ""; private final Map items; @@ -47,6 +49,10 @@ public String getCookie(final String key) { return items.get(key); } + public String getJSessionId() { + return items.getOrDefault(JSESSIONID, EMPTY_STRING); + } + @Override public String toString() { return items.entrySet() diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpExtensionType.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpExtensionType.java index 48e1fe07df..394e1b9e0e 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpExtensionType.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpExtensionType.java @@ -1,7 +1,7 @@ package org.apache.coyote.http11; import java.util.Arrays; -import org.apache.coyote.http11.request.RequestLine; +import nextstep.jwp.exception.NotAllowedMethodException; public enum HttpExtensionType { @@ -23,14 +23,7 @@ public static HttpExtensionType from(final String extension) { return Arrays.stream(values()) .filter(it -> extension.contains(it.extension)) .findAny() - .orElse(HTML); - } - - public static HttpExtensionType from(final RequestLine requestLine) { - return Arrays.stream(values()) - .filter(it -> requestLine.hasFileExtension(it.getExtension())) - .findAny() - .orElse(HTML); + .orElseThrow(NotAllowedMethodException::new); } public String getExtension() { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java index 3cc09155df..67c81eb5ce 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java @@ -5,7 +5,10 @@ public enum HttpStatusCode { OK(200, "OK"), FOUND(302, "Found"), - UNAUTHORIZED(401, "Unauthorized"); + BAD_REQUEST(400, "Bad Request"), + UNAUTHORIZED(401, "Unauthorized"), + NOT_FOUND(404, "Not Found"), + CONFLICT(409, "Conflict"); private final int code; private final String message; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java deleted file mode 100644 index 67226948b4..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.apache.coyote.http11; - -import java.io.IOException; -import java.util.Map; -import java.util.UUID; -import nextstep.jwp.db.InMemoryUserRepository; -import nextstep.jwp.exception.LoginException; -import nextstep.jwp.model.User; -import org.apache.coyote.http11.request.HttpMethod; -import org.apache.coyote.http11.request.HttpRequest; -import org.apache.coyote.http11.request.RequestPath; -import org.apache.coyote.http11.response.HttpResponse; -import org.apache.coyote.http11.response.ResponseBody; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RequestHandler { - - private static final Logger log = LoggerFactory.getLogger(RequestHandler.class); - - private static final SessionManager sessionManager = new SessionManager(); - - public static HttpResponse handleRequest(final HttpRequest httpRequest) throws IOException { - final RequestPath requestPath = httpRequest.getRequestPath(); - final String requestResource = requestPath.getResource(); - - // 기본 - if (requestResource.equals("/")) { - final ResponseBody responseBody = ResponseBody.of(HttpExtensionType.HTML.getExtension(), "Hello world!"); - return HttpResponse.of(HttpStatusCode.OK, responseBody); - } - - // 로그인 페이지 - if (requestResource.equals("/login") && httpRequest.getHttpMethod().equals(HttpMethod.GET)) { - final HttpCookie cookie = HttpCookie.from(httpRequest.getRequestHeaders().geHeaderValue("Cookie")); - if (cookie.contains("JSESSIONID")) { - final ResponseBody responseBody = FileExtractor.extractHtmlFile("/index"); - final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); - httpResponse.addCookie(cookie); - return httpResponse; - } - final ResponseBody responseBody = FileExtractor.extractHtmlFile(requestResource); - return HttpResponse.of(HttpStatusCode.OK, responseBody); - } - - // 로그인 진행 - if (requestResource.equals("/login") && httpRequest.getHttpMethod().equals(HttpMethod.POST)) { - try { - final String userName = httpRequest.getRequestBody().get("account"); - final String password = httpRequest.getRequestBody().get("password"); - - final User user = InMemoryUserRepository.findByAccount(userName) - .orElseThrow(LoginException::new); - - if (user.checkPassword(password)) { - log.info(user.toString()); - final HttpCookie cookie = HttpCookie.from(httpRequest.getRequestHeaders().geHeaderValue("Cookie")); - if (!cookie.contains("JSESSIONID")) { - final Session session = new Session(UUID.randomUUID().toString()); - session.setAttribute("user", user); - sessionManager.add(session); - cookie.setCookie("JSESSIONID", UUID.randomUUID().toString()); - } - final ResponseBody responseBody = FileExtractor.extractHtmlFile("/index"); - final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); - httpResponse.addCookie(cookie); - return httpResponse; - } - throw new LoginException(); - } catch (LoginException exception) { - final ResponseBody responseBody = FileExtractor.extractHtmlFile("/401"); - return HttpResponse.of(HttpStatusCode.UNAUTHORIZED, responseBody); - } - } - - // 회원가입 페이지 - if (requestResource.equals("/register") && httpRequest.getHttpMethod().equals(HttpMethod.GET)) { - final ResponseBody responseBody = FileExtractor.extractHtmlFile("/register"); - return HttpResponse.of(HttpStatusCode.OK, responseBody); - } - - // 회원가입 진행 - if (requestResource.equals("/register") && httpRequest.getHttpMethod().equals(HttpMethod.POST)) { - final Map requestBody = httpRequest.getRequestBody(); - - final String account = requestBody.get("account"); - final String password = requestBody.get("password"); - final String email = requestBody.get("email"); - - if (InMemoryUserRepository.checkExistingId(account)) { - final ResponseBody responseBody = FileExtractor.extractHtmlFile("/409"); - return HttpResponse.of(HttpStatusCode.OK, responseBody); - } - final User user = new User(account, password, email); - InMemoryUserRepository.save(user); - final ResponseBody responseBody = FileExtractor.extractHtmlFile("/index"); - return HttpResponse.of(HttpStatusCode.OK, responseBody); - } - - // 나머지 - final ResponseBody responseBody = FileExtractor.extractFile(requestResource); - return HttpResponse.of(HttpStatusCode.OK, 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 f302b6bc2a..0218c481d0 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 @@ -4,6 +4,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import org.apache.coyote.http11.HttpCookie; public class HttpRequest { @@ -67,6 +68,11 @@ public RequestHeader getRequestHeaders() { return requestHeader; } + public String getSessionId() { + final HttpCookie cookie = requestHeader.getCookie(); + return cookie.getJSessionId(); + } + public Map getQueryParameter() { return requestLine.getRequestPath().getQueryParameter(); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestHeader.java b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestHeader.java index 4d3dfc538b..3d9d5ffbd7 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestHeader.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestHeader.java @@ -2,10 +2,12 @@ import java.util.Map; import java.util.Optional; +import org.apache.coyote.http11.HttpCookie; public class RequestHeader { private static final String EMPTY_STRING = ""; + private static final String COOKIE_HEADER = "Cookie"; private final Map elements; @@ -21,4 +23,8 @@ public String geHeaderValue(final String key) { public Map getElements() { return elements; } + + public HttpCookie getCookie() { + return HttpCookie.from(elements.getOrDefault(COOKIE_HEADER, EMPTY_STRING)); + } } diff --git a/tomcat/src/main/resources/static/400.html b/tomcat/src/main/resources/static/400.html new file mode 100644 index 0000000000..02ad15da1e --- /dev/null +++ b/tomcat/src/main/resources/static/400.html @@ -0,0 +1,50 @@ + + + + + + + + + 400 Bad Request - SB Admin + + + + +
+
+
+
+
+
+
+

This requested URL was not found on this server.

+ + + Return to Dashboard + +
+
+
+
+
+
+ +
+ + + + diff --git a/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java b/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java index 15c96ffdab..cbe114c500 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java @@ -21,7 +21,7 @@ void from() { assertThat(actual.getContentType()).isEqualTo(expected); } - @DisplayName("ExtensionType에 해당하는 확장자가 없으면 HTML 타입을 반환한다.") + @DisplayName("ExtensionType에 해당하는 확장자가 없으면 null 반환한다.") @Test void from_emptyExtension() { // given @@ -32,6 +32,6 @@ void from_emptyExtension() { final HttpExtensionType actual = HttpExtensionType.from(extension); // then - assertThat(actual.getContentType()).isEqualTo(expected); + assertThat(actual).isNull(); } } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/SessionManagerTest.java b/tomcat/src/test/java/org/apache/coyote/http11/SessionManagerTest.java index fa80fb4fbd..3326156286 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/SessionManagerTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/SessionManagerTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import org.apache.catalina.SessionManager; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; From 6faa7a24de6ae9d1b069b2f01d5d9a0826fc45cc Mon Sep 17 00:00:00 2001 From: jjongwa Date: Sun, 10 Sep 2023 02:34:31 +0900 Subject: [PATCH 03/16] =?UTF-8?q?refactor:=20Executors=EB=A1=9C=20Thread?= =?UTF-8?q?=20Pool=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/catalina/connector/Connector.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java index d171bb84a8..9d4a0407c7 100644 --- a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java +++ b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java @@ -4,6 +4,8 @@ import java.io.UncheckedIOException; import java.net.ServerSocket; import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.apache.coyote.http11.Http11Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,17 +16,20 @@ public class Connector implements Runnable { private static final int DEFAULT_PORT = 8080; private static final int DEFAULT_ACCEPT_COUNT = 100; + private static final int DEFAULT_THREAD_COUNT = 200; private final ServerSocket serverSocket; + private final ExecutorService executorService; private boolean stopped; public Connector() { - this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT); + this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_THREAD_COUNT); } - public Connector(final int port, final int acceptCount) { + public Connector(final int port, final int acceptCount, final int threadCount) { this.serverSocket = createServerSocket(port, acceptCount); this.stopped = false; + this.executorService = Executors.newFixedThreadPool(threadCount); } private ServerSocket createServerSocket(final int port, final int acceptCount) { @@ -66,7 +71,7 @@ private void process(final Socket connection) { return; } var processor = new Http11Processor(connection); - new Thread(processor).start(); + executorService.execute(processor); } public void stop() { From 656a8e38c4e5dee9bd1ed968cb7458eae375d649 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Sun, 10 Sep 2023 02:35:30 +0900 Subject: [PATCH 04/16] =?UTF-8?q?refactor:=20ConcurrentHashMap=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/catalina/SessionManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/SessionManager.java index b5f5da3eb9..22baaaf152 100644 --- a/tomcat/src/main/java/org/apache/catalina/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/SessionManager.java @@ -1,12 +1,12 @@ package org.apache.catalina; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.coyote.http11.Session; public class SessionManager implements Manager { - private static final Map SESSIONS = new HashMap<>(); + private static final Map SESSIONS = new ConcurrentHashMap<>(); @Override public void add(final Session session) { From 14cea648f0e03df3beb77afecc5f1156b7af89b7 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Sun, 10 Sep 2023 02:35:59 +0900 Subject: [PATCH 05/16] =?UTF-8?q?refactor:=20user=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EC=8B=9C=20id=20=EA=B0=92=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nextstep/jwp/db/InMemoryUserRepository.java | 8 ++++++-- tomcat/src/main/java/nextstep/jwp/model/User.java | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/db/InMemoryUserRepository.java b/tomcat/src/main/java/nextstep/jwp/db/InMemoryUserRepository.java index 37d4893ca7..691d313ad7 100644 --- a/tomcat/src/main/java/nextstep/jwp/db/InMemoryUserRepository.java +++ b/tomcat/src/main/java/nextstep/jwp/db/InMemoryUserRepository.java @@ -3,19 +3,23 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; import nextstep.jwp.model.User; public class InMemoryUserRepository { + private static final AtomicLong id = new AtomicLong(1L); + private static final Map database = new ConcurrentHashMap<>(); static { - final User user = new User(1L, "gugu", "password", "hkkang@woowahan.com"); + final User user = new User(id.getAndIncrement(), "gugu", "password", "hkkang@woowahan.com"); database.put(user.getAccount(), user); } public static void save(User user) { - database.put(user.getAccount(), user); + final User userWithId = new User(id.getAndIncrement(), user.getAccount(), user.getPassword(), user.getEmail()); + database.put(user.getAccount(), userWithId); } public static Optional findByAccount(String account) { diff --git a/tomcat/src/main/java/nextstep/jwp/model/User.java b/tomcat/src/main/java/nextstep/jwp/model/User.java index 4c2a2cd184..158ae5cce5 100644 --- a/tomcat/src/main/java/nextstep/jwp/model/User.java +++ b/tomcat/src/main/java/nextstep/jwp/model/User.java @@ -26,6 +26,14 @@ public String getAccount() { return account; } + public String getPassword() { + return password; + } + + public String getEmail() { + return email; + } + @Override public String toString() { return "User{" + From e6454d2e1126b8e3215b8cb41c20d4fa392dd427 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Sun, 10 Sep 2023 03:01:38 +0900 Subject: [PATCH 06/16] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nextstep/jwp/LoginController.java | 2 +- .../org/apache/coyote/http11/HttpCookie.java | 17 +++++------------ .../coyote/http11/request/HttpRequest.java | 10 ---------- .../coyote/http11/request/RequestLine.java | 4 ---- .../coyote/http11/request/RequestPath.java | 8 -------- .../coyote/http11/HttpExtensionTypeTest.java | 14 +++++++------- 6 files changed, 13 insertions(+), 42 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/LoginController.java b/tomcat/src/main/java/nextstep/jwp/LoginController.java index 7162fccdc5..5979ae324b 100644 --- a/tomcat/src/main/java/nextstep/jwp/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/LoginController.java @@ -39,7 +39,7 @@ protected HttpResponse doPost(final HttpRequest request) throws IOException { .orElseThrow(LoginException::new); if (user.checkPassword(password)) { - log.info(user.toString()); + log.info("user : " + user); final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); checkSession(user, cookie); final ResponseBody responseBody = FileExtractor.extractFile(INDEX); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java index 6d18a8380d..741f144b0d 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java @@ -12,8 +12,9 @@ public class HttpCookie { private static final String DELIMITER = "; "; private static final String EQUAL = "="; - private static final String JSESSIONID = "JSESSIONID"; - private static final String EMPTY_STRING = ""; + private static final int KEY_INDEX = 0; + private static final int VALUE_INDEX = 1; + private static final int SPLIT_LIMIT = 2; private final Map items; @@ -30,9 +31,9 @@ public static HttpCookie from(final String cookieHeader) { return new HttpCookie(); } return Arrays.stream(cookieHeader.split(DELIMITER)) - .map(it -> it.split(EQUAL, 2)) + .map(it -> it.split(EQUAL, SPLIT_LIMIT)) .collect(collectingAndThen( - toMap(it -> it[0], it -> it[1]), + toMap(it -> it[KEY_INDEX], it -> it[VALUE_INDEX]), HttpCookie::new )); } @@ -45,14 +46,6 @@ public boolean contains(final String key) { return items.containsKey(key); } - public String getCookie(final String key) { - return items.get(key); - } - - public String getJSessionId() { - return items.getOrDefault(JSESSIONID, EMPTY_STRING); - } - @Override public String toString() { return items.entrySet() 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 0218c481d0..78285064c0 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 @@ -4,7 +4,6 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -import org.apache.coyote.http11.HttpCookie; public class HttpRequest { @@ -68,15 +67,6 @@ public RequestHeader getRequestHeaders() { return requestHeader; } - public String getSessionId() { - final HttpCookie cookie = requestHeader.getCookie(); - return cookie.getJSessionId(); - } - - public Map getQueryParameter() { - return requestLine.getRequestPath().getQueryParameter(); - } - public Map getRequestBody() { return requestBody.getBody(); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java index e488dec93e..21cd56d814 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java @@ -25,10 +25,6 @@ public static RequestLine from(final String line) { return new RequestLine(HttpMethod.from(split[0]), RequestPath.from(split[1]), split[2]); } - public boolean hasFileExtension(final String extension) { - return requestPath.isParamEmpty() && requestPath.contains(extension); - } - public HttpMethod getHttpMethod() { return httpMethod; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestPath.java b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestPath.java index ad9185f6e8..bbc053c5b6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestPath.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestPath.java @@ -27,14 +27,6 @@ public static RequestPath from(final String uri) { return new RequestPath(resource, QueryParameter.from(queryString)); } - public boolean contains(final String extension) { - return resource.contains(extension); - } - - public boolean isParamEmpty() { - return queryParameter.getParams().isEmpty(); - } - public String getResource() { return resource; } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java b/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java index cbe114c500..55148091fd 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java @@ -1,7 +1,9 @@ package org.apache.coyote.http11; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import nextstep.jwp.exception.NotAllowedMethodException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -21,17 +23,15 @@ void from() { assertThat(actual.getContentType()).isEqualTo(expected); } - @DisplayName("ExtensionType에 해당하는 확장자가 없으면 null 반환한다.") + @DisplayName("ExtensionType에 해당하는 확장자가 없으면 예외 처리한다.") @Test void from_emptyExtension() { // given final String extension = "EmptyExtension"; - final String expected = HttpExtensionType.HTML.getContentType(); - // when - final HttpExtensionType actual = HttpExtensionType.from(extension); - - // then - assertThat(actual).isNull(); + // when & then + assertThatThrownBy(() -> HttpExtensionType.from(extension)) + .isInstanceOf(NotAllowedMethodException.class) + .hasMessage("해당하는 Method가 존재하지 않습니다."); } } From e88da3c2024a49943fb7458220b38a13ed8a4369 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Sun, 10 Sep 2023 03:03:24 +0900 Subject: [PATCH 07/16] =?UTF-8?q?refactor:=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nextstep/jwp/HomeController.java | 4 ++-- ...HttpExtensionType.java => ExtensionType.java} | 6 +++--- .../org/apache/coyote/http11/FileExtractor.java | 6 +++--- .../coyote/http11/response/ResponseBody.java | 16 ++++++++-------- ...nsionTypeTest.java => ExtensionTypeTest.java} | 6 +++--- .../coyote/http11/request/RequestPathTest.java | 6 +++--- .../coyote/http11/response/ResponseBodyTest.java | 6 +++--- .../http11/response/ResponseHeaderTest.java | 6 +++--- 8 files changed, 28 insertions(+), 28 deletions(-) rename tomcat/src/main/java/org/apache/coyote/http11/{HttpExtensionType.java => ExtensionType.java} (82%) rename tomcat/src/test/java/org/apache/coyote/http11/{HttpExtensionTypeTest.java => ExtensionTypeTest.java} (85%) diff --git a/tomcat/src/main/java/nextstep/jwp/HomeController.java b/tomcat/src/main/java/nextstep/jwp/HomeController.java index c5b664a1f0..943a9a7f65 100644 --- a/tomcat/src/main/java/nextstep/jwp/HomeController.java +++ b/tomcat/src/main/java/nextstep/jwp/HomeController.java @@ -2,7 +2,7 @@ import java.io.IOException; import org.apache.catalina.AbstractController; -import org.apache.coyote.http11.HttpExtensionType; +import org.apache.coyote.http11.ExtensionType; import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -14,7 +14,7 @@ public class HomeController extends AbstractController { @Override protected HttpResponse doGet(final HttpRequest request) throws IOException { - final ResponseBody responseBody = ResponseBody.of(HttpExtensionType.HTML.getExtension(), DEFAULT_CONTENT); + final ResponseBody responseBody = ResponseBody.of(ExtensionType.HTML.getExtension(), DEFAULT_CONTENT); return HttpResponse.of(HttpStatusCode.OK, responseBody); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpExtensionType.java b/tomcat/src/main/java/org/apache/coyote/http11/ExtensionType.java similarity index 82% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpExtensionType.java rename to tomcat/src/main/java/org/apache/coyote/http11/ExtensionType.java index 394e1b9e0e..31a6e9cdba 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpExtensionType.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/ExtensionType.java @@ -3,7 +3,7 @@ import java.util.Arrays; import nextstep.jwp.exception.NotAllowedMethodException; -public enum HttpExtensionType { +public enum ExtensionType { HTML(".html", "text/html;charset=utf-8"), CSS(".css", "text/css"), @@ -14,12 +14,12 @@ public enum HttpExtensionType { private final String extension; private final String contentType; - HttpExtensionType(final String extension, final String contentType) { + ExtensionType(final String extension, final String contentType) { this.extension = extension; this.contentType = contentType; } - public static HttpExtensionType from(final String extension) { + public static ExtensionType from(final String extension) { return Arrays.stream(values()) .filter(it -> extension.contains(it.extension)) .findAny() diff --git a/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java b/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java index eeaeac0251..c7c7431cb0 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java @@ -21,12 +21,12 @@ public static ResponseBody extractFile(final String resource) throws IOException return extractHtmlFile(resource); } final URL url = CLASSLOADER.getResource(STATIC + resource); - return ResponseBody.of(HttpExtensionType.from(resource).getExtension(), makeBodyContent(url)); + return ResponseBody.of(ExtensionType.from(resource).getExtension(), makeBodyContent(url)); } private static ResponseBody extractHtmlFile(final String resource) throws IOException { - final URL url = CLASSLOADER.getResource(STATIC + resource + HttpExtensionType.HTML.getExtension()); - return ResponseBody.of(HttpExtensionType.HTML.getExtension(), makeBodyContent(url)); + final URL url = CLASSLOADER.getResource(STATIC + resource + ExtensionType.HTML.getExtension()); + return ResponseBody.of(ExtensionType.HTML.getExtension(), makeBodyContent(url)); } private static String makeBodyContent(final URL url) throws IOException { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/ResponseBody.java b/tomcat/src/main/java/org/apache/coyote/http11/response/ResponseBody.java index 9a1dff6c5f..1b5301e8dc 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/ResponseBody.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/ResponseBody.java @@ -1,27 +1,27 @@ package org.apache.coyote.http11.response; -import org.apache.coyote.http11.HttpExtensionType; +import org.apache.coyote.http11.ExtensionType; public class ResponseBody { - private final HttpExtensionType httpExtensionType; + private final ExtensionType extensionType; private final String content; - private ResponseBody(final HttpExtensionType httpExtensionType, final String content) { - this.httpExtensionType = httpExtensionType; + private ResponseBody(final ExtensionType extensionType, final String content) { + this.extensionType = extensionType; this.content = content; } public static ResponseBody html(final String content) { - return new ResponseBody(HttpExtensionType.HTML, content); + return new ResponseBody(ExtensionType.HTML, content); } public static ResponseBody of(final String extension, final String content) { - return new ResponseBody(HttpExtensionType.from(extension), content); + return new ResponseBody(ExtensionType.from(extension), content); } - public HttpExtensionType getHttpExtensionType() { - return httpExtensionType; + public ExtensionType getHttpExtensionType() { + return extensionType; } public String getContent() { diff --git a/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java b/tomcat/src/test/java/org/apache/coyote/http11/ExtensionTypeTest.java similarity index 85% rename from tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java rename to tomcat/src/test/java/org/apache/coyote/http11/ExtensionTypeTest.java index 55148091fd..765aed0b0e 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/HttpExtensionTypeTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/ExtensionTypeTest.java @@ -7,7 +7,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -class HttpExtensionTypeTest { +class ExtensionTypeTest { @DisplayName("contentType을 올바르게 가져올 수 있다.") @Test @@ -17,7 +17,7 @@ void from() { final String expected = "text/css"; // when - final HttpExtensionType actual = HttpExtensionType.from(extension); + final ExtensionType actual = ExtensionType.from(extension); // then assertThat(actual.getContentType()).isEqualTo(expected); @@ -30,7 +30,7 @@ void from_emptyExtension() { final String extension = "EmptyExtension"; // when & then - assertThatThrownBy(() -> HttpExtensionType.from(extension)) + assertThatThrownBy(() -> ExtensionType.from(extension)) .isInstanceOf(NotAllowedMethodException.class) .hasMessage("해당하는 Method가 존재하지 않습니다."); } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestPathTest.java b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestPathTest.java index 7c4b61fa69..1e751947e4 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestPathTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestPathTest.java @@ -5,7 +5,7 @@ import java.util.HashMap; import java.util.Map; -import org.apache.coyote.http11.HttpExtensionType; +import org.apache.coyote.http11.ExtensionType; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -17,7 +17,7 @@ void from_emptyQueryParameter() { // given final String uri = "/index.html"; final String expectedResource = "/index"; - final HttpExtensionType expectedExtensionType = HttpExtensionType.HTML; + final ExtensionType expectedExtensionType = ExtensionType.HTML; // when final RequestPath requestPath = RequestPath.from(uri); @@ -36,7 +36,7 @@ void from_hasQueryParameter() { // given final String uri = "/login?account=gugu&password=password"; final String expectedResource = "/login"; - final HttpExtensionType expectedExtensionType = HttpExtensionType.HTML; + final ExtensionType expectedExtensionType = ExtensionType.HTML; final Map expectedParams = new HashMap<>(); expectedParams.put("account", "gugu"); expectedParams.put("password", "password"); diff --git a/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseBodyTest.java b/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseBodyTest.java index 930377ef77..63114f87ef 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseBodyTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseBodyTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; -import org.apache.coyote.http11.HttpExtensionType; +import org.apache.coyote.http11.ExtensionType; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -18,7 +18,7 @@ void html() { // when & then assertAll( - () -> assertThat(responseBody.getHttpExtensionType()).isEqualTo(HttpExtensionType.HTML), + () -> assertThat(responseBody.getHttpExtensionType()).isEqualTo(ExtensionType.HTML), () -> assertThat(responseBody.getContent()).isEqualTo(test) ); } @@ -32,7 +32,7 @@ void of() { // when & then assertAll( - () -> assertThat(responseBody.getHttpExtensionType()).isEqualTo(HttpExtensionType.CSS), + () -> assertThat(responseBody.getHttpExtensionType()).isEqualTo(ExtensionType.CSS), () -> assertThat(responseBody.getContent()).isEqualTo(test) ); } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseHeaderTest.java b/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseHeaderTest.java index 50ae4b9637..18f47ab1c5 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseHeaderTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/response/ResponseHeaderTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertAll; import org.apache.coyote.http11.HttpCookie; -import org.apache.coyote.http11.HttpExtensionType; +import org.apache.coyote.http11.ExtensionType; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -25,7 +25,7 @@ void from() { // then assertAll( () -> assertThat(responseHeader.getValue("Content-Type")).isEqualTo( - HttpExtensionType.HTML.getContentType()), + ExtensionType.HTML.getContentType()), () -> assertThat(responseHeader.getValue("Content-Length")).isEqualTo(contentLength) ); } @@ -50,7 +50,7 @@ void addCookie() { void getValue() { // given final ResponseBody responseBody = ResponseBody.html(CONTENT); - final String expected = HttpExtensionType.HTML.getContentType(); + final String expected = ExtensionType.HTML.getContentType(); // when final ResponseHeader responseHeader = ResponseHeader.from(responseBody); From 46d938ae02fc7d718d6e237d43b31990a10e1e3c Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 14:03:09 +0900 Subject: [PATCH 08/16] =?UTF-8?q?refactor:=20Controller=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/jwp/DefaultController.java | 10 ++++- .../java/nextstep/jwp/HomeController.java | 10 ++++- .../java/nextstep/jwp/LoginController.java | 38 ++++++++++++++----- .../java/nextstep/jwp/RegisterController.java | 32 +++++++++++++--- .../apache/catalina/AbstractController.java | 14 +++---- .../java/org/apache/catalina/Controller.java | 2 +- .../apache/coyote/http11/Http11Processor.java | 10 ++--- .../coyote/http11/request/RequestLine.java | 9 ++++- .../coyote/http11/response/HttpResponse.java | 27 ++++++------- .../http11/response/HttpResponseTest.java | 25 ++++++------ 10 files changed, 113 insertions(+), 64 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/DefaultController.java b/tomcat/src/main/java/nextstep/jwp/DefaultController.java index f33b424aba..829fd80abc 100644 --- a/tomcat/src/main/java/nextstep/jwp/DefaultController.java +++ b/tomcat/src/main/java/nextstep/jwp/DefaultController.java @@ -7,13 +7,19 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import org.apache.coyote.http11.response.ResponseBody; +import org.apache.coyote.http11.response.ResponseHeader; +import org.apache.coyote.http11.response.StatusLine; public class DefaultController extends AbstractController { @Override - protected HttpResponse doGet(final HttpRequest request) throws IOException { + protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { final String resource = request.getRequestPath().getResource(); final ResponseBody responseBody = FileExtractor.extractFile(resource); - return HttpResponse.of(HttpStatusCode.OK, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.OK)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); } } diff --git a/tomcat/src/main/java/nextstep/jwp/HomeController.java b/tomcat/src/main/java/nextstep/jwp/HomeController.java index 943a9a7f65..a869426436 100644 --- a/tomcat/src/main/java/nextstep/jwp/HomeController.java +++ b/tomcat/src/main/java/nextstep/jwp/HomeController.java @@ -7,14 +7,20 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import org.apache.coyote.http11.response.ResponseBody; +import org.apache.coyote.http11.response.ResponseHeader; +import org.apache.coyote.http11.response.StatusLine; public class HomeController extends AbstractController { private static final String DEFAULT_CONTENT = "Hello world!"; @Override - protected HttpResponse doGet(final HttpRequest request) throws IOException { + protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { final ResponseBody responseBody = ResponseBody.of(ExtensionType.HTML.getExtension(), DEFAULT_CONTENT); - return HttpResponse.of(HttpStatusCode.OK, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.OK)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); } } diff --git a/tomcat/src/main/java/nextstep/jwp/LoginController.java b/tomcat/src/main/java/nextstep/jwp/LoginController.java index 5979ae324b..e312d021cf 100644 --- a/tomcat/src/main/java/nextstep/jwp/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/LoginController.java @@ -16,6 +16,8 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import org.apache.coyote.http11.response.ResponseBody; +import org.apache.coyote.http11.response.ResponseHeader; +import org.apache.coyote.http11.response.StatusLine; public class LoginController extends AbstractController { @@ -30,7 +32,7 @@ public class LoginController extends AbstractController { private static final String UNAUTHORIZED = "/401"; @Override - protected HttpResponse doPost(final HttpRequest request) throws IOException { + protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { try { final String userName = request.getRequestBody().get(ACCOUNT); final String password = request.getRequestBody().get(PASSWORD); @@ -43,14 +45,22 @@ protected HttpResponse doPost(final HttpRequest request) throws IOException { final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); checkSession(user, cookie); final ResponseBody responseBody = FileExtractor.extractFile(INDEX); - final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); - httpResponse.addCookie(cookie); - return httpResponse; + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.FOUND)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); + response.setCookie(cookie); + return; } throw new LoginException(); } catch (LoginException exception) { final ResponseBody responseBody = FileExtractor.extractFile(UNAUTHORIZED); - return HttpResponse.of(HttpStatusCode.UNAUTHORIZED, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.UNAUTHORIZED)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); } } @@ -64,17 +74,25 @@ private void checkSession(final User user, final HttpCookie cookie) { } @Override - protected HttpResponse doGet(final HttpRequest request) throws IOException { + protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); final String requestResource = request.getRequestPath().getResource(); if (cookie.contains(JSESSIONID)) { final ResponseBody responseBody = FileExtractor.extractFile(INDEX); - final HttpResponse httpResponse = HttpResponse.of(HttpStatusCode.FOUND, responseBody); - httpResponse.addCookie(cookie); - return httpResponse; + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.FOUND)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); + response.setCookie(cookie); + return; } final ResponseBody responseBody = FileExtractor.extractFile(requestResource); - return HttpResponse.of(HttpStatusCode.OK, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.OK)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); } } diff --git a/tomcat/src/main/java/nextstep/jwp/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/RegisterController.java index f7f9b72744..0c5ef99785 100644 --- a/tomcat/src/main/java/nextstep/jwp/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/RegisterController.java @@ -10,6 +10,8 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import org.apache.coyote.http11.response.ResponseBody; +import org.apache.coyote.http11.response.ResponseHeader; +import org.apache.coyote.http11.response.StatusLine; public class RegisterController extends AbstractController { @@ -22,7 +24,7 @@ public class RegisterController extends AbstractController { private static final String EMAIL = "email"; @Override - protected HttpResponse doPost(final HttpRequest request) throws IOException { + protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { final Map requestBody = request.getRequestBody(); final String account = requestBody.get(ACCOUNT); @@ -31,22 +33,40 @@ protected HttpResponse doPost(final HttpRequest request) throws IOException { if (account.isBlank() || password.isBlank() || email.isBlank()) { final ResponseBody responseBody = FileExtractor.extractFile(BAD_REQUEST); - return HttpResponse.of(HttpStatusCode.BAD_REQUEST, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.BAD_REQUEST)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); + return; } if (InMemoryUserRepository.checkExistingId(account)) { final ResponseBody responseBody = FileExtractor.extractFile(CONFLICT); - return HttpResponse.of(HttpStatusCode.OK, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.CONFLICT)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); + return; } final User user = new User(account, password, email); InMemoryUserRepository.save(user); final ResponseBody responseBody = FileExtractor.extractFile(INDEX); - return HttpResponse.of(HttpStatusCode.OK, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.OK)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); } @Override - protected HttpResponse doGet(final HttpRequest request) throws IOException { + protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { final ResponseBody responseBody = FileExtractor.extractFile(REGISTER); - return HttpResponse.of(HttpStatusCode.OK, responseBody); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); + + response.setStatusLine(new StatusLine(HttpStatusCode.OK)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); } } diff --git a/tomcat/src/main/java/org/apache/catalina/AbstractController.java b/tomcat/src/main/java/org/apache/catalina/AbstractController.java index 3d993e61eb..84f162f8ed 100644 --- a/tomcat/src/main/java/org/apache/catalina/AbstractController.java +++ b/tomcat/src/main/java/org/apache/catalina/AbstractController.java @@ -8,22 +8,22 @@ public class AbstractController implements Controller { @Override - public HttpResponse service(final HttpRequest request) throws IOException { + public void service(final HttpRequest request, final HttpResponse response) throws IOException { if (request.getHttpMethod().equals(HttpMethod.GET)) { - return doGet(request); + doGet(request, response); + return; } if (request.getHttpMethod().equals(HttpMethod.POST)) { - return doPost(request); + doPost(request, response); + return; } throw new UnsupportedOperationException(); } - protected HttpResponse doPost(final HttpRequest request) throws IOException { - return null; + protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { } - protected HttpResponse doGet(final HttpRequest request) throws IOException { - return null; + protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { } } diff --git a/tomcat/src/main/java/org/apache/catalina/Controller.java b/tomcat/src/main/java/org/apache/catalina/Controller.java index 00af3297e3..2d64f5efae 100644 --- a/tomcat/src/main/java/org/apache/catalina/Controller.java +++ b/tomcat/src/main/java/org/apache/catalina/Controller.java @@ -6,5 +6,5 @@ public interface Controller { - HttpResponse service(final HttpRequest request) throws IOException; + void service(final HttpRequest request, final HttpResponse response) throws IOException; } 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 127d0fddec..79515a5d37 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,10 +1,8 @@ package org.apache.coyote.http11; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; -import nextstep.jwp.exception.UncheckedServletException; import org.apache.catalina.Controller; import org.apache.catalina.RequestMapping; import org.apache.coyote.Processor; @@ -38,12 +36,14 @@ public void process(final Socket connection) { final HttpRequest httpRequest = HttpRequest.parse(bufferedReader); final RequestMapping requestMapping = new RequestMapping(); final Controller controller = requestMapping.getController(httpRequest); - final HttpResponse httpResponse = controller.service(httpRequest); - final String response = httpResponse.toString(); + final HttpResponse httpResponse = new HttpResponse(); + + controller.service(httpRequest, httpResponse); + final String response = httpResponse.toString(); outputStream.write(response.getBytes()); outputStream.flush(); - } catch (IOException | UncheckedServletException e) { + } catch (Exception e) { log.error(e.getMessage(), e); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java index 21cd56d814..927bb15271 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java @@ -5,6 +5,9 @@ public class RequestLine { private static final String BLANK_REGEX = " "; + private static final int METHOD_INDEX = 0; + private static final int PATH_INDEX = 1; + private static final int VERSION_INDEX = 2; private final HttpMethod httpMethod; private final RequestPath requestPath; @@ -22,7 +25,11 @@ public static RequestLine from(final String line) { } final String[] split = line.split(BLANK_REGEX); - return new RequestLine(HttpMethod.from(split[0]), RequestPath.from(split[1]), split[2]); + return new RequestLine( + HttpMethod.from(split[METHOD_INDEX]), + RequestPath.from(split[PATH_INDEX]), + split[VERSION_INDEX] + ); } public HttpMethod getHttpMethod() { 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 025bf3303f..31aaacdf3b 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,34 +1,29 @@ package org.apache.coyote.http11.response; import org.apache.coyote.http11.HttpCookie; -import org.apache.coyote.http11.HttpStatusCode; public class HttpResponse { private static final String CRLF = "\r\n"; - private final StatusLine statusLine; - private final ResponseHeader responseHeader; - private final ResponseBody responseBody; + private StatusLine statusLine; + private ResponseHeader responseHeader; + private ResponseBody responseBody; - private HttpResponse( - final StatusLine statusLine, - final ResponseHeader responseHeader, - final ResponseBody responseBody - ) { + public void setStatusLine(final StatusLine statusLine) { this.statusLine = statusLine; + } + + public void setResponseHeader(final ResponseHeader responseHeader) { this.responseHeader = responseHeader; - this.responseBody = responseBody; } - public static HttpResponse of(final HttpStatusCode httpStatusCode, final ResponseBody responseBody) { - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - final StatusLine statusLine = new StatusLine(httpStatusCode); - return new HttpResponse(statusLine, responseHeader, responseBody); + public void setResponseBody(final ResponseBody responseBody) { + this.responseBody = responseBody; } - public void addCookie(final HttpCookie httpCookie) { - responseHeader.addCookie(httpCookie); + public void setCookie(final HttpCookie httpCookie) { + this.responseHeader.addCookie(httpCookie); } public StatusLine getStatusLine() { diff --git a/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java b/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java index 476e99ba0e..bfe00e9f53 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/response/HttpResponseTest.java @@ -1,31 +1,28 @@ package org.apache.coyote.http11.response; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import org.apache.coyote.http11.HttpStatusCode; +import org.apache.coyote.http11.ExtensionType; +import org.apache.coyote.http11.HttpCookie; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class HttpResponseTest { - @DisplayName("HttpStatusCode와 ResponseBody로 HttpResponse를 만들 수 있다.") + @DisplayName("Response에 Cookie를 추가할 수 있다.") @Test - void of() { + void setCookie() { // given - final ResponseBody responseBody = ResponseBody.of("index.html", "/index.html"); - final HttpStatusCode httpStatusCode = HttpStatusCode.OK; + final HttpResponse httpResponse = new HttpResponse(); + final ResponseBody responseBody = ResponseBody.of(ExtensionType.HTML.getExtension(), "test"); + httpResponse.setResponseHeader(ResponseHeader.from(responseBody)); + + final HttpCookie httpCookie = new HttpCookie(); // when - final HttpResponse httpResponse = HttpResponse.of(httpStatusCode, responseBody); + httpResponse.setCookie(httpCookie); // then - assertAll( - () -> assertThat(httpResponse.getStatusLine()).usingRecursiveComparison() - .isEqualTo(new StatusLine(httpStatusCode)), - () -> assertThat(httpResponse.getResponseHeaders()).usingRecursiveComparison() - .isEqualTo(ResponseHeader.from(responseBody)), - () -> assertThat(httpResponse.getResponseBody()).isEqualTo(responseBody) - ); + assertThat(httpResponse.getResponseHeaders().getValue("Set-Cookie")).isNotNull(); } } From 5f41b2826c1adc9a6de1a3363d7c8bae8b2a8ce7 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 14:03:46 +0900 Subject: [PATCH 09/16] =?UTF-8?q?refactor:=20sessions=20=EC=86=8C=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/catalina/SessionManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/SessionManager.java index 22baaaf152..188284b11f 100644 --- a/tomcat/src/main/java/org/apache/catalina/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/SessionManager.java @@ -6,20 +6,20 @@ public class SessionManager implements Manager { - private static final Map SESSIONS = new ConcurrentHashMap<>(); + private static final Map sessions = new ConcurrentHashMap<>(); @Override public void add(final Session session) { - SESSIONS.put(session.getId(), session); + sessions.put(session.getId(), session); } @Override public Session findSession(final String id) { - return SESSIONS.get(id); + return sessions.get(id); } @Override public void remove(final Session session) { - SESSIONS.remove(session.getId()); + sessions.remove(session.getId()); } } From 75667513e1f7ae97a270015efc8d6e98559cce11 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 14:37:27 +0900 Subject: [PATCH 10/16] =?UTF-8?q?refactor:=20doPost=EC=99=80=20doGet=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/jwp/DefaultController.java | 15 ++++----- .../java/nextstep/jwp/HomeController.java | 5 +++ .../java/nextstep/jwp/LoginController.java | 32 +++---------------- .../java/nextstep/jwp/RegisterController.java | 32 +++---------------- .../apache/catalina/AbstractController.java | 23 ++++++++++--- .../apache/coyote/http11/HttpStatusCode.java | 3 +- 6 files changed, 40 insertions(+), 70 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/DefaultController.java b/tomcat/src/main/java/nextstep/jwp/DefaultController.java index 829fd80abc..ead9a2f94d 100644 --- a/tomcat/src/main/java/nextstep/jwp/DefaultController.java +++ b/tomcat/src/main/java/nextstep/jwp/DefaultController.java @@ -2,24 +2,21 @@ import java.io.IOException; import org.apache.catalina.AbstractController; -import org.apache.coyote.http11.FileExtractor; import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; -import org.apache.coyote.http11.response.ResponseBody; -import org.apache.coyote.http11.response.ResponseHeader; -import org.apache.coyote.http11.response.StatusLine; public class DefaultController extends AbstractController { + @Override + protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { + setResponse(response, "/500", HttpStatusCode.INTERNAL_SERVER_ERROR); + } + @Override protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { final String resource = request.getRequestPath().getResource(); - final ResponseBody responseBody = FileExtractor.extractFile(resource); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - response.setStatusLine(new StatusLine(HttpStatusCode.OK)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, resource, HttpStatusCode.OK); } } diff --git a/tomcat/src/main/java/nextstep/jwp/HomeController.java b/tomcat/src/main/java/nextstep/jwp/HomeController.java index a869426436..c7ecfad5e3 100644 --- a/tomcat/src/main/java/nextstep/jwp/HomeController.java +++ b/tomcat/src/main/java/nextstep/jwp/HomeController.java @@ -14,6 +14,11 @@ public class HomeController extends AbstractController { private static final String DEFAULT_CONTENT = "Hello world!"; + @Override + protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { + setResponse(response, "/500", HttpStatusCode.INTERNAL_SERVER_ERROR); + } + @Override protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { final ResponseBody responseBody = ResponseBody.of(ExtensionType.HTML.getExtension(), DEFAULT_CONTENT); diff --git a/tomcat/src/main/java/nextstep/jwp/LoginController.java b/tomcat/src/main/java/nextstep/jwp/LoginController.java index e312d021cf..b84762093e 100644 --- a/tomcat/src/main/java/nextstep/jwp/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/LoginController.java @@ -9,15 +9,11 @@ import nextstep.jwp.model.User; import org.apache.catalina.AbstractController; import org.apache.catalina.SessionManager; -import org.apache.coyote.http11.FileExtractor; import org.apache.coyote.http11.HttpCookie; import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.Session; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; -import org.apache.coyote.http11.response.ResponseBody; -import org.apache.coyote.http11.response.ResponseHeader; -import org.apache.coyote.http11.response.StatusLine; public class LoginController extends AbstractController { @@ -44,23 +40,13 @@ protected void doPost(final HttpRequest request, final HttpResponse response) th log.info("user : " + user); final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); checkSession(user, cookie); - final ResponseBody responseBody = FileExtractor.extractFile(INDEX); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.FOUND)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, INDEX, HttpStatusCode.FOUND); response.setCookie(cookie); return; } throw new LoginException(); } catch (LoginException exception) { - final ResponseBody responseBody = FileExtractor.extractFile(UNAUTHORIZED); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.UNAUTHORIZED)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, UNAUTHORIZED, HttpStatusCode.UNAUTHORIZED); } } @@ -79,20 +65,10 @@ protected void doGet(final HttpRequest request, final HttpResponse response) thr final String requestResource = request.getRequestPath().getResource(); if (cookie.contains(JSESSIONID)) { - final ResponseBody responseBody = FileExtractor.extractFile(INDEX); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.FOUND)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, INDEX, HttpStatusCode.FOUND); response.setCookie(cookie); return; } - final ResponseBody responseBody = FileExtractor.extractFile(requestResource); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.OK)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, requestResource, HttpStatusCode.OK); } } diff --git a/tomcat/src/main/java/nextstep/jwp/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/RegisterController.java index 0c5ef99785..3c233bb234 100644 --- a/tomcat/src/main/java/nextstep/jwp/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/RegisterController.java @@ -5,13 +5,9 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.model.User; import org.apache.catalina.AbstractController; -import org.apache.coyote.http11.FileExtractor; import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; -import org.apache.coyote.http11.response.ResponseBody; -import org.apache.coyote.http11.response.ResponseHeader; -import org.apache.coyote.http11.response.StatusLine; public class RegisterController extends AbstractController { @@ -32,41 +28,21 @@ protected void doPost(final HttpRequest request, final HttpResponse response) th final String email = requestBody.get(EMAIL); if (account.isBlank() || password.isBlank() || email.isBlank()) { - final ResponseBody responseBody = FileExtractor.extractFile(BAD_REQUEST); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.BAD_REQUEST)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, BAD_REQUEST, HttpStatusCode.BAD_REQUEST); return; } if (InMemoryUserRepository.checkExistingId(account)) { - final ResponseBody responseBody = FileExtractor.extractFile(CONFLICT); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.CONFLICT)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, CONFLICT, HttpStatusCode.CONFLICT); return; } final User user = new User(account, password, email); InMemoryUserRepository.save(user); - final ResponseBody responseBody = FileExtractor.extractFile(INDEX); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.OK)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, INDEX, HttpStatusCode.OK); } @Override protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { - final ResponseBody responseBody = FileExtractor.extractFile(REGISTER); - final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - - response.setStatusLine(new StatusLine(HttpStatusCode.OK)); - response.setResponseHeader(responseHeader); - response.setResponseBody(responseBody); + setResponse(response, REGISTER, HttpStatusCode.OK); } } diff --git a/tomcat/src/main/java/org/apache/catalina/AbstractController.java b/tomcat/src/main/java/org/apache/catalina/AbstractController.java index 84f162f8ed..2cd8c3058d 100644 --- a/tomcat/src/main/java/org/apache/catalina/AbstractController.java +++ b/tomcat/src/main/java/org/apache/catalina/AbstractController.java @@ -1,11 +1,16 @@ package org.apache.catalina; import java.io.IOException; +import org.apache.coyote.http11.FileExtractor; +import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.request.HttpMethod; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.ResponseBody; +import org.apache.coyote.http11.response.ResponseHeader; +import org.apache.coyote.http11.response.StatusLine; -public class AbstractController implements Controller { +public abstract class AbstractController implements Controller { @Override public void service(final HttpRequest request, final HttpResponse response) throws IOException { @@ -20,10 +25,20 @@ public void service(final HttpRequest request, final HttpResponse response) thro throw new UnsupportedOperationException(); } + protected abstract void doPost(HttpRequest request, HttpResponse response) throws IOException; - protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { - } + protected abstract void doGet(final HttpRequest request, final HttpResponse response) throws IOException; + + protected void setResponse( + final HttpResponse response, + final String resource, + final HttpStatusCode statusCode + ) throws IOException { + final ResponseBody responseBody = FileExtractor.extractFile(resource); + final ResponseHeader responseHeader = ResponseHeader.from(responseBody); - protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { + response.setStatusLine(new StatusLine(statusCode)); + response.setResponseHeader(responseHeader); + response.setResponseBody(responseBody); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java index 67c81eb5ce..c037780b1a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java @@ -8,7 +8,8 @@ public enum HttpStatusCode { BAD_REQUEST(400, "Bad Request"), UNAUTHORIZED(401, "Unauthorized"), NOT_FOUND(404, "Not Found"), - CONFLICT(409, "Conflict"); + CONFLICT(409, "Conflict"), + INTERNAL_SERVER_ERROR(500, "Internal Server Error"); private final int code; private final String message; From a0278bdc338d4ae8307e737bae6338ee8c64858f Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 14:37:58 +0900 Subject: [PATCH 11/16] =?UTF-8?q?refactor:=20Id=20or=20Password=EC=97=90?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=20=EC=97=86=EC=9D=84=20=EB=96=84=20400?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/nextstep/jwp/LoginController.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tomcat/src/main/java/nextstep/jwp/LoginController.java b/tomcat/src/main/java/nextstep/jwp/LoginController.java index b84762093e..4ecccf2e1b 100644 --- a/tomcat/src/main/java/nextstep/jwp/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/LoginController.java @@ -26,6 +26,7 @@ public class LoginController extends AbstractController { private static final String COOKIE = "Cookie"; private static final String USER = "user"; private static final String UNAUTHORIZED = "/401"; + private static final String BAD_REQUEST = "/400"; @Override protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { @@ -33,6 +34,11 @@ protected void doPost(final HttpRequest request, final HttpResponse response) th final String userName = request.getRequestBody().get(ACCOUNT); final String password = request.getRequestBody().get(PASSWORD); + if (userName.isBlank() || password.isBlank()) { + setResponse(response, BAD_REQUEST, HttpStatusCode.BAD_REQUEST); + return; + } + final User user = InMemoryUserRepository.findByAccount(userName) .orElseThrow(LoginException::new); From 304fe4d48c7af5b07ab201d57c77e59850663f31 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 14:43:30 +0900 Subject: [PATCH 12/16] =?UTF-8?q?refactor:=20log=20=EA=B4=80=EB=A0=A8=20so?= =?UTF-8?q?narCube=20=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/nextstep/jwp/LoginController.java | 2 -- .../src/main/java/org/apache/catalina/AbstractController.java | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/LoginController.java b/tomcat/src/main/java/nextstep/jwp/LoginController.java index 4ecccf2e1b..70c9c137f7 100644 --- a/tomcat/src/main/java/nextstep/jwp/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/LoginController.java @@ -1,7 +1,5 @@ package nextstep.jwp; -import static org.reflections.Reflections.log; - import java.io.IOException; import java.util.UUID; import nextstep.jwp.db.InMemoryUserRepository; diff --git a/tomcat/src/main/java/org/apache/catalina/AbstractController.java b/tomcat/src/main/java/org/apache/catalina/AbstractController.java index 2cd8c3058d..155933ee62 100644 --- a/tomcat/src/main/java/org/apache/catalina/AbstractController.java +++ b/tomcat/src/main/java/org/apache/catalina/AbstractController.java @@ -9,9 +9,13 @@ import org.apache.coyote.http11.response.ResponseBody; import org.apache.coyote.http11.response.ResponseHeader; import org.apache.coyote.http11.response.StatusLine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class AbstractController implements Controller { + protected static final Logger log = LoggerFactory.getLogger(AbstractController.class); + @Override public void service(final HttpRequest request, final HttpResponse response) throws IOException { if (request.getHttpMethod().equals(HttpMethod.GET)) { From c5d20eb44272ac81ee74266175d13b9976879801 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 16:09:55 +0900 Subject: [PATCH 13/16] =?UTF-8?q?refactor:=20NotAllowedExtensionException?= =?UTF-8?q?=20=EC=9C=BC=EB=A1=9C=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20=EC=84=B8=EB=B6=84=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/exception/NotAllowedExtensionException.java | 8 ++++++++ .../main/java/org/apache/coyote/http11/ExtensionType.java | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 tomcat/src/main/java/nextstep/jwp/exception/NotAllowedExtensionException.java diff --git a/tomcat/src/main/java/nextstep/jwp/exception/NotAllowedExtensionException.java b/tomcat/src/main/java/nextstep/jwp/exception/NotAllowedExtensionException.java new file mode 100644 index 0000000000..8c8813a790 --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/exception/NotAllowedExtensionException.java @@ -0,0 +1,8 @@ +package nextstep.jwp.exception; + +public class NotAllowedExtensionException extends RuntimeException { + + public NotAllowedExtensionException() { + super("해당하는 Extension이 존재하지 않습니다."); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/ExtensionType.java b/tomcat/src/main/java/org/apache/coyote/http11/ExtensionType.java index 31a6e9cdba..9b80c1c1a7 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/ExtensionType.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/ExtensionType.java @@ -1,7 +1,7 @@ package org.apache.coyote.http11; import java.util.Arrays; -import nextstep.jwp.exception.NotAllowedMethodException; +import nextstep.jwp.exception.NotAllowedExtensionException; public enum ExtensionType { @@ -23,7 +23,7 @@ public static ExtensionType from(final String extension) { return Arrays.stream(values()) .filter(it -> extension.contains(it.extension)) .findAny() - .orElseThrow(NotAllowedMethodException::new); + .orElseThrow(NotAllowedExtensionException::new); } public String getExtension() { From 51ca60f51d6edaf4c03448edac3b872910180e97 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 17:17:37 +0900 Subject: [PATCH 14/16] =?UTF-8?q?refactor:=20Controller=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/nextstep/Application.java | 6 +++++ .../java/org/apache/catalina/Controller.java | 16 ++++++++++++ .../apache/catalina}/DefaultController.java | 7 ++--- .../org/apache/catalina/RequestMapping.java | 26 +++++++------------ .../apache/catalina/connector/Connector.java | 11 +++++--- .../org/apache/catalina/startup/Tomcat.java | 10 ++++++- .../apache/coyote/http11/Http11Processor.java | 8 +++--- 7 files changed, 57 insertions(+), 27 deletions(-) rename tomcat/src/main/java/{nextstep/jwp => org/apache/catalina}/DefaultController.java (77%) diff --git a/tomcat/src/main/java/nextstep/Application.java b/tomcat/src/main/java/nextstep/Application.java index 3dd7593507..4a6c27696f 100644 --- a/tomcat/src/main/java/nextstep/Application.java +++ b/tomcat/src/main/java/nextstep/Application.java @@ -1,11 +1,17 @@ package nextstep; +import nextstep.jwp.HomeController; +import nextstep.jwp.LoginController; +import nextstep.jwp.RegisterController; import org.apache.catalina.startup.Tomcat; public class Application { public static void main(String[] args) { final var tomcat = new Tomcat(); + tomcat.addController("/", new HomeController()); + tomcat.addController("/login", new LoginController()); + tomcat.addController("register", new RegisterController()); tomcat.start(); } } diff --git a/tomcat/src/main/java/org/apache/catalina/Controller.java b/tomcat/src/main/java/org/apache/catalina/Controller.java index 2d64f5efae..a633d5b916 100644 --- a/tomcat/src/main/java/org/apache/catalina/Controller.java +++ b/tomcat/src/main/java/org/apache/catalina/Controller.java @@ -1,10 +1,26 @@ package org.apache.catalina; import java.io.IOException; +import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; public interface Controller { void service(final HttpRequest request, final HttpResponse response) throws IOException; + + class DefaultController extends AbstractController { + + @Override + protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { + setResponse(response, "/500", HttpStatusCode.INTERNAL_SERVER_ERROR); + } + + @Override + protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { + final String resource = request.getRequestPath().getResource(); + + setResponse(response, resource, HttpStatusCode.OK); + } + } } diff --git a/tomcat/src/main/java/nextstep/jwp/DefaultController.java b/tomcat/src/main/java/org/apache/catalina/DefaultController.java similarity index 77% rename from tomcat/src/main/java/nextstep/jwp/DefaultController.java rename to tomcat/src/main/java/org/apache/catalina/DefaultController.java index ead9a2f94d..1be0aa3e7c 100644 --- a/tomcat/src/main/java/nextstep/jwp/DefaultController.java +++ b/tomcat/src/main/java/org/apache/catalina/DefaultController.java @@ -1,16 +1,17 @@ -package nextstep.jwp; +package org.apache.catalina; import java.io.IOException; -import org.apache.catalina.AbstractController; import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; public class DefaultController extends AbstractController { + private static final String INTERNAL_SERVER_ERROR = "/500"; + @Override protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { - setResponse(response, "/500", HttpStatusCode.INTERNAL_SERVER_ERROR); + setResponse(response, INTERNAL_SERVER_ERROR, HttpStatusCode.INTERNAL_SERVER_ERROR); } @Override diff --git a/tomcat/src/main/java/org/apache/catalina/RequestMapping.java b/tomcat/src/main/java/org/apache/catalina/RequestMapping.java index ee17e8431e..35fc2ed248 100644 --- a/tomcat/src/main/java/org/apache/catalina/RequestMapping.java +++ b/tomcat/src/main/java/org/apache/catalina/RequestMapping.java @@ -1,26 +1,20 @@ package org.apache.catalina; -import nextstep.jwp.DefaultController; -import nextstep.jwp.HomeController; -import nextstep.jwp.LoginController; -import nextstep.jwp.RegisterController; +import java.util.HashMap; +import java.util.Map; +import org.apache.catalina.Controller.DefaultController; import org.apache.coyote.http11.request.HttpRequest; public class RequestMapping { - public Controller getController(final HttpRequest request) { - final String resource = request.getRequestPath().getResource(); + private final Map mapper = new HashMap<>(); - if (resource.equals("/")) { - return new HomeController(); - } - if (resource.equals("/login")) { - return new LoginController(); - } - if (resource.equals("/register")) { - return new RegisterController(); - } + public void put(final String path, final Controller controller) { + this.mapper.put(path, controller); + } - return new DefaultController(); + public Controller getController(final HttpRequest request) { + final String resource = request.getRequestPath().getResource(); + return mapper.getOrDefault(resource, new DefaultController()); } } diff --git a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java index 9d4a0407c7..66866a1761 100644 --- a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java +++ b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java @@ -6,6 +6,7 @@ import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.apache.catalina.RequestMapping; import org.apache.coyote.http11.Http11Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,18 +19,20 @@ public class Connector implements Runnable { private static final int DEFAULT_ACCEPT_COUNT = 100; private static final int DEFAULT_THREAD_COUNT = 200; + private final RequestMapping requestMapping; private final ServerSocket serverSocket; private final ExecutorService executorService; private boolean stopped; - public Connector() { - this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_THREAD_COUNT); + public Connector(final RequestMapping mapping) { + this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_THREAD_COUNT, mapping); } - public Connector(final int port, final int acceptCount, final int threadCount) { + public Connector(final int port, final int acceptCount, final int threadCount, final RequestMapping mapping) { this.serverSocket = createServerSocket(port, acceptCount); this.stopped = false; this.executorService = Executors.newFixedThreadPool(threadCount); + this.requestMapping = mapping; } private ServerSocket createServerSocket(final int port, final int acceptCount) { @@ -70,7 +73,7 @@ private void process(final Socket connection) { if (connection == null) { return; } - var processor = new Http11Processor(connection); + var processor = new Http11Processor(connection, requestMapping); executorService.execute(processor); } diff --git a/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java b/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java index 390589fad4..9e00173a04 100644 --- a/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java +++ b/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java @@ -1,6 +1,8 @@ package org.apache.catalina.startup; import java.io.IOException; +import org.apache.catalina.Controller; +import org.apache.catalina.RequestMapping; import org.apache.catalina.connector.Connector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -9,8 +11,10 @@ public class Tomcat { private static final Logger log = LoggerFactory.getLogger(Tomcat.class); + private final RequestMapping requestMapping = new RequestMapping(); + public void start() { - var connector = new Connector(); + var connector = new Connector(requestMapping); connector.start(); try { @@ -23,4 +27,8 @@ public void start() { connector.stop(); } } + + public void addController(final String path, final Controller controller) { + requestMapping.put(path, controller); + } } 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 79515a5d37..ec869f9bda 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -15,10 +15,13 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); + private final RequestMapping mapping; + private final Socket connection; - public Http11Processor(final Socket connection) { + public Http11Processor(final Socket connection, RequestMapping mapping) { this.connection = connection; + this.mapping = mapping; } @Override @@ -34,8 +37,7 @@ public void process(final Socket connection) { final var bufferedReader = new BufferedReader(new InputStreamReader(inputStream)) ) { final HttpRequest httpRequest = HttpRequest.parse(bufferedReader); - final RequestMapping requestMapping = new RequestMapping(); - final Controller controller = requestMapping.getController(httpRequest); + final Controller controller = mapping.getController(httpRequest); final HttpResponse httpResponse = new HttpResponse(); controller.service(httpRequest, httpResponse); From f53d16fab51822cf901aa8e66ff4d889e8df851b Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 17:23:55 +0900 Subject: [PATCH 15/16] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/http11/FileExtractor.java | 3 +++ .../java/org/apache/coyote/http11/ExtensionTypeTest.java | 6 +++--- .../org/apache/coyote/http11/Http11ProcessorTest.java | 9 +++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java b/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java index c7c7431cb0..bd43f6f353 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/FileExtractor.java @@ -26,6 +26,9 @@ public static ResponseBody extractFile(final String resource) throws IOException private static ResponseBody extractHtmlFile(final String resource) throws IOException { final URL url = CLASSLOADER.getResource(STATIC + resource + ExtensionType.HTML.getExtension()); + if (url == null) { + return ResponseBody.html("Hello world!"); + } return ResponseBody.of(ExtensionType.HTML.getExtension(), makeBodyContent(url)); } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/ExtensionTypeTest.java b/tomcat/src/test/java/org/apache/coyote/http11/ExtensionTypeTest.java index 765aed0b0e..1959d51e98 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/ExtensionTypeTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/ExtensionTypeTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import nextstep.jwp.exception.NotAllowedMethodException; +import nextstep.jwp.exception.NotAllowedExtensionException; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,7 +31,7 @@ void from_emptyExtension() { // when & then assertThatThrownBy(() -> ExtensionType.from(extension)) - .isInstanceOf(NotAllowedMethodException.class) - .hasMessage("해당하는 Method가 존재하지 않습니다."); + .isInstanceOf(NotAllowedExtensionException.class) + .hasMessage("해당하는 Extension이 존재하지 않습니다."); } } 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 98282f4144..410aff206c 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.net.URL; import java.nio.file.Files; +import org.apache.catalina.RequestMapping; import org.junit.jupiter.api.Test; import support.StubSocket; @@ -15,7 +16,7 @@ class Http11ProcessorTest { void process() { // given final var socket = new StubSocket(); - final var processor = new Http11Processor(socket); + final var processor = new Http11Processor(socket, new RequestMapping()); // when processor.process(socket); @@ -34,7 +35,7 @@ void process() { @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 ", @@ -42,7 +43,7 @@ void index() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(socket, new RequestMapping()); // when processor.process(socket); @@ -52,7 +53,7 @@ void index() throws IOException { var expected = "HTTP/1.1 200 OK \r\n" + "Content-Type: text/html;charset=utf-8 \r\n" + "Content-Length: 5564 \r\n" + - "\r\n"+ + "\r\n" + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); assertThat(socket.output()).isEqualTo(expected); From d3994c89b3e44e00215453f17609f4b05d12b1db Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 11 Sep 2023 17:32:34 +0900 Subject: [PATCH 16/16] =?UTF-8?q?refactor:=20DefaultController=20=EB=8B=A4?= =?UTF-8?q?=EC=8B=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/catalina/Controller.java | 16 ---------------- .../java/org/apache/catalina/RequestMapping.java | 1 - 2 files changed, 17 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/Controller.java b/tomcat/src/main/java/org/apache/catalina/Controller.java index a633d5b916..2d64f5efae 100644 --- a/tomcat/src/main/java/org/apache/catalina/Controller.java +++ b/tomcat/src/main/java/org/apache/catalina/Controller.java @@ -1,26 +1,10 @@ package org.apache.catalina; import java.io.IOException; -import org.apache.coyote.http11.HttpStatusCode; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; public interface Controller { void service(final HttpRequest request, final HttpResponse response) throws IOException; - - class DefaultController extends AbstractController { - - @Override - protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { - setResponse(response, "/500", HttpStatusCode.INTERNAL_SERVER_ERROR); - } - - @Override - protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { - final String resource = request.getRequestPath().getResource(); - - setResponse(response, resource, HttpStatusCode.OK); - } - } } diff --git a/tomcat/src/main/java/org/apache/catalina/RequestMapping.java b/tomcat/src/main/java/org/apache/catalina/RequestMapping.java index 35fc2ed248..31f8b33f2a 100644 --- a/tomcat/src/main/java/org/apache/catalina/RequestMapping.java +++ b/tomcat/src/main/java/org/apache/catalina/RequestMapping.java @@ -2,7 +2,6 @@ import java.util.HashMap; import java.util.Map; -import org.apache.catalina.Controller.DefaultController; import org.apache.coyote.http11.request.HttpRequest; public class RequestMapping {