From caae46af8510526d013b227fc503c19331fe55f8 Mon Sep 17 00:00:00 2001 From: Jang Hyeok-su <76612738+zangsu@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:37:11 +0900 Subject: [PATCH 01/37] =?UTF-8?q?=EC=9D=B4=EC=8A=88=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/Feature Template | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Feature Template diff --git a/.github/ISSUE_TEMPLATE/Feature Template b/.github/ISSUE_TEMPLATE/Feature Template new file mode 100644 index 0000000000..2de2c831b2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature Template @@ -0,0 +1,23 @@ +--- +name: Feature Template +about: 기능 추가 이슈 템플릿 +title: "[FEAT] " +labels: feature +assignees: '' + +--- + +## 📌 어떤 기능인가요? +> 추가하려는 기능에 대해 간결하게 설명해주세요 + + +## 📜 작업 상세 내용 +- [ ] TODO +- [ ] TODO +- [ ] TODO + +## ⏳ 예상 소요 시간 +> 이슈를 완료하기까지 예상되는 소요 시간을 분 or 시간 or 일 단위로 작성해주세요. + + +## 🔍 참고할만한 자료(선택) From fed02f6f5f4308400e55c160d9495cad010f5bfb Mon Sep 17 00:00:00 2001 From: Gyeongho Yang Date: Thu, 5 Sep 2024 11:11:09 +0900 Subject: [PATCH 02/37] fix: remove implementation logback-classic on gradle (#501) --- study/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/study/build.gradle b/study/build.gradle index 5c69542f84..87a1f0313c 100644 --- a/study/build.gradle +++ b/study/build.gradle @@ -19,7 +19,6 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-webflux' - implementation 'ch.qos.logback:logback-classic:1.5.7' implementation 'org.apache.commons:commons-lang3:3.14.0' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1' From 7e9135698878932274ddc1f523ba817ed9c56c70 Mon Sep 17 00:00:00 2001 From: Gyeongho Yang Date: Thu, 5 Sep 2024 13:51:07 +0900 Subject: [PATCH 03/37] fix: add threads min-spare configuration on properties (#502) --- study/src/main/resources/application.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml index 4e8655a962..e3503a5fb9 100644 --- a/study/src/main/resources/application.yml +++ b/study/src/main/resources/application.yml @@ -6,4 +6,5 @@ server: accept-count: 1 max-connections: 1 threads: + min-spare: 2 max: 2 From 2466ea2071ef7e6a60f906df628ff11b6dc5146e Mon Sep 17 00:00:00 2001 From: zangsu Date: Thu, 12 Sep 2024 21:39:37 +0900 Subject: [PATCH 04/37] =?UTF-8?q?chore:=20=EC=84=B8=EC=85=98=EC=9D=80=20Ht?= =?UTF-8?q?tp=20=EC=97=90=20=EC=A2=85=EC=86=8D=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EC=A1=B4=EC=9E=AC=EA=B0=80=20=EC=95=84=EB=8B=88=EB=AF=80?= =?UTF-8?q?=EB=A1=9C=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/catalina/Manager.java | 2 +- .../apache/coyote/http11/handler/DefaultResourceHandler.java | 4 ++-- .../org/apache/coyote/http11/httpmessage/request/Request.java | 4 ++-- .../java/org/apache/coyote/{http11 => }/session/Session.java | 2 +- .../apache/coyote/{http11 => }/session/SessionManager.java | 2 +- .../java/org/apache/coyote/http11/Http11ProcessorTest.java | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) rename tomcat/src/main/java/org/apache/coyote/{http11 => }/session/Session.java (93%) rename tomcat/src/main/java/org/apache/coyote/{http11 => }/session/SessionManager.java (94%) diff --git a/tomcat/src/main/java/org/apache/catalina/Manager.java b/tomcat/src/main/java/org/apache/catalina/Manager.java index fd850c6558..4c5392254c 100644 --- a/tomcat/src/main/java/org/apache/catalina/Manager.java +++ b/tomcat/src/main/java/org/apache/catalina/Manager.java @@ -2,7 +2,7 @@ import java.io.IOException; -import org.apache.coyote.http11.session.Session; +import org.apache.coyote.session.Session; /** * A Manager manages the pool of Sessions that are associated with a diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java index fcca082d83..df7b3b47fa 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java @@ -9,8 +9,8 @@ import org.apache.coyote.http11.httpmessage.request.Request; import org.apache.coyote.http11.httpmessage.response.Response; import org.apache.coyote.http11.httpmessage.response.StaticResource; -import org.apache.coyote.http11.session.Session; -import org.apache.coyote.http11.session.SessionManager; +import org.apache.coyote.session.Session; +import org.apache.coyote.session.SessionManager; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Request.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Request.java index 83798f2c7d..4d8c2ad1a9 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Request.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Request.java @@ -8,8 +8,8 @@ import org.apache.coyote.http11.httpmessage.HttpCookie; import org.apache.coyote.http11.httpmessage.HttpHeaders; -import org.apache.coyote.http11.session.Session; -import org.apache.coyote.http11.session.SessionManager; +import org.apache.coyote.session.Session; +import org.apache.coyote.session.SessionManager; public class Request { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/session/Session.java b/tomcat/src/main/java/org/apache/coyote/session/Session.java similarity index 93% rename from tomcat/src/main/java/org/apache/coyote/http11/session/Session.java rename to tomcat/src/main/java/org/apache/coyote/session/Session.java index ba63df869d..c1c2f41b55 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/session/Session.java +++ b/tomcat/src/main/java/org/apache/coyote/session/Session.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11.session; +package org.apache.coyote.session; import java.util.HashMap; import java.util.Map; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java b/tomcat/src/main/java/org/apache/coyote/session/SessionManager.java similarity index 94% rename from tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java rename to tomcat/src/main/java/org/apache/coyote/session/SessionManager.java index 277c87c3e1..482a7a8967 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java +++ b/tomcat/src/main/java/org/apache/coyote/session/SessionManager.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11.session; +package org.apache.coyote.session; import java.util.HashMap; import java.util.Map; 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 a521e0059a..83ccfbbeb2 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -7,8 +7,8 @@ import java.net.URL; import java.nio.file.Files; -import org.apache.coyote.http11.session.Session; -import org.apache.coyote.http11.session.SessionManager; +import org.apache.coyote.session.Session; +import org.apache.coyote.session.SessionManager; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; From 76e056beb1fcab0782454ec56d2465df3a1c87b6 Mon Sep 17 00:00:00 2001 From: zangsu Date: Thu, 12 Sep 2024 21:40:43 +0900 Subject: [PATCH 05/37] =?UTF-8?q?chore:=20RequestParameters=20=EB=8A=94=20?= =?UTF-8?q?Http=20=EC=9A=94=EC=B2=AD=EC=97=90=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=EB=90=9C=20=EA=B0=9D=EC=B2=B4=EC=9D=B4=EB=AF=80=EB=A1=9C=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/handler/DefaultResourceHandler.java | 1 + .../{handler => httpmessage/request}/RequestParameters.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename tomcat/src/main/java/org/apache/coyote/http11/{handler => httpmessage/request}/RequestParameters.java (94%) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java index df7b3b47fa..ac0a47f2b5 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java @@ -7,6 +7,7 @@ import org.apache.coyote.http11.exception.CanNotHandleRequest; import org.apache.coyote.http11.exception.NoSuchUserException; import org.apache.coyote.http11.httpmessage.request.Request; +import org.apache.coyote.http11.httpmessage.request.RequestParameters; import org.apache.coyote.http11.httpmessage.response.Response; import org.apache.coyote.http11.httpmessage.response.StaticResource; import org.apache.coyote.session.Session; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/RequestParameters.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestParameters.java similarity index 94% rename from tomcat/src/main/java/org/apache/coyote/http11/handler/RequestParameters.java rename to tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestParameters.java index f75590253a..aff6af689f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/RequestParameters.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestParameters.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11.handler; +package org.apache.coyote.http11.httpmessage.request; import java.util.HashMap; import java.util.Map; From 5faa10c193a1405e00b0bc824775c2d76e7d31af Mon Sep 17 00:00:00 2001 From: zangsu Date: Thu, 12 Sep 2024 22:29:03 +0900 Subject: [PATCH 06/37] =?UTF-8?q?refactor:=20RequestLine=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/build.gradle | 1 + .../IllegalHttpMessageException.java | 7 ++ .../httpmessage/request/RequestLine.java | 5 + .../httpmessage/request/RequestLineTest.java | 95 +++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/exception/IllegalHttpMessageException.java create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestLineTest.java diff --git a/tomcat/build.gradle b/tomcat/build.gradle index ba598c228d..c5f1fbb5ca 100644 --- a/tomcat/build.gradle +++ b/tomcat/build.gradle @@ -25,6 +25,7 @@ dependencies { testImplementation 'org.mockito:mockito-core:5.12.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2' } test { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/exception/IllegalHttpMessageException.java b/tomcat/src/main/java/org/apache/coyote/http11/exception/IllegalHttpMessageException.java new file mode 100644 index 0000000000..206ed000b1 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/exception/IllegalHttpMessageException.java @@ -0,0 +1,7 @@ +package org.apache.coyote.http11.exception; + +public class IllegalHttpMessageException extends RuntimeException { + public IllegalHttpMessageException(String message) { + super(message); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestLine.java index 66cad8037e..21ad6c05df 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestLine.java @@ -1,5 +1,7 @@ package org.apache.coyote.http11.httpmessage.request; +import org.apache.coyote.http11.exception.IllegalHttpMessageException; + public record RequestLine ( Method method, String target, @@ -8,6 +10,9 @@ public record RequestLine ( public static RequestLine parseFrom(String requestLineText) { String[] token = requestLineText.split(" "); + if (token.length != 3) { + throw new IllegalHttpMessageException("잘못된 헤더 형식입니다."); + } return new RequestLine(Method.findByName(token[0]), token[1], token[2]); } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestLineTest.java b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestLineTest.java new file mode 100644 index 0000000000..80edd9a7fc --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestLineTest.java @@ -0,0 +1,95 @@ +package org.apache.coyote.http11.httpmessage.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.apache.coyote.http11.exception.IllegalHttpMessageException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class RequestLineTest { + + @Nested + @DisplayName("파싱 테스트") + class ParseFromTest { + @Test + @DisplayName("파싱 성공") + void success() { + // given + String requestLineText = "GET /index.html HTTP/1.1 "; + + // when + RequestLine requestLine = RequestLine.parseFrom(requestLineText); + + //then + assertAll( + () -> assertThat(requestLine.httpVersion()).isEqualTo("HTTP/1.1"), + () -> assertThat(requestLine.method()).isEqualTo(Method.GET), + () -> assertThat(requestLine.target()).isEqualTo("/index.html") + ); + } + + @Test + @DisplayName("잘못된 형식 파싱 실패") + void IllegalFormTest() { + // given + String wrongRequestLine = "GET /index.html"; + + // when & then + assertThatThrownBy(() -> RequestLine.parseFrom(wrongRequestLine)) + .isInstanceOf(IllegalHttpMessageException.class) + .hasMessageContaining("잘못된 헤더 형식입니다."); + } + } + + @Nested + @DisplayName("정적 리소스 확인 테스트") + class IsStaticResourceRequestTest { + + @ParameterizedTest(name = "{0} 확장자 파일을 요청하면 정적 리소스로 판단한다.") + @ValueSource(strings = {".css", ".html", ".js"}) + void staticResourceTest(String extension) { + // given + String target = "/somePath" + extension; + String requestLineText = "GET " + target + " HTTP/1.1"; + + //when + RequestLine requestLine = RequestLine.parseFrom(requestLineText); + + //then + assertThat(requestLine.isStaticResourceRequest()).isTrue(); + } + + @Test + @DisplayName("파일 확장자가 없으면 정적 리소스로 판단하지 않는다.") + void noExtensionPathTest() { + // given + String target = "/somePath"; + String requestLineText = "GET " + target + " HTTP/1.1"; + + //when + RequestLine requestLine = RequestLine.parseFrom(requestLineText); + + //then + assertThat(requestLine.isStaticResourceRequest()).isFalse(); + } + + @Test + @DisplayName("css, js, html 이외의 파일 확장자가 있으면 정적 리소스로 판단하지 않는다.") + void otherExtensionPathTest() { + // given + String target = "/somePath.java"; + String requestLineText = "GET " + target + " HTTP/1.1"; + + //when + RequestLine requestLine = RequestLine.parseFrom(requestLineText); + + //then + assertThat(requestLine.isStaticResourceRequest()).isFalse(); + } + } +} From e63b72d081847c840b6d2f6c1b55f34bef652633 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 08:05:45 +0900 Subject: [PATCH 07/37] =?UTF-8?q?test:=20RequestParameters=20=ED=8C=8C?= =?UTF-8?q?=EC=8B=B1=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/RequestParametersTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestParametersTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestParametersTest.java b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestParametersTest.java new file mode 100644 index 0000000000..d38403ca55 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestParametersTest.java @@ -0,0 +1,64 @@ +package org.apache.coyote.http11.httpmessage.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.NoSuchElementException; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class RequestParametersTest { + + @Nested + @DisplayName("파싱 테스트") + class ParseTest { + + @Test + @DisplayName("key=value 형식의 문자열을 정상적으로 파싱할 수 있다.") + void oneKeyValueFromParseTest() { + //given + String parameter = "key=value"; + + //when + RequestParameters requestParameters = RequestParameters.parseFrom(parameter); + + //then + assertThat(requestParameters.getParam("key")).isEqualTo("value"); + } + + @ParameterizedTest + @DisplayName("key=value 형식의 문자열 여러개를 & 로 이어 붙이면 정상적으로 파싱할 수 있다.") + @ValueSource(strings = {"key1=value1&key2=value2", "key1=value1&key2=value2&key3=value3"}) + void multipleKeyValueFromParseTest(String parameterText) { + assertThatCode(() -> RequestParameters.parseFrom(parameterText)) + .doesNotThrowAnyException(); + } + + @ParameterizedTest(name = "{0}을 이용해 문자열을 이어붙이면 제대로 파싱되지 않는다.") + @ValueSource(strings = {",", "|", ";"}) + void wrongDelimiterTest(String delimiter) { + //given + String parameterText = String.join(delimiter, "key1=value1", + "key2=value2"); + + //when + RequestParameters requestParameters = RequestParameters.parseFrom(parameterText); + + //then + assertAll( + () -> assertThat(requestParameters.getParam("key1")) + .isNotEqualTo("value1"), + () -> assertThatThrownBy(() -> requestParameters.getParam("key2")) + .isInstanceOf(NoSuchElementException.class) + .hasMessage("key2 에 해당하는 값이 존재하지 않습니다.") + ); + + } + } +} From 479ee7aa819a3a9b5294229eb73d82a734b8932d Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 08:15:24 +0900 Subject: [PATCH 08/37] =?UTF-8?q?refactor:=20Http=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=EB=93=A4=EC=97=90=EA=B2=8C=20Http=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 12 +-- .../apache/coyote/http11/RequestHandler.java | 4 +- .../handler/DefaultResourceHandler.java | 84 +++++++++---------- .../request/{Method.java => HttpMethod.java} | 4 +- .../{Request.java => HttpRequest.java} | 28 +++---- ...{RequestLine.java => HttpRequestLine.java} | 14 ++-- ...meters.java => HttpRequestParameters.java} | 8 +- .../{Response.java => HttpResponse.java} | 24 +++--- .../{StatusLine.java => HttpStatusLine.java} | 4 +- ...Test.java => HttpHttpRequestLineTest.java} | 26 +++--- ...ava => HttpHttpRequestParametersTest.java} | 14 ++-- ...{RequestTest.java => HttpRequestTest.java} | 12 +-- 12 files changed, 117 insertions(+), 117 deletions(-) rename tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/{Method.java => HttpMethod.java} (81%) rename tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/{Request.java => HttpRequest.java} (76%) rename tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/{RequestLine.java => HttpRequestLine.java} (66%) rename tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/{RequestParameters.java => HttpRequestParameters.java} (77%) rename tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/{Response.java => HttpResponse.java} (74%) rename tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/{StatusLine.java => HttpStatusLine.java} (78%) rename tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/{RequestLineTest.java => HttpHttpRequestLineTest.java} (70%) rename tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/{RequestParametersTest.java => HttpHttpRequestParametersTest.java} (77%) rename tomcat/src/test/java/org/apache/coyote/http11/request/{RequestTest.java => HttpRequestTest.java} (73%) 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 e61d416570..f4890779bc 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -7,7 +7,7 @@ import org.apache.coyote.Processor; import org.apache.coyote.http11.handler.DefaultResourceHandler; -import org.apache.coyote.http11.httpmessage.request.Request; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,9 +37,9 @@ public void process(Socket connection) { BufferedReader requestBufferedReader = new BufferedReader(inputStreamReader); var outputStream = connection.getOutputStream()) { - Request request = Request.readFrom(requestBufferedReader); - log.info("request : {}", request); - String response = getResponse(request); + HttpRequest httpRequest = HttpRequest.readFrom(requestBufferedReader); + log.info("request : {}", httpRequest); + String response = getResponse(httpRequest); outputStream.write(response.getBytes()); outputStream.flush(); @@ -48,7 +48,7 @@ public void process(Socket connection) { } } - private String getResponse(Request request) throws IOException { - return requestHandler.handle(request); + private String getResponse(HttpRequest httpRequest) throws IOException { + return requestHandler.handle(httpRequest); } } 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 89ac542ac2..e446d763c8 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java @@ -2,9 +2,9 @@ import java.io.IOException; -import org.apache.coyote.http11.httpmessage.request.Request; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; @FunctionalInterface public interface RequestHandler { - String handle(Request request) throws IOException; + String handle(HttpRequest httpRequest) throws IOException; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java index ac0a47f2b5..387cb95230 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java @@ -6,9 +6,9 @@ import org.apache.coyote.http11.RequestHandler; import org.apache.coyote.http11.exception.CanNotHandleRequest; import org.apache.coyote.http11.exception.NoSuchUserException; -import org.apache.coyote.http11.httpmessage.request.Request; -import org.apache.coyote.http11.httpmessage.request.RequestParameters; -import org.apache.coyote.http11.httpmessage.response.Response; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.request.HttpRequestParameters; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; import org.apache.coyote.http11.httpmessage.response.StaticResource; import org.apache.coyote.session.Session; import org.apache.coyote.session.SessionManager; @@ -19,89 +19,89 @@ public class DefaultResourceHandler implements RequestHandler { @Override - public String handle(Request request) throws IOException { - if (request.isStaticResourceRequest()) { - return Response.builder() - .versionOf(request.getHttpVersion()) - .ofStaticResource(new StaticResource(request.getTarget())) + public String handle(HttpRequest httpRequest) throws IOException { + if (httpRequest.isStaticResourceRequest()) { + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) + .ofStaticResource(new StaticResource(httpRequest.getTarget())) .toHttpMessage(); } - if (request.getTarget().equals("/")) { - return Response.builder() - .versionOf(request.getHttpVersion()) + if (httpRequest.getTarget().equals("/")) { + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) .ofStaticResource(new StaticResource("/index.html")) .toHttpMessage(); } - if (request.getTarget().equals("/login")) { - return loginResponse(request); + if (httpRequest.getTarget().equals("/login")) { + return loginResponse(httpRequest); } - if (request.getTarget().contains("register")) { - return registerResponse(request); + if (httpRequest.getTarget().contains("register")) { + return registerResponse(httpRequest); } - throw new CanNotHandleRequest("처리할 수 없는 요청입니다. : " + request.getTarget()); + throw new CanNotHandleRequest("처리할 수 없는 요청입니다. : " + httpRequest.getTarget()); } - private String loginResponse(Request request) throws IOException { - if (request.isPost()) { - return login(request).toHttpMessage(); + private String loginResponse(HttpRequest httpRequest) throws IOException { + if (httpRequest.isPost()) { + return login(httpRequest).toHttpMessage(); } - if (isLoggedIn(request)) { - return Response.builder() - .versionOf(request.getHttpVersion()) + if (isLoggedIn(httpRequest)) { + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) .found("/index.html") .toHttpMessage(); } - return Response.builder() - .versionOf(request.getHttpVersion()) + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) .ofStaticResource(new StaticResource("/login.html")) .toHttpMessage(); } - private boolean isLoggedIn(Request request) { - return Objects.nonNull(request.getSession(false)); + private boolean isLoggedIn(HttpRequest httpRequest) { + return Objects.nonNull(httpRequest.getSession(false)); } - private Response login(Request request) throws NoSuchUserException { - RequestParameters requestParams = RequestParameters.parseFrom(request.getBody()); + private HttpResponse login(HttpRequest httpRequest) throws NoSuchUserException { + HttpRequestParameters requestParams = HttpRequestParameters.parseFrom(httpRequest.getBody()); String account = requestParams.getParam("account"); String password = requestParams.getParam("password"); User user = InMemoryUserRepository.fetchByAccount(account); if (user.checkPassword(password)) { - Session session = request.getSession(true); + Session session = httpRequest.getSession(true); session.setAttribute("user", user); SessionManager.getInstance().add(session); - return Response.builder() - .versionOf(request.getHttpVersion()) + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) .addCookie("JSESSIONID", session.getId()) .found("/index.html"); } - return Response.builder() - .versionOf(request.getHttpVersion()) + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) .found("/401.html"); } - private String registerResponse(Request request) throws IOException { - if (request.isPost()) { - RequestParameters methodRequest = RequestParameters.parseFrom(request.getBody()); + private String registerResponse(HttpRequest httpRequest) throws IOException { + if (httpRequest.isPost()) { + HttpRequestParameters methodRequest = HttpRequestParameters.parseFrom(httpRequest.getBody()); User user = register(methodRequest); - Session session = request.getSession(true); + Session session = httpRequest.getSession(true); session.setAttribute("user", user); SessionManager.getInstance().add(session); - return Response.builder() - .versionOf(request.getHttpVersion()) + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) .addCookie("JSESSIONID", session.getId()) .found("/index.html") .toHttpMessage(); } - return Response.builder() - .versionOf(request.getHttpVersion()) + return HttpResponse.builder() + .versionOf(httpRequest.getHttpVersion()) .ofStaticResource(new StaticResource("/register.html")) .toHttpMessage(); } - private User register(RequestParameters requestParams) { + private User register(HttpRequestParameters requestParams) { String account = requestParams.getParam("account"); User user = new User( account, diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Method.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpMethod.java similarity index 81% rename from tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Method.java rename to tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpMethod.java index 46e3b4ed9a..995138f632 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Method.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpMethod.java @@ -2,10 +2,10 @@ import java.util.Arrays; -public enum Method { +public enum HttpMethod { GET, POST, PUT, PATCH, DELETE; - public static Method findByName(String name) { + public static HttpMethod findByName(String name) { return Arrays.stream(values()) .filter(method -> method.name().equals(name)) .findFirst() diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Request.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java similarity index 76% rename from tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Request.java rename to tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java index 4d8c2ad1a9..6d36639152 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/Request.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java @@ -11,17 +11,17 @@ import org.apache.coyote.session.Session; import org.apache.coyote.session.SessionManager; -public class Request { +public class HttpRequest { - private final RequestLine requestLine; + private final HttpRequestLine httpRequestLine; private final HttpHeaders headers; private final HttpCookie cookies; private final String body; private Session session; - private Request(RequestLine requestLine, HttpHeaders headers, String body) { - this.requestLine = requestLine; + private HttpRequest(HttpRequestLine httpRequestLine, HttpHeaders headers, String body) { + this.httpRequestLine = httpRequestLine; this.headers = headers; if (headers.contains(HttpHeaders.COOKIE)) { this.cookies = HttpCookie.parseFrom(headers.get(HttpHeaders.COOKIE)); @@ -36,11 +36,11 @@ private Request(RequestLine requestLine, HttpHeaders headers, String body) { } } - public static Request readFrom(BufferedReader reader) throws IOException { - RequestLine requestLine = RequestLine.parseFrom(reader.readLine()); + public static HttpRequest readFrom(BufferedReader reader) throws IOException { + HttpRequestLine httpRequestLine = HttpRequestLine.parseFrom(reader.readLine()); HttpHeaders header = new HttpHeaders(readHeader(reader)); String requestBody = readBody(reader, header.getContentLength()); - return new Request(requestLine, header, requestBody); + return new HttpRequest(httpRequestLine, header, requestBody); } private static Map readHeader(BufferedReader reader) throws IOException { @@ -71,23 +71,23 @@ public Session getSession(boolean created) { } public boolean isPost() { - return requestLine.isPost(); + return httpRequestLine.isPost(); } public boolean isStaticResourceRequest() { - return requestLine.isStaticResourceRequest(); + return httpRequestLine.isStaticResourceRequest(); } - public Method getMethod() { - return requestLine.method(); + public HttpMethod getMethod() { + return httpRequestLine.httpMethod(); } public String getTarget() { - return requestLine.target(); + return httpRequestLine.target(); } public String getHttpVersion() { - return requestLine.httpVersion(); + return httpRequestLine.httpVersion(); } public String getBody() { @@ -97,7 +97,7 @@ public String getBody() { @Override public String toString() { return "Request{" + - "requestLine=" + requestLine + + "requestLine=" + httpRequestLine + ", headers=" + headers + ", body='" + body + '\'' + '}'; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestLine.java similarity index 66% rename from tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestLine.java rename to tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestLine.java index 21ad6c05df..aafef340e8 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestLine.java @@ -2,22 +2,22 @@ import org.apache.coyote.http11.exception.IllegalHttpMessageException; -public record RequestLine ( - Method method, +public record HttpRequestLine( + HttpMethod httpMethod, String target, String httpVersion ) { - public static RequestLine parseFrom(String requestLineText) { - String[] token = requestLineText.split(" "); + public static HttpRequestLine parseFrom(String httpRequestLineText) { + String[] token = httpRequestLineText.split(" "); if (token.length != 3) { throw new IllegalHttpMessageException("잘못된 헤더 형식입니다."); } - return new RequestLine(Method.findByName(token[0]), token[1], token[2]); + return new HttpRequestLine(HttpMethod.findByName(token[0]), token[1], token[2]); } public boolean isPost() { - return method == Method.POST; + return httpMethod == HttpMethod.POST; } public boolean isStaticResourceRequest() { @@ -29,7 +29,7 @@ public boolean isStaticResourceRequest() { @Override public String toString() { return "RequestLine{" + - "method=" + method + + "httpMethod=" + httpMethod + ", target='" + target + '\'' + ", httpVersion='" + httpVersion + '\'' + '}'; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestParameters.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestParameters.java similarity index 77% rename from tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestParameters.java rename to tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestParameters.java index aff6af689f..0494ff1720 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/RequestParameters.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestParameters.java @@ -5,21 +5,21 @@ import java.util.NoSuchElementException; import java.util.Optional; -public class RequestParameters { +public class HttpRequestParameters { private final Map requestParams; - private RequestParameters(Map requestParams) { + private HttpRequestParameters(Map requestParams) { this.requestParams = Map.copyOf(requestParams); } - public static RequestParameters parseFrom(String paramString) { + public static HttpRequestParameters parseFrom(String paramString) { Map requestParams = new HashMap<>(); String[] requestParamTokens = paramString.split("&"); for (String requestParam : requestParamTokens) { String[] split = requestParam.split("="); requestParams.put(split[0], split[1]); } - return new RequestParameters(requestParams); + return new HttpRequestParameters(requestParams); } public String getParam(String key) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/Response.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java similarity index 74% rename from tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/Response.java rename to tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java index 13e65f1303..2111727f9f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/Response.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java @@ -6,9 +6,9 @@ import org.apache.coyote.http11.httpmessage.HttpCookie; import org.apache.coyote.http11.httpmessage.HttpHeaders; -public class Response { +public class HttpResponse { - private final StatusLine statusLine; + private final HttpStatusLine httpStatusLine; private final HttpHeaders headers; private final String content; @@ -16,8 +16,8 @@ public static ResponseBuilder builder() { return new ResponseBuilder(); } - public Response(StatusLine statusLine, HttpHeaders headers, String content) { - this.statusLine = statusLine; + public HttpResponse(HttpStatusLine httpStatusLine, HttpHeaders headers, String content) { + this.httpStatusLine = httpStatusLine; this.headers = headers; this.content = content; } @@ -43,30 +43,30 @@ public ResponseBuilder addCookie(String key, String value) { return this; } - public Response found(String target) { + public HttpResponse found(String target) { this.headers.addHeader(HttpHeaders.LOCATION, target); return build( - new StatusLine(this.ProtocolVersion, 301, "FOUND"), + new HttpStatusLine(this.ProtocolVersion, 301, "FOUND"), this.headers, "" ); } - public Response ofStaticResource(StaticResource resource) throws IOException { + public HttpResponse ofStaticResource(StaticResource resource) throws IOException { headers.addHeader(HttpHeaders.CONTENT_TYPE, resource.getContentType() + ";charset=utf-8"); headers.addHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(resource.getContentLength())); return build( - new StatusLine(this.ProtocolVersion, 200, "OK"), + new HttpStatusLine(this.ProtocolVersion, 200, "OK"), this.headers, resource.getContent() ); } - public Response build(StatusLine statusLine, HttpHeaders headers, String content) { + public HttpResponse build(HttpStatusLine httpStatusLine, HttpHeaders headers, String content) { setCookie(headers); - return new Response(statusLine, headers, content); + return new HttpResponse(httpStatusLine, headers, content); } private void setCookie(HttpHeaders headers) { @@ -77,11 +77,11 @@ private void setCookie(HttpHeaders headers) { } public String toHttpMessage() { - if (statusLine == null) { + if (httpStatusLine == null) { throw new NotCompleteResponseException("응답이 완성되지 않았습니다."); } return String.join("\r\n", - statusLine.toHttpMessage(), + httpStatusLine.toHttpMessage(), headers.toHttpMessage(), "", content); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/StatusLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java similarity index 78% rename from tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/StatusLine.java rename to tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java index 21b1a87990..2bdb16ce12 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/StatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java @@ -1,12 +1,12 @@ package org.apache.coyote.http11.httpmessage.response; -public class StatusLine { +public class HttpStatusLine { private final String protocolVersion; private final int statusCode; private final String statusText; - public StatusLine(String protocolVersion, int statusCode, String statusText) { + public HttpStatusLine(String protocolVersion, int statusCode, String statusText) { this.protocolVersion = protocolVersion; this.statusCode = statusCode; this.statusText = statusText; diff --git a/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestLineTest.java b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpHttpRequestLineTest.java similarity index 70% rename from tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestLineTest.java rename to tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpHttpRequestLineTest.java index 80edd9a7fc..ce36c0eb81 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestLineTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpHttpRequestLineTest.java @@ -11,7 +11,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -class RequestLineTest { +class HttpHttpRequestLineTest { @Nested @DisplayName("파싱 테스트") @@ -23,13 +23,13 @@ void success() { String requestLineText = "GET /index.html HTTP/1.1 "; // when - RequestLine requestLine = RequestLine.parseFrom(requestLineText); + HttpRequestLine httpRequestLine = HttpRequestLine.parseFrom(requestLineText); //then assertAll( - () -> assertThat(requestLine.httpVersion()).isEqualTo("HTTP/1.1"), - () -> assertThat(requestLine.method()).isEqualTo(Method.GET), - () -> assertThat(requestLine.target()).isEqualTo("/index.html") + () -> assertThat(httpRequestLine.httpVersion()).isEqualTo("HTTP/1.1"), + () -> assertThat(httpRequestLine.httpMethod()).isEqualTo(HttpMethod.GET), + () -> assertThat(httpRequestLine.target()).isEqualTo("/index.html") ); } @@ -40,7 +40,7 @@ void IllegalFormTest() { String wrongRequestLine = "GET /index.html"; // when & then - assertThatThrownBy(() -> RequestLine.parseFrom(wrongRequestLine)) + assertThatThrownBy(() -> HttpRequestLine.parseFrom(wrongRequestLine)) .isInstanceOf(IllegalHttpMessageException.class) .hasMessageContaining("잘못된 헤더 형식입니다."); } @@ -48,7 +48,7 @@ void IllegalFormTest() { @Nested @DisplayName("정적 리소스 확인 테스트") - class IsStaticResourceRequestTest { + class IsStaticResourceHttpRequestTest { @ParameterizedTest(name = "{0} 확장자 파일을 요청하면 정적 리소스로 판단한다.") @ValueSource(strings = {".css", ".html", ".js"}) @@ -58,10 +58,10 @@ void staticResourceTest(String extension) { String requestLineText = "GET " + target + " HTTP/1.1"; //when - RequestLine requestLine = RequestLine.parseFrom(requestLineText); + HttpRequestLine httpRequestLine = HttpRequestLine.parseFrom(requestLineText); //then - assertThat(requestLine.isStaticResourceRequest()).isTrue(); + assertThat(httpRequestLine.isStaticResourceRequest()).isTrue(); } @Test @@ -72,10 +72,10 @@ void noExtensionPathTest() { String requestLineText = "GET " + target + " HTTP/1.1"; //when - RequestLine requestLine = RequestLine.parseFrom(requestLineText); + HttpRequestLine httpRequestLine = HttpRequestLine.parseFrom(requestLineText); //then - assertThat(requestLine.isStaticResourceRequest()).isFalse(); + assertThat(httpRequestLine.isStaticResourceRequest()).isFalse(); } @Test @@ -86,10 +86,10 @@ void otherExtensionPathTest() { String requestLineText = "GET " + target + " HTTP/1.1"; //when - RequestLine requestLine = RequestLine.parseFrom(requestLineText); + HttpRequestLine httpRequestLine = HttpRequestLine.parseFrom(requestLineText); //then - assertThat(requestLine.isStaticResourceRequest()).isFalse(); + assertThat(httpRequestLine.isStaticResourceRequest()).isFalse(); } } } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestParametersTest.java b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpHttpRequestParametersTest.java similarity index 77% rename from tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestParametersTest.java rename to tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpHttpRequestParametersTest.java index d38403ca55..3f21357596 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/RequestParametersTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpHttpRequestParametersTest.java @@ -13,7 +13,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -class RequestParametersTest { +class HttpHttpRequestParametersTest { @Nested @DisplayName("파싱 테스트") @@ -26,17 +26,17 @@ void oneKeyValueFromParseTest() { String parameter = "key=value"; //when - RequestParameters requestParameters = RequestParameters.parseFrom(parameter); + HttpRequestParameters httpRequestParameters = HttpRequestParameters.parseFrom(parameter); //then - assertThat(requestParameters.getParam("key")).isEqualTo("value"); + assertThat(httpRequestParameters.getParam("key")).isEqualTo("value"); } @ParameterizedTest @DisplayName("key=value 형식의 문자열 여러개를 & 로 이어 붙이면 정상적으로 파싱할 수 있다.") @ValueSource(strings = {"key1=value1&key2=value2", "key1=value1&key2=value2&key3=value3"}) void multipleKeyValueFromParseTest(String parameterText) { - assertThatCode(() -> RequestParameters.parseFrom(parameterText)) + assertThatCode(() -> HttpRequestParameters.parseFrom(parameterText)) .doesNotThrowAnyException(); } @@ -48,13 +48,13 @@ void wrongDelimiterTest(String delimiter) { "key2=value2"); //when - RequestParameters requestParameters = RequestParameters.parseFrom(parameterText); + HttpRequestParameters httpRequestParameters = HttpRequestParameters.parseFrom(parameterText); //then assertAll( - () -> assertThat(requestParameters.getParam("key1")) + () -> assertThat(httpRequestParameters.getParam("key1")) .isNotEqualTo("value1"), - () -> assertThatThrownBy(() -> requestParameters.getParam("key2")) + () -> assertThatThrownBy(() -> httpRequestParameters.getParam("key2")) .isInstanceOf(NoSuchElementException.class) .hasMessage("key2 에 해당하는 값이 존재하지 않습니다.") ); diff --git a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java b/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestTest.java similarity index 73% rename from tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java rename to tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestTest.java index 8438feca69..a4a795a830 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestTest.java @@ -9,13 +9,13 @@ import java.io.InputStream; import java.io.InputStreamReader; -import org.apache.coyote.http11.httpmessage.request.Method; -import org.apache.coyote.http11.httpmessage.request.Request; +import org.apache.coyote.http11.httpmessage.request.HttpMethod; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -class RequestTest { +class HttpRequestTest { @Nested @DisplayName("생성 테스트") @@ -37,12 +37,12 @@ void getRequestConstructTest() throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(requestStream)); - Request request = Request.readFrom(bufferedReader); + HttpRequest httpRequest = HttpRequest.readFrom(bufferedReader); //then assertAll( - () -> assertThat(request.getMethod()).isEqualTo(Method.GET), - () -> assertThat(request.getTarget()).isEqualTo("/index.html") + () -> assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.GET), + () -> assertThat(httpRequest.getTarget()).isEqualTo("/index.html") ); } } From 83e855264bf78b8b8d4ac2fbb4a24c683a862a8c Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 08:17:34 +0900 Subject: [PATCH 09/37] =?UTF-8?q?feat:=20=EB=AF=B8=EC=85=98=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EB=BC=88=EB=8C=80=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catalina/servlet/AbstractController.java | 15 +++++++++++++++ .../org/apache/catalina/servlet/Controller.java | 8 ++++++++ .../apache/catalina/servlet/RequestMapping.java | 9 +++++++++ 3 files changed, 32 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java create mode 100644 tomcat/src/main/java/org/apache/catalina/servlet/Controller.java create mode 100644 tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java b/tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java new file mode 100644 index 0000000000..8a5cf3815d --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java @@ -0,0 +1,15 @@ +package org.apache.catalina.servlet; + +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; + +public abstract class AbstractController implements Controller { + + @Override + public void service(HttpRequest request, HttpResponse response) throws Exception { + // http method 분기문 + } + + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } +} diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/Controller.java b/tomcat/src/main/java/org/apache/catalina/servlet/Controller.java new file mode 100644 index 0000000000..e873e618ee --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/servlet/Controller.java @@ -0,0 +1,8 @@ +package org.apache.catalina.servlet; + +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; + +public interface Controller { + void service(HttpRequest request, HttpResponse response) throws Exception; +} diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java new file mode 100644 index 0000000000..b2c02834fb --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java @@ -0,0 +1,9 @@ +package org.apache.catalina.servlet; + +import org.apache.coyote.http11.httpmessage.request.HttpRequest; + +public class RequestMapping { + public Controller getController(HttpRequest request) { + return null; + } +} From 44aca15ac7e3b62de260a5a21731f7e5858d64d9 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 08:24:28 +0900 Subject: [PATCH 10/37] =?UTF-8?q?feat:=20Http=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EB=B6=84=EA=B8=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/catalina/servlet/AbstractController.java | 12 +++++++++--- .../http11/httpmessage/request/HttpRequest.java | 4 ++++ .../http11/httpmessage/request/HttpRequestLine.java | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java b/tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java index 8a5cf3815d..a71171118e 100644 --- a/tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java +++ b/tomcat/src/main/java/org/apache/catalina/servlet/AbstractController.java @@ -7,9 +7,15 @@ public abstract class AbstractController implements Controller { @Override public void service(HttpRequest request, HttpResponse response) throws Exception { - // http method 분기문 + if (request.isGet()) { + doGet(request, response); + } + if (request.isPost()) { + doPost(request, response); + } } - protected void doPost(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } - protected void doGet(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } + protected abstract void doPost(HttpRequest request, HttpResponse response) throws Exception; + + protected abstract void doGet(HttpRequest request, HttpResponse response) throws Exception; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java index 6d36639152..74de827fbc 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java @@ -70,6 +70,10 @@ public Session getSession(boolean created) { return this.session; } + public boolean isGet() { + return httpRequestLine.isGet(); + } + public boolean isPost() { return httpRequestLine.isPost(); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestLine.java index aafef340e8..e3cc362f9a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequestLine.java @@ -16,6 +16,10 @@ public static HttpRequestLine parseFrom(String httpRequestLineText) { return new HttpRequestLine(HttpMethod.findByName(token[0]), token[1], token[2]); } + public boolean isGet() { + return this.httpMethod == HttpMethod.GET; + } + public boolean isPost() { return httpMethod == HttpMethod.POST; } From 611a3f59d3dda96c503abbdf43105e93b03e73fc Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 08:35:49 +0900 Subject: [PATCH 11/37] =?UTF-8?q?feat:=20=EC=9A=94=EC=B2=AD=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=9D=BC=20Servlet=20=EC=9D=84=20=EB=8B=A4=EB=A5=B4?= =?UTF-8?q?=EA=B2=8C=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20=ED=9D=90?= =?UTF-8?q?=EB=A6=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/NoMatchedHandlerException.java | 7 +++++++ .../servlet/PathMatchServletContainer.java | 19 +++++++++++++++++++ .../catalina/servlet/RequestMapping.java | 14 +++++++++++++- .../org/apache/coyote/ServletContainer.java | 8 ++++++++ .../http11/exception/NoHandlerException.java | 7 ------- 5 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java create mode 100644 tomcat/src/main/java/org/apache/catalina/servlet/PathMatchServletContainer.java create mode 100644 tomcat/src/main/java/org/apache/coyote/ServletContainer.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java diff --git a/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java b/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java new file mode 100644 index 0000000000..0d08a06d54 --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java @@ -0,0 +1,7 @@ +package org.apache.catalina.exception; + +public class NoMatchedHandlerException extends RuntimeException { + public NoMatchedHandlerException(String message) { + super(message); + } +} diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/PathMatchServletContainer.java b/tomcat/src/main/java/org/apache/catalina/servlet/PathMatchServletContainer.java new file mode 100644 index 0000000000..23fb280aad --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/servlet/PathMatchServletContainer.java @@ -0,0 +1,19 @@ +package org.apache.catalina.servlet; + +import org.apache.coyote.ServletContainer; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; + +public class PathMatchServletContainer implements ServletContainer { + private final RequestMapping requestMapping; + + public PathMatchServletContainer(RequestMapping requestMapping) { + this.requestMapping = requestMapping; + } + + @Override + public void service(HttpRequest request, HttpResponse response) throws Exception { + Controller controller = requestMapping.getController(request); + controller.service(request, response); + } +} diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java index b2c02834fb..cae2f89a68 100644 --- a/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java +++ b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java @@ -1,9 +1,21 @@ package org.apache.catalina.servlet; +import java.util.Map; + +import org.apache.catalina.exception.NoMatchedHandlerException; import org.apache.coyote.http11.httpmessage.request.HttpRequest; public class RequestMapping { + private final Map mappedController; + + public RequestMapping(Map mappedController) { + this.mappedController = mappedController; + } + public Controller getController(HttpRequest request) { - return null; + if (mappedController.containsKey(request.getTarget())) { + return mappedController.get(request.getTarget()); + } + throw new NoMatchedHandlerException(request.getTarget() + " 요청을 처리할 컨트롤러가 존재하지 않습니다."); } } diff --git a/tomcat/src/main/java/org/apache/coyote/ServletContainer.java b/tomcat/src/main/java/org/apache/coyote/ServletContainer.java new file mode 100644 index 0000000000..dafc782b31 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/ServletContainer.java @@ -0,0 +1,8 @@ +package org.apache.coyote; + +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; + +public interface ServletContainer { + void service(HttpRequest request, HttpResponse response) throws Exception; +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java b/tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java deleted file mode 100644 index a8f36e5d4e..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.apache.coyote.http11.exception; - -public class NoHandlerException extends RuntimeException { - public NoHandlerException(String message) { - super(message); - } -} From fc8dbd39548a0b2a26fde19fe7a8d364bb7a8dcb Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 08:49:43 +0900 Subject: [PATCH 12/37] =?UTF-8?q?feat:=20=EC=8B=A4=EC=A0=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EC=9D=B4=20Controller=20=EA=B9=8C=EC=A7=80?= =?UTF-8?q?=20=EC=A0=84=EB=8B=AC=EB=90=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/Application.java | 10 ++++++- .../apache/catalina/connector/Connector.java | 12 +++++--- .../org/apache/catalina/startup/Tomcat.java | 9 +++++- .../apache/coyote/http11/Http11Processor.java | 20 +++++++++++-- .../coyote/http11/Http11ProcessorTest.java | 30 ++++++++++++------- 5 files changed, 62 insertions(+), 19 deletions(-) diff --git a/tomcat/src/main/java/com/techcourse/Application.java b/tomcat/src/main/java/com/techcourse/Application.java index f874a4efb5..4ec4d22243 100644 --- a/tomcat/src/main/java/com/techcourse/Application.java +++ b/tomcat/src/main/java/com/techcourse/Application.java @@ -1,11 +1,19 @@ package com.techcourse; +import java.util.Map; + +import org.apache.catalina.servlet.PathMatchServletContainer; +import org.apache.catalina.servlet.RequestMapping; import org.apache.catalina.startup.Tomcat; public class Application { public static void main(String[] args) { - var tomcat = new Tomcat(); + RequestMapping requestMapping = new RequestMapping( + Map.of() + ); + PathMatchServletContainer servletContainer = new PathMatchServletContainer(requestMapping); + var tomcat = new Tomcat(servletContainer); tomcat.start(); } } 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 2e2de79386..447c9853cd 100644 --- a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java +++ b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java @@ -5,6 +5,7 @@ import java.net.ServerSocket; import java.net.Socket; +import org.apache.coyote.ServletContainer; import org.apache.coyote.http11.Http11Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,13 +18,16 @@ public class Connector implements Runnable { private static final int DEFAULT_ACCEPT_COUNT = 100; private final ServerSocket serverSocket; + private final ServletContainer servletContainer; + private boolean stopped; - public Connector() { - this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT); + public Connector(ServletContainer servletContainer) { + this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, servletContainer); } - public Connector(int port, int acceptCount) { + public Connector(int port, int acceptCount, ServletContainer servletContainer) { + this.servletContainer = servletContainer; this.serverSocket = createServerSocket(port, acceptCount); this.stopped = false; } @@ -66,7 +70,7 @@ private void process(Socket connection) { if (connection == null) { return; } - var processor = new Http11Processor(connection); + var processor = new Http11Processor(servletContainer, connection); new Thread(processor).start(); } 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 61afa8df71..eddcdf8b0c 100644 --- a/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java +++ b/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java @@ -3,6 +3,7 @@ import java.io.IOException; import org.apache.catalina.connector.Connector; +import org.apache.coyote.ServletContainer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -10,8 +11,14 @@ public class Tomcat { private static final Logger log = LoggerFactory.getLogger(Tomcat.class); + private final ServletContainer servletContainer; + + public Tomcat(ServletContainer servletContainer) { + this.servletContainer = servletContainer; + } + public void start() { - var connector = new Connector(); + var connector = new Connector(servletContainer); connector.start(); try { 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 f4890779bc..47e19dad81 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -6,8 +6,10 @@ import java.net.Socket; import org.apache.coyote.Processor; +import org.apache.coyote.ServletContainer; import org.apache.coyote.http11.handler.DefaultResourceHandler; import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,10 +18,12 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); + private final ServletContainer servletContainer; private final RequestHandler requestHandler; private final Socket connection; - public Http11Processor(Socket connection) { + public Http11Processor(ServletContainer servletContainer, Socket connection) { + this.servletContainer = servletContainer; this.connection = connection; this.requestHandler = new DefaultResourceHandler(); } @@ -39,15 +43,25 @@ public void process(Socket connection) { HttpRequest httpRequest = HttpRequest.readFrom(requestBufferedReader); log.info("request : {}", httpRequest); - String response = getResponse(httpRequest); + HttpResponse httpResponse = null; - outputStream.write(response.getBytes()); + service(httpRequest, httpResponse); + + outputStream.write(httpResponse.toHttpMessage().getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { log.error(e.getMessage(), e); } } + private void service(HttpRequest httpRequest, HttpResponse httpResponse) { + try { + servletContainer.service(httpRequest, httpResponse); + } catch (Exception e) { + //todo 예외 처리 + } + } + private String getResponse(HttpRequest httpRequest) throws IOException { return requestHandler.handle(httpRequest); } 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 83ccfbbeb2..7ca4b5c7b3 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -6,7 +6,11 @@ import java.io.IOException; import java.net.URL; import java.nio.file.Files; +import java.util.Map; +import org.apache.catalina.servlet.PathMatchServletContainer; +import org.apache.catalina.servlet.RequestMapping; +import org.apache.coyote.ServletContainer; import org.apache.coyote.session.Session; import org.apache.coyote.session.SessionManager; import org.junit.jupiter.api.Disabled; @@ -14,6 +18,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import com.techcourse.controller.LoginController; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; @@ -21,12 +26,17 @@ class Http11ProcessorTest { + private final RequestMapping requestMapping = new RequestMapping( + Map.of() + ); + private final ServletContainer servletContainer = new PathMatchServletContainer(requestMapping); + @Test @Disabled void process() { // given final var socket = new StubSocket(); - final var processor = new Http11Processor(socket); + final var processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -51,7 +61,7 @@ void index() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -85,7 +95,7 @@ void index() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -115,7 +125,7 @@ void css() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -149,7 +159,7 @@ void login() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -184,7 +194,7 @@ void loginViewWhenLoggedIn() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -207,7 +217,7 @@ void loginSuccess() throws IOException { "", requestBody); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -232,7 +242,7 @@ void loginFailed() throws IOException { requestBody); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -260,7 +270,7 @@ void registerView() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); @@ -290,7 +300,7 @@ void registerSuccess() throws IOException { requestBody); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(servletContainer, socket); // when processor.process(socket); From 7201ebcfe1d93a699bb740f3a22b6c6df6ca0912 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:12:30 +0900 Subject: [PATCH 13/37] =?UTF-8?q?feat:=20HttpResponse=20=EB=A5=BC=20?= =?UTF-8?q?=EA=B0=80=EB=B3=80=EA=B0=9D=EC=B2=B4=EB=A1=9C=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 --- .../apache/coyote/http11/Http11Processor.java | 5 +- .../apache/coyote/http11/RequestHandler.java | 3 +- .../handler/DefaultResourceHandler.java | 68 ++++++------- .../httpmessage/response/HttpResponse.java | 96 +++++++------------ .../httpmessage/response/HttpStatusLine.java | 26 +++-- 5 files changed, 90 insertions(+), 108 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 47e19dad81..4aec00a77b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -62,7 +62,8 @@ private void service(HttpRequest httpRequest, HttpResponse httpResponse) { } } - private String getResponse(HttpRequest httpRequest) throws IOException { - return requestHandler.handle(httpRequest); + private void getResponse(HttpRequest httpRequest) throws IOException { + HttpResponse httpResponse = new HttpResponse(httpRequest); + requestHandler.handle(httpRequest, httpResponse); } } 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 e446d763c8..350f7da8d8 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java @@ -3,8 +3,9 @@ import java.io.IOException; import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; @FunctionalInterface public interface RequestHandler { - String handle(HttpRequest httpRequest) throws IOException; + void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java index 387cb95230..7271f52192 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java @@ -19,49 +19,45 @@ public class DefaultResourceHandler implements RequestHandler { @Override - public String handle(HttpRequest httpRequest) throws IOException { + public void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { if (httpRequest.isStaticResourceRequest()) { - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .ofStaticResource(new StaticResource(httpRequest.getTarget())) - .toHttpMessage(); + StaticResource staticResource = new StaticResource(httpRequest.getTarget()); + httpResponse.setResponseOfStaticResource(staticResource); + return; } if (httpRequest.getTarget().equals("/")) { - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .ofStaticResource(new StaticResource("/index.html")) - .toHttpMessage(); + StaticResource staticResource = new StaticResource("/index.html"); + httpResponse.setResponseOfStaticResource(staticResource); + return; } if (httpRequest.getTarget().equals("/login")) { - return loginResponse(httpRequest); + loginResponse(httpRequest, httpResponse); + return; } if (httpRequest.getTarget().contains("register")) { - return registerResponse(httpRequest); + registerResponse(httpRequest, httpResponse); + return; } throw new CanNotHandleRequest("처리할 수 없는 요청입니다. : " + httpRequest.getTarget()); } - private String loginResponse(HttpRequest httpRequest) throws IOException { + private void loginResponse(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { if (httpRequest.isPost()) { - return login(httpRequest).toHttpMessage(); + login(httpRequest, httpResponse); + return; } if (isLoggedIn(httpRequest)) { - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .found("/index.html") - .toHttpMessage(); + httpResponse.setMethodFound("/index.html"); + return; } - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .ofStaticResource(new StaticResource("/login.html")) - .toHttpMessage(); + httpResponse.setMethodFound("/index.html"); } private boolean isLoggedIn(HttpRequest httpRequest) { return Objects.nonNull(httpRequest.getSession(false)); } - private HttpResponse login(HttpRequest httpRequest) throws NoSuchUserException { + private void login(HttpRequest httpRequest, HttpResponse httpResponse) throws NoSuchUserException { HttpRequestParameters requestParams = HttpRequestParameters.parseFrom(httpRequest.getBody()); String account = requestParams.getParam("account"); String password = requestParams.getParam("password"); @@ -70,35 +66,29 @@ private HttpResponse login(HttpRequest httpRequest) throws NoSuchUserException { Session session = httpRequest.getSession(true); session.setAttribute("user", user); SessionManager.getInstance().add(session); - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .addCookie("JSESSIONID", session.getId()) - .found("/index.html"); + + httpResponse.addCookie("JSESSIONID", session.getId()); + httpResponse.setMethodFound("/index.html"); + return; } - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .found("/401.html"); + httpResponse.setMethodFound("/401.html"); } - private String registerResponse(HttpRequest httpRequest) throws IOException { + private void registerResponse(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { if (httpRequest.isPost()) { HttpRequestParameters methodRequest = HttpRequestParameters.parseFrom(httpRequest.getBody()); User user = register(methodRequest); Session session = httpRequest.getSession(true); session.setAttribute("user", user); SessionManager.getInstance().add(session); - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .addCookie("JSESSIONID", session.getId()) - .found("/index.html") - .toHttpMessage(); + + httpResponse.addCookie("JSESSIONID", session.getId()); + httpResponse.setMethodFound("/index.html"); + return; } - return HttpResponse.builder() - .versionOf(httpRequest.getHttpVersion()) - .ofStaticResource(new StaticResource("/register.html")) - .toHttpMessage(); + httpResponse.setResponseOfStaticResource(new StaticResource("/register.html")); } private User register(HttpRequestParameters requestParams) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java index 2111727f9f..278c2afcb6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java @@ -5,85 +5,61 @@ import org.apache.coyote.http11.exception.NotCompleteResponseException; import org.apache.coyote.http11.httpmessage.HttpCookie; import org.apache.coyote.http11.httpmessage.HttpHeaders; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; public class HttpResponse { - private final HttpStatusLine httpStatusLine; - private final HttpHeaders headers; - private final String content; + private final HttpCookie httpCookie; + private HttpStatusLine httpStatusLine; + private HttpHeaders headers; + private String body; - public static ResponseBuilder builder() { - return new ResponseBuilder(); - } - public HttpResponse(HttpStatusLine httpStatusLine, HttpHeaders headers, String content) { + public HttpResponse(HttpStatusLine httpStatusLine, HttpHeaders headers, String body) { this.httpStatusLine = httpStatusLine; this.headers = headers; - this.content = content; + this.body = body; + httpCookie = new HttpCookie(); } - public static class ResponseBuilder { - private final HttpCookie httpCookie; - private final HttpHeaders headers; - private String ProtocolVersion; - - private ResponseBuilder() { - ProtocolVersion = "HTTP/1.1"; - httpCookie = new HttpCookie(); - headers = new HttpHeaders(); - } - - public ResponseBuilder versionOf(String protocolVersion) { - this.ProtocolVersion = protocolVersion; - return this; - } - - public ResponseBuilder addCookie(String key, String value) { - httpCookie.addCookie(key, value); - return this; - } - - public HttpResponse found(String target) { - this.headers.addHeader(HttpHeaders.LOCATION, target); - - return build( - new HttpStatusLine(this.ProtocolVersion, 301, "FOUND"), - this.headers, - "" - ); - } - - public HttpResponse ofStaticResource(StaticResource resource) throws IOException { - headers.addHeader(HttpHeaders.CONTENT_TYPE, resource.getContentType() + ";charset=utf-8"); - headers.addHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(resource.getContentLength())); - - return build( - new HttpStatusLine(this.ProtocolVersion, 200, "OK"), - this.headers, - resource.getContent() - ); - } + public HttpResponse(HttpRequest httpRequest) { - public HttpResponse build(HttpStatusLine httpStatusLine, HttpHeaders headers, String content) { - setCookie(headers); - return new HttpResponse(httpStatusLine, headers, content); - } - - private void setCookie(HttpHeaders headers) { - if(!httpCookie.isEmpty()) { - headers.addHeader(HttpHeaders.SET_COOKIE, httpCookie.toHttpMessage()); - } - } + this(new HttpStatusLine(httpRequest.getHttpVersion(), 0, null), //todo 생성 방식 고민 + new HttpHeaders(), + ""); } public String toHttpMessage() { if (httpStatusLine == null) { throw new NotCompleteResponseException("응답이 완성되지 않았습니다."); } + setCookie(); return String.join("\r\n", httpStatusLine.toHttpMessage(), headers.toHttpMessage(), "", - content); + body); + } + + private void setCookie() { + if(!httpCookie.isEmpty()) { + headers.addHeader(HttpHeaders.SET_COOKIE, httpCookie.toHttpMessage()); + } + } + + public void setMethodFound(String target) { + this.httpStatusLine.setMethodFound(); + this.headers.addHeader(HttpHeaders.LOCATION, target); + } + + public void setResponseOfStaticResource(StaticResource resource) throws IOException { + this.httpStatusLine.setMethodOK(); + headers.addHeader(HttpHeaders.CONTENT_TYPE, resource.getContentType() + ";charset=utf-8"); + headers.addHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(resource.getContentLength())); + this.body = resource.getContent(); + } + + public void addCookie(String key, String value) { + httpCookie.addCookie(key, value); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java index 2bdb16ce12..4333b77c07 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java @@ -2,17 +2,31 @@ public class HttpStatusLine { - private final String protocolVersion; - private final int statusCode; - private final String statusText; + private String httpVersion; + private int statusCode; + private String statusText; - public HttpStatusLine(String protocolVersion, int statusCode, String statusText) { - this.protocolVersion = protocolVersion; + public HttpStatusLine(String httpVersion, int statusCode, String statusText) { + this.httpVersion = httpVersion; this.statusCode = statusCode; this.statusText = statusText; } public String toHttpMessage() { - return String.format("%s %s %s ", protocolVersion, statusCode, statusText); + return String.format("%s %s %s ", httpVersion, statusCode, statusText); + } + + public void setHttpVersion(String httpVersion) { + this.httpVersion = httpVersion; + } + + public void setMethodFound() { + this.statusCode = 301; + this.statusText = "FOUND"; + } + + public void setMethodOK() { + this.statusCode = 200; + this.statusText = "OK"; } } From 6c2ab747dab3abe34ac75a18f424762e29857d61 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:17:58 +0900 Subject: [PATCH 14/37] =?UTF-8?q?feat:=20HttpResponse=20=EB=A5=BC=20?= =?UTF-8?q?=EA=B0=80=EB=B3=80=EA=B0=9D=EC=B2=B4=EB=A1=9C=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/org/apache/coyote/http11/Http11Processor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 4aec00a77b..6630fb702c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -43,7 +43,7 @@ public void process(Socket connection) { HttpRequest httpRequest = HttpRequest.readFrom(requestBufferedReader); log.info("request : {}", httpRequest); - HttpResponse httpResponse = null; + HttpResponse httpResponse = new HttpResponse(httpRequest); service(httpRequest, httpResponse); From dabb8d528905b12f0f33e33ddff5d0393df9ba84 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:22:06 +0900 Subject: [PATCH 15/37] =?UTF-8?q?refactor:=20Request=20URL=20=EA=B3=BC=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/Application.java | 4 +++- .../techcourse/config/RequestMappingConfig.java | 17 +++++++++++++++++ .../coyote/http11/Http11ProcessorTest.java | 7 ++----- 3 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java diff --git a/tomcat/src/main/java/com/techcourse/Application.java b/tomcat/src/main/java/com/techcourse/Application.java index 4ec4d22243..b2ab9852c7 100644 --- a/tomcat/src/main/java/com/techcourse/Application.java +++ b/tomcat/src/main/java/com/techcourse/Application.java @@ -6,11 +6,13 @@ import org.apache.catalina.servlet.RequestMapping; import org.apache.catalina.startup.Tomcat; +import com.techcourse.controller.LoginController; + public class Application { public static void main(String[] args) { RequestMapping requestMapping = new RequestMapping( - Map.of() + Map.of("/login", new LoginController()) ); PathMatchServletContainer servletContainer = new PathMatchServletContainer(requestMapping); var tomcat = new Tomcat(servletContainer); diff --git a/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java new file mode 100644 index 0000000000..0248958d24 --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java @@ -0,0 +1,17 @@ +package com.techcourse.config; + +import java.util.Map; + +import org.apache.catalina.servlet.RequestMapping; + +import com.techcourse.controller.LoginController; + +public class RequestMappingConfig { + public static RequestMapping getRequestMapping() { + return new RequestMapping( + Map.of( + "/login", new LoginController() + ) + ); + } +} 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 7ca4b5c7b3..ad21dbbbe4 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.net.URL; import java.nio.file.Files; -import java.util.Map; import org.apache.catalina.servlet.PathMatchServletContainer; import org.apache.catalina.servlet.RequestMapping; @@ -18,7 +17,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import com.techcourse.controller.LoginController; +import com.techcourse.config.RequestMappingConfig; import com.techcourse.db.InMemoryUserRepository; import com.techcourse.model.User; @@ -26,9 +25,7 @@ class Http11ProcessorTest { - private final RequestMapping requestMapping = new RequestMapping( - Map.of() - ); + private final RequestMapping requestMapping = RequestMappingConfig.getRequestMapping(); private final ServletContainer servletContainer = new PathMatchServletContainer(requestMapping); @Test From cf262472eb73349cd339fa51e4cff9e20f9e8f27 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:24:44 +0900 Subject: [PATCH 16/37] =?UTF-8?q?refactor:=20LoginController=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 --- .../controller/LoginController.java | 49 +++++++++++++++++++ .../handler/DefaultResourceHandler.java | 40 --------------- 2 files changed, 49 insertions(+), 40 deletions(-) create mode 100644 tomcat/src/main/java/com/techcourse/controller/LoginController.java diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java new file mode 100644 index 0000000000..f489f28ebd --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -0,0 +1,49 @@ +package com.techcourse.controller; + +import java.util.Objects; + +import org.apache.catalina.servlet.AbstractController; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.request.HttpRequestParameters; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; +import org.apache.coyote.session.Session; +import org.apache.coyote.session.SessionManager; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + +public class LoginController extends AbstractController { + @Override + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { + HttpRequestParameters requestParams = HttpRequestParameters.parseFrom(request.getBody()); + String account = requestParams.getParam("account"); + String password = requestParams.getParam("password"); + User user = InMemoryUserRepository.fetchByAccount(account); + if (user.checkPassword(password)) { + Session session = request.getSession(true); + session.setAttribute("user", user); + SessionManager.getInstance().add(session); + + response.addCookie("JSESSIONID", session.getId()); + response.setMethodFound("/index.html"); + return; + } + + response.setMethodFound("/401.html"); + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + if (isLoggedIn(request)) { + response.setMethodFound("/index.html"); + return; + } + response.setMethodFound("/index.html"); + } + + + + private boolean isLoggedIn(HttpRequest httpRequest) { + return Objects.nonNull(httpRequest.getSession(false)); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java index 7271f52192..94d154b8e9 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java @@ -1,11 +1,9 @@ package org.apache.coyote.http11.handler; import java.io.IOException; -import java.util.Objects; import org.apache.coyote.http11.RequestHandler; import org.apache.coyote.http11.exception.CanNotHandleRequest; -import org.apache.coyote.http11.exception.NoSuchUserException; import org.apache.coyote.http11.httpmessage.request.HttpRequest; import org.apache.coyote.http11.httpmessage.request.HttpRequestParameters; import org.apache.coyote.http11.httpmessage.response.HttpResponse; @@ -30,10 +28,6 @@ public void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws IO httpResponse.setResponseOfStaticResource(staticResource); return; } - if (httpRequest.getTarget().equals("/login")) { - loginResponse(httpRequest, httpResponse); - return; - } if (httpRequest.getTarget().contains("register")) { registerResponse(httpRequest, httpResponse); return; @@ -41,40 +35,6 @@ public void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws IO throw new CanNotHandleRequest("처리할 수 없는 요청입니다. : " + httpRequest.getTarget()); } - private void loginResponse(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { - if (httpRequest.isPost()) { - login(httpRequest, httpResponse); - return; - } - if (isLoggedIn(httpRequest)) { - httpResponse.setMethodFound("/index.html"); - return; - } - httpResponse.setMethodFound("/index.html"); - } - - private boolean isLoggedIn(HttpRequest httpRequest) { - return Objects.nonNull(httpRequest.getSession(false)); - } - - private void login(HttpRequest httpRequest, HttpResponse httpResponse) throws NoSuchUserException { - HttpRequestParameters requestParams = HttpRequestParameters.parseFrom(httpRequest.getBody()); - String account = requestParams.getParam("account"); - String password = requestParams.getParam("password"); - User user = InMemoryUserRepository.fetchByAccount(account); - if (user.checkPassword(password)) { - Session session = httpRequest.getSession(true); - session.setAttribute("user", user); - SessionManager.getInstance().add(session); - - httpResponse.addCookie("JSESSIONID", session.getId()); - httpResponse.setMethodFound("/index.html"); - return; - } - - httpResponse.setMethodFound("/401.html"); - } - private void registerResponse(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { if (httpRequest.isPost()) { HttpRequestParameters methodRequest = HttpRequestParameters.parseFrom(httpRequest.getBody()); From c48cd92b726e95e5692366b8fb2ed81323140852 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:27:14 +0900 Subject: [PATCH 17/37] =?UTF-8?q?refactor:=20RegisterController=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/RequestMappingConfig.java | 4 +- .../controller/RegisterController.java | 42 +++++++++++++++++++ .../handler/DefaultResourceHandler.java | 30 ------------- 3 files changed, 45 insertions(+), 31 deletions(-) create mode 100644 tomcat/src/main/java/com/techcourse/controller/RegisterController.java diff --git a/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java index 0248958d24..e0adfed951 100644 --- a/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java +++ b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java @@ -5,12 +5,14 @@ import org.apache.catalina.servlet.RequestMapping; import com.techcourse.controller.LoginController; +import com.techcourse.controller.RegisterController; public class RequestMappingConfig { public static RequestMapping getRequestMapping() { return new RequestMapping( Map.of( - "/login", new LoginController() + "/login", new LoginController(), + "/register", new RegisterController() ) ); } diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java new file mode 100644 index 0000000000..7b5f35ffdd --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -0,0 +1,42 @@ +package com.techcourse.controller; + +import org.apache.catalina.servlet.AbstractController; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.request.HttpRequestParameters; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; +import org.apache.coyote.http11.httpmessage.response.StaticResource; +import org.apache.coyote.session.Session; +import org.apache.coyote.session.SessionManager; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + +public class RegisterController extends AbstractController { + @Override + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { + HttpRequestParameters methodRequest = HttpRequestParameters.parseFrom(request.getBody()); + User user = register(methodRequest); + Session session = request.getSession(true); + session.setAttribute("user", user); + SessionManager.getInstance().add(session); + + response.addCookie("JSESSIONID", session.getId()); + response.setMethodFound("/index.html"); + } + + private User register(HttpRequestParameters requestParams) { + String account = requestParams.getParam("account"); + User user = new User( + account, + requestParams.getParam("password"), + requestParams.getParam("email") + ); + InMemoryUserRepository.save(user); + return InMemoryUserRepository.fetchByAccount(account); + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + response.setResponseOfStaticResource(new StaticResource("/register.html")); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java index 94d154b8e9..5e29b83316 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java @@ -28,37 +28,7 @@ public void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws IO httpResponse.setResponseOfStaticResource(staticResource); return; } - if (httpRequest.getTarget().contains("register")) { - registerResponse(httpRequest, httpResponse); - return; - } throw new CanNotHandleRequest("처리할 수 없는 요청입니다. : " + httpRequest.getTarget()); } - private void registerResponse(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { - if (httpRequest.isPost()) { - HttpRequestParameters methodRequest = HttpRequestParameters.parseFrom(httpRequest.getBody()); - User user = register(methodRequest); - Session session = httpRequest.getSession(true); - session.setAttribute("user", user); - SessionManager.getInstance().add(session); - - httpResponse.addCookie("JSESSIONID", session.getId()); - httpResponse.setMethodFound("/index.html"); - return; - } - - httpResponse.setResponseOfStaticResource(new StaticResource("/register.html")); - } - - private User register(HttpRequestParameters requestParams) { - String account = requestParams.getParam("account"); - User user = new User( - account, - requestParams.getParam("password"), - requestParams.getParam("email") - ); - InMemoryUserRepository.save(user); - return InMemoryUserRepository.fetchByAccount(account); - } } From c3ede1c0ffb4c57c56bdcbf246550e744e8df8a5 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:28:46 +0900 Subject: [PATCH 18/37] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=B7=B0=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/controller/LoginController.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index f489f28ebd..5df32a4fe5 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -6,6 +6,7 @@ import org.apache.coyote.http11.httpmessage.request.HttpRequest; import org.apache.coyote.http11.httpmessage.request.HttpRequestParameters; import org.apache.coyote.http11.httpmessage.response.HttpResponse; +import org.apache.coyote.http11.httpmessage.response.StaticResource; import org.apache.coyote.session.Session; import org.apache.coyote.session.SessionManager; @@ -38,11 +39,9 @@ protected void doGet(HttpRequest request, HttpResponse response) throws Exceptio response.setMethodFound("/index.html"); return; } - response.setMethodFound("/index.html"); + response.setResponseOfStaticResource(new StaticResource("/login.html")); } - - private boolean isLoggedIn(HttpRequest httpRequest) { return Objects.nonNull(httpRequest.getSession(false)); } From 2a115e6f290538c352815b8a82984d3afd964cf6 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:35:55 +0900 Subject: [PATCH 19/37] =?UTF-8?q?refactor:=20=EC=A0=95=EC=A0=81=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20Controller=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/RequestMappingConfig.java | 11 +++++- .../controller/StaticResourceController.java | 24 +++++++++++++ .../apache/coyote/http11/Http11Processor.java | 8 ----- .../apache/coyote/http11/RequestHandler.java | 11 ------ .../http11/exception/CanNotHandleRequest.java | 7 ---- .../handler/DefaultResourceHandler.java | 34 ------------------- 6 files changed, 34 insertions(+), 61 deletions(-) create mode 100644 tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/http11/exception/CanNotHandleRequest.java delete mode 100644 tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java diff --git a/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java index e0adfed951..ce2b78db11 100644 --- a/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java +++ b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java @@ -6,13 +6,22 @@ import com.techcourse.controller.LoginController; import com.techcourse.controller.RegisterController; +import com.techcourse.controller.StaticResourceController; public class RequestMappingConfig { public static RequestMapping getRequestMapping() { + var staticResourceController = new StaticResourceController(); return new RequestMapping( Map.of( "/login", new LoginController(), - "/register", new RegisterController() + "/register", new RegisterController(), + "/", staticResourceController, + "/index.html", staticResourceController, + "/login.html", staticResourceController, + "/register.html", staticResourceController, + "/css/styles.css", staticResourceController, + "/401.html", staticResourceController, + "/js/scripts.js", staticResourceController ) ); } diff --git a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java new file mode 100644 index 0000000000..b8d3608409 --- /dev/null +++ b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java @@ -0,0 +1,24 @@ +package com.techcourse.controller; + +import org.apache.catalina.servlet.AbstractController; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; +import org.apache.coyote.http11.httpmessage.response.StaticResource; + +public class StaticResourceController extends AbstractController { + @Override + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { + //todo 예외 처리? + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + if (request.getTarget().equals("/")) { + StaticResource staticResource = new StaticResource("/index.html"); + response.setResponseOfStaticResource(staticResource); + return; + } + StaticResource staticResource = new StaticResource(request.getTarget()); + response.setResponseOfStaticResource(staticResource); + } +} 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 6630fb702c..da82743a03 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -7,7 +7,6 @@ import org.apache.coyote.Processor; import org.apache.coyote.ServletContainer; -import org.apache.coyote.http11.handler.DefaultResourceHandler; import org.apache.coyote.http11.httpmessage.request.HttpRequest; import org.apache.coyote.http11.httpmessage.response.HttpResponse; import org.slf4j.Logger; @@ -19,13 +18,11 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); private final ServletContainer servletContainer; - private final RequestHandler requestHandler; private final Socket connection; public Http11Processor(ServletContainer servletContainer, Socket connection) { this.servletContainer = servletContainer; this.connection = connection; - this.requestHandler = new DefaultResourceHandler(); } @Override @@ -61,9 +58,4 @@ private void service(HttpRequest httpRequest, HttpResponse httpResponse) { //todo 예외 처리 } } - - private void getResponse(HttpRequest httpRequest) throws IOException { - HttpResponse httpResponse = new HttpResponse(httpRequest); - requestHandler.handle(httpRequest, httpResponse); - } } 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 350f7da8d8..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.apache.coyote.http11; - -import java.io.IOException; - -import org.apache.coyote.http11.httpmessage.request.HttpRequest; -import org.apache.coyote.http11.httpmessage.response.HttpResponse; - -@FunctionalInterface -public interface RequestHandler { - void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException; -} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/exception/CanNotHandleRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/exception/CanNotHandleRequest.java deleted file mode 100644 index 922fbc0c82..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http11/exception/CanNotHandleRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.apache.coyote.http11.exception; - -public class CanNotHandleRequest extends RuntimeException { - public CanNotHandleRequest(String message) { - super(message); - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java deleted file mode 100644 index 5e29b83316..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/DefaultResourceHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.apache.coyote.http11.handler; - -import java.io.IOException; - -import org.apache.coyote.http11.RequestHandler; -import org.apache.coyote.http11.exception.CanNotHandleRequest; -import org.apache.coyote.http11.httpmessage.request.HttpRequest; -import org.apache.coyote.http11.httpmessage.request.HttpRequestParameters; -import org.apache.coyote.http11.httpmessage.response.HttpResponse; -import org.apache.coyote.http11.httpmessage.response.StaticResource; -import org.apache.coyote.session.Session; -import org.apache.coyote.session.SessionManager; - -import com.techcourse.db.InMemoryUserRepository; -import com.techcourse.model.User; - -public class DefaultResourceHandler implements RequestHandler { - - @Override - public void handle(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { - if (httpRequest.isStaticResourceRequest()) { - StaticResource staticResource = new StaticResource(httpRequest.getTarget()); - httpResponse.setResponseOfStaticResource(staticResource); - return; - } - if (httpRequest.getTarget().equals("/")) { - StaticResource staticResource = new StaticResource("/index.html"); - httpResponse.setResponseOfStaticResource(staticResource); - return; - } - throw new CanNotHandleRequest("처리할 수 없는 요청입니다. : " + httpRequest.getTarget()); - } - -} From 3107316ea8335b4a341f5c578c653f4278c0dcd7 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:39:23 +0900 Subject: [PATCH 20/37] =?UTF-8?q?refactor:=20=EC=83=81=EC=88=98=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/controller/LoginController.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index 5df32a4fe5..d502a61094 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -1,5 +1,7 @@ package com.techcourse.controller; +import static org.apache.coyote.http11.httpmessage.HttpHeaders.JSESSIONID; + import java.util.Objects; import org.apache.catalina.servlet.AbstractController; @@ -25,7 +27,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti session.setAttribute("user", user); SessionManager.getInstance().add(session); - response.addCookie("JSESSIONID", session.getId()); + response.addCookie(JSESSIONID, session.getId()); response.setMethodFound("/index.html"); return; } From 9ff172288fc79cf1bec9cd61b93116a57d28f476 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:45:05 +0900 Subject: [PATCH 21/37] =?UTF-8?q?refactor:=20=EC=A0=95=EC=A0=81=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20POST=20=EC=9A=94=EC=B2=AD=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/controller/StaticResourceController.java | 5 ++++- .../http11/exception/CantHandleRequestException.java | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/exception/CantHandleRequestException.java diff --git a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java index b8d3608409..2bab1ab70f 100644 --- a/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java +++ b/tomcat/src/main/java/com/techcourse/controller/StaticResourceController.java @@ -1,6 +1,7 @@ package com.techcourse.controller; import org.apache.catalina.servlet.AbstractController; +import org.apache.coyote.http11.exception.CantHandleRequestException; import org.apache.coyote.http11.httpmessage.request.HttpRequest; import org.apache.coyote.http11.httpmessage.response.HttpResponse; import org.apache.coyote.http11.httpmessage.response.StaticResource; @@ -8,7 +9,9 @@ public class StaticResourceController extends AbstractController { @Override protected void doPost(HttpRequest request, HttpResponse response) throws Exception { - //todo 예외 처리? + throw new CantHandleRequestException( + String.format("%s %s 요청을 처리할 수 없습니다.", request.getMethod().name(), request.getTarget()) + ); } @Override diff --git a/tomcat/src/main/java/org/apache/coyote/http11/exception/CantHandleRequestException.java b/tomcat/src/main/java/org/apache/coyote/http11/exception/CantHandleRequestException.java new file mode 100644 index 0000000000..f81aa9cff8 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/exception/CantHandleRequestException.java @@ -0,0 +1,7 @@ +package org.apache.coyote.http11.exception; + +public class CantHandleRequestException extends RuntimeException { + public CantHandleRequestException(String message) { + super(message); + } +} From 410c5c5d102dfc46525af4860c6c9eff535fbd4f Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:47:30 +0900 Subject: [PATCH 22/37] =?UTF-8?q?refactor:=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=8B=A4=ED=8C=A8=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/http11/Http11Processor.java | 3 ++- .../coyote/http11/httpmessage/response/HttpResponse.java | 4 ++++ .../coyote/http11/httpmessage/response/HttpStatusLine.java | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index da82743a03..83b3273c94 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -55,7 +55,8 @@ private void service(HttpRequest httpRequest, HttpResponse httpResponse) { try { servletContainer.service(httpRequest, httpResponse); } catch (Exception e) { - //todo 예외 처리 + log.error("request 처리 실패 : ", e); + httpResponse.setMethodBadRequest(); } } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java index 278c2afcb6..6ac2bafe46 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java @@ -52,6 +52,10 @@ public void setMethodFound(String target) { this.headers.addHeader(HttpHeaders.LOCATION, target); } + public void setMethodBadRequest() { + this.httpStatusLine.setMethodBadRequest(); + } + public void setResponseOfStaticResource(StaticResource resource) throws IOException { this.httpStatusLine.setMethodOK(); headers.addHeader(HttpHeaders.CONTENT_TYPE, resource.getContentType() + ";charset=utf-8"); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java index 4333b77c07..0402b68ac6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java @@ -29,4 +29,9 @@ public void setMethodOK() { this.statusCode = 200; this.statusText = "OK"; } + + public void setMethodBadRequest() { + this.statusCode = 400; + this.statusText = "BAD REQUEST"; + } } From 810e43fd4adb80a2a1a645eb1b0deaf9082c9d7b Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:48:16 +0900 Subject: [PATCH 23/37] =?UTF-8?q?refactor:=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catalina/exception/NoMatchedControllerException.java | 7 +++++++ .../catalina/exception/NoMatchedHandlerException.java | 7 ------- .../java/org/apache/catalina/servlet/RequestMapping.java | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/catalina/exception/NoMatchedControllerException.java delete mode 100644 tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java diff --git a/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedControllerException.java b/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedControllerException.java new file mode 100644 index 0000000000..851114b214 --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedControllerException.java @@ -0,0 +1,7 @@ +package org.apache.catalina.exception; + +public class NoMatchedControllerException extends RuntimeException { + public NoMatchedControllerException(String message) { + super(message); + } +} diff --git a/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java b/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java deleted file mode 100644 index 0d08a06d54..0000000000 --- a/tomcat/src/main/java/org/apache/catalina/exception/NoMatchedHandlerException.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.apache.catalina.exception; - -public class NoMatchedHandlerException extends RuntimeException { - public NoMatchedHandlerException(String message) { - super(message); - } -} diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java index cae2f89a68..f9e2e8cbea 100644 --- a/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java +++ b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java @@ -2,7 +2,7 @@ import java.util.Map; -import org.apache.catalina.exception.NoMatchedHandlerException; +import org.apache.catalina.exception.NoMatchedControllerException; import org.apache.coyote.http11.httpmessage.request.HttpRequest; public class RequestMapping { @@ -16,6 +16,6 @@ public Controller getController(HttpRequest request) { if (mappedController.containsKey(request.getTarget())) { return mappedController.get(request.getTarget()); } - throw new NoMatchedHandlerException(request.getTarget() + " 요청을 처리할 컨트롤러가 존재하지 않습니다."); + throw new NoMatchedControllerException(request.getTarget() + " 요청을 처리할 컨트롤러가 존재하지 않습니다."); } } From ccd4e8817a6684f8dd100b7a44d1563862d1c40e Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:51:11 +0900 Subject: [PATCH 24/37] =?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=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/httpmessage/response/HttpStatusLine.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java index 0402b68ac6..54ab713cd3 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java @@ -16,10 +16,6 @@ public String toHttpMessage() { return String.format("%s %s %s ", httpVersion, statusCode, statusText); } - public void setHttpVersion(String httpVersion) { - this.httpVersion = httpVersion; - } - public void setMethodFound() { this.statusCode = 301; this.statusText = "FOUND"; From a997bf1fcef78cf75e63a057ee64df3be6c779dd Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:54:00 +0900 Subject: [PATCH 25/37] =?UTF-8?q?refactor:=20HttpStatus=20enum=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 --- .../controller/LoginController.java | 6 ++--- .../controller/RegisterController.java | 2 +- .../apache/coyote/http11/Http11Processor.java | 2 +- .../httpmessage/response/HttpResponse.java | 10 ++++---- .../httpmessage/response/HttpStatus.java | 23 +++++++++++++++++++ .../httpmessage/response/HttpStatusLine.java | 16 +++---------- 6 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java diff --git a/tomcat/src/main/java/com/techcourse/controller/LoginController.java b/tomcat/src/main/java/com/techcourse/controller/LoginController.java index d502a61094..c2b8933b2b 100644 --- a/tomcat/src/main/java/com/techcourse/controller/LoginController.java +++ b/tomcat/src/main/java/com/techcourse/controller/LoginController.java @@ -28,17 +28,17 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti SessionManager.getInstance().add(session); response.addCookie(JSESSIONID, session.getId()); - response.setMethodFound("/index.html"); + response.setStatusFound("/index.html"); return; } - response.setMethodFound("/401.html"); + response.setStatusFound("/401.html"); } @Override protected void doGet(HttpRequest request, HttpResponse response) throws Exception { if (isLoggedIn(request)) { - response.setMethodFound("/index.html"); + response.setStatusFound("/index.html"); return; } response.setResponseOfStaticResource(new StaticResource("/login.html")); diff --git a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java index 7b5f35ffdd..701643895c 100644 --- a/tomcat/src/main/java/com/techcourse/controller/RegisterController.java +++ b/tomcat/src/main/java/com/techcourse/controller/RegisterController.java @@ -21,7 +21,7 @@ protected void doPost(HttpRequest request, HttpResponse response) throws Excepti SessionManager.getInstance().add(session); response.addCookie("JSESSIONID", session.getId()); - response.setMethodFound("/index.html"); + response.setStatusFound("/index.html"); } private User register(HttpRequestParameters requestParams) { 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 83b3273c94..7b916a50a3 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -56,7 +56,7 @@ private void service(HttpRequest httpRequest, HttpResponse httpResponse) { servletContainer.service(httpRequest, httpResponse); } catch (Exception e) { log.error("request 처리 실패 : ", e); - httpResponse.setMethodBadRequest(); + httpResponse.setStatusBadRequest(); } } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java index 6ac2bafe46..a14100baaf 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java @@ -47,17 +47,17 @@ private void setCookie() { } } - public void setMethodFound(String target) { - this.httpStatusLine.setMethodFound(); + public void setStatusFound(String target) { + this.httpStatusLine.setStatus(HttpStatus.FOUND); this.headers.addHeader(HttpHeaders.LOCATION, target); } - public void setMethodBadRequest() { - this.httpStatusLine.setMethodBadRequest(); + public void setStatusBadRequest() { + this.httpStatusLine.setStatus(HttpStatus.BAD_REQUEST); } public void setResponseOfStaticResource(StaticResource resource) throws IOException { - this.httpStatusLine.setMethodOK(); + this.httpStatusLine.setStatus(HttpStatus.OK); headers.addHeader(HttpHeaders.CONTENT_TYPE, resource.getContentType() + ";charset=utf-8"); headers.addHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(resource.getContentLength())); this.body = resource.getContent(); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java new file mode 100644 index 0000000000..5af1b10649 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java @@ -0,0 +1,23 @@ +package org.apache.coyote.http11.httpmessage.response; + +public enum HttpStatus { + OK(200, "OK"), + FOUND(301, "FOUND"), + BAD_REQUEST(400, "BAD REQUEST") + ; + private final int statusCode; + private final String statusText; + + HttpStatus(int statusCode, String statusText) { + this.statusCode = statusCode; + this.statusText = statusText; + } + + public int getStatusCode() { + return statusCode; + } + + public String getStatusText() { + return statusText; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java index 54ab713cd3..16a0960dd3 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java @@ -16,18 +16,8 @@ public String toHttpMessage() { return String.format("%s %s %s ", httpVersion, statusCode, statusText); } - public void setMethodFound() { - this.statusCode = 301; - this.statusText = "FOUND"; - } - - public void setMethodOK() { - this.statusCode = 200; - this.statusText = "OK"; - } - - public void setMethodBadRequest() { - this.statusCode = 400; - this.statusText = "BAD REQUEST"; + public void setStatus(HttpStatus status) { + this.statusCode = status.getStatusCode(); + this.statusText = status.getStatusText(); } } From f7af5c5260cb17b4633f3d4b38907f9534dd6df5 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 09:59:05 +0900 Subject: [PATCH 26/37] =?UTF-8?q?refactor:=20=ED=95=84=EB=93=9C=EC=97=90?= =?UTF-8?q?=20final=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/httpmessage/response/HttpResponse.java | 4 ++-- .../coyote/http11/httpmessage/response/HttpStatusLine.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java index a14100baaf..32aacfdfb6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java @@ -10,8 +10,8 @@ public class HttpResponse { private final HttpCookie httpCookie; - private HttpStatusLine httpStatusLine; - private HttpHeaders headers; + private final HttpStatusLine httpStatusLine; + private final HttpHeaders headers; private String body; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java index 16a0960dd3..fa69d23bf1 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java @@ -2,7 +2,8 @@ public class HttpStatusLine { - private String httpVersion; + private final String httpVersion; + private int statusCode; private String statusText; From f08952bf558569335c2de72f46949e268e9f2b09 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 10:02:49 +0900 Subject: [PATCH 27/37] =?UTF-8?q?refactor:=20=EA=B8=B0=EB=B3=B8=EC=A0=81?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=83=9D=EC=84=B1=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=EC=9D=84=20NOT=5FFOUND=20=EB=A1=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/httpmessage/response/HttpResponse.java | 2 +- .../coyote/http11/httpmessage/response/HttpStatus.java | 5 +++-- .../coyote/http11/httpmessage/response/HttpStatusLine.java | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java index 32aacfdfb6..da29d1e2bc 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java @@ -24,7 +24,7 @@ public HttpResponse(HttpStatusLine httpStatusLine, HttpHeaders headers, String b public HttpResponse(HttpRequest httpRequest) { - this(new HttpStatusLine(httpRequest.getHttpVersion(), 0, null), //todo 생성 방식 고민 + this(new HttpStatusLine(httpRequest.getHttpVersion(), HttpStatus.NOT_FOUND), new HttpHeaders(), ""); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java index 5af1b10649..e1595c8a08 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatus.java @@ -3,8 +3,9 @@ public enum HttpStatus { OK(200, "OK"), FOUND(301, "FOUND"), - BAD_REQUEST(400, "BAD REQUEST") - ; + BAD_REQUEST(400, "BAD REQUEST"), + NOT_FOUND(404, "NOT FOUND"); + private final int statusCode; private final String statusText; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java index fa69d23bf1..b0f4e0f376 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpStatusLine.java @@ -7,10 +7,10 @@ public class HttpStatusLine { private int statusCode; private String statusText; - public HttpStatusLine(String httpVersion, int statusCode, String statusText) { + public HttpStatusLine(String httpVersion, HttpStatus httpStatus) { this.httpVersion = httpVersion; - this.statusCode = statusCode; - this.statusText = statusText; + this.statusCode = httpStatus.getStatusCode(); + this.statusText = httpStatus.getStatusText(); } public String toHttpMessage() { From a5e7582f941e7d3617d345ef34326706d51bf171 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 11:33:59 +0900 Subject: [PATCH 28/37] =?UTF-8?q?test:=20PathMatchServletContainer=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TestPathServletContainerConfig.java | 37 +++++++++++++ .../PathMatchServletContainerTest.java | 55 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/catalina/TestPathServletContainerConfig.java create mode 100644 tomcat/src/test/java/org/apache/catalina/servlet/PathMatchServletContainerTest.java diff --git a/tomcat/src/test/java/org/apache/catalina/TestPathServletContainerConfig.java b/tomcat/src/test/java/org/apache/catalina/TestPathServletContainerConfig.java new file mode 100644 index 0000000000..a636d3678a --- /dev/null +++ b/tomcat/src/test/java/org/apache/catalina/TestPathServletContainerConfig.java @@ -0,0 +1,37 @@ +package org.apache.catalina; + +import java.util.Map; + +import org.apache.catalina.servlet.AbstractController; +import org.apache.catalina.servlet.RequestMapping; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; +import org.apache.coyote.http11.httpmessage.response.StaticResource; + +import com.techcourse.controller.StaticResourceController; + +public class TestPathServletContainerConfig { + + public static final String SUCCESS_PATH = "/success"; + + public static RequestMapping getRequestMapping() { + return new RequestMapping( + Map.of( + SUCCESS_PATH, new SuccessController() + ) + ); + } + + private static class SuccessController extends AbstractController { + + @Override + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { + response.setResponseOfStaticResource(new StaticResource("/index.html")); + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + response.setResponseOfStaticResource(new StaticResource("/index.html")); + } + } +} diff --git a/tomcat/src/test/java/org/apache/catalina/servlet/PathMatchServletContainerTest.java b/tomcat/src/test/java/org/apache/catalina/servlet/PathMatchServletContainerTest.java new file mode 100644 index 0000000000..f840e3432b --- /dev/null +++ b/tomcat/src/test/java/org/apache/catalina/servlet/PathMatchServletContainerTest.java @@ -0,0 +1,55 @@ +package org.apache.catalina.servlet; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.catalina.TestPathServletContainerConfig; +import org.apache.catalina.exception.NoMatchedControllerException; +import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.http11.httpmessage.response.HttpResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PathMatchServletContainerTest { + + private PathMatchServletContainer pathMatchServletContainer = new PathMatchServletContainer( + TestPathServletContainerConfig.getRequestMapping() + ); + + @Test + @DisplayName("매핑 되는 경로의 컨트롤러가 존재하면 요청을 처리할 수 있다.") + void successService() throws IOException { + //given + HttpRequest httpRequest = makeRequestFrom("GET /success HTTP/1.1 "); + HttpResponse httpResponse = new HttpResponse(httpRequest); + + //when & then + assertThatCode(() -> pathMatchServletContainer.service(httpRequest, httpResponse)) + .doesNotThrowAnyException(); + } + + @Test + @DisplayName("매핑 되는 경로의 컨트롤러가 존재하지 않으면 예외가 발생한다.") + void failServiceNotMatchController() throws IOException { + //given + HttpRequest httpRequest = makeRequestFrom("GET /fail HTTP/1.1 "); + HttpResponse httpResponse = new HttpResponse(httpRequest); + + //when & then + assertThatThrownBy(() -> pathMatchServletContainer.service(httpRequest, httpResponse)) + .isInstanceOf(NoMatchedControllerException.class) + .hasMessage(httpRequest.getTarget() + " 요청을 처리할 컨트롤러가 존재하지 않습니다."); + } + + private HttpRequest makeRequestFrom(String requestMessage) throws IOException { + var bufferedInputStream = new BufferedReader( + new InputStreamReader(new ByteArrayInputStream(requestMessage.getBytes())) + ); + return HttpRequest.readFrom(bufferedInputStream); + } +} From d025b9b2d6c1b55abca483ecb1ad671f19f2e315 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 13:44:40 +0900 Subject: [PATCH 29/37] =?UTF-8?q?test:=20SessionManager=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/session/SessionManagerTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/coyote/session/SessionManagerTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/session/SessionManagerTest.java b/tomcat/src/test/java/org/apache/coyote/session/SessionManagerTest.java new file mode 100644 index 0000000000..86069c4c09 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/session/SessionManagerTest.java @@ -0,0 +1,45 @@ +package org.apache.coyote.session; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class SessionManagerTest { + + @Test + @DisplayName("SessionManager 를 싱글톤으로 관리한다.") + void singletonTest() { + SessionManager sessionManager1 = SessionManager.getInstance(); + SessionManager sessionManager2 = SessionManager.getInstance(); + + assertThat(sessionManager1).isSameAs(sessionManager2); + } + + @Test + @DisplayName("Session 을 저장하고 session id 값으로 다시 조회할 수 있다.") + void sessionAddAndFindTest() { + String sessionId = "sessionId"; + Session session = new Session(sessionId); + SessionManager sessionManager = SessionManager.getInstance(); + + sessionManager.add(session); + + assertThat(sessionManager.findSession(sessionId)) + .isEqualTo(session); + } + + @Test + @DisplayName("Session 을 삭제하면 session id 값으로 조회했을 때 null 이 나온다.") + void sessionRemoveAndFindTest() { + String sessionId = "sessionId"; + Session session = new Session(sessionId); + SessionManager sessionManager = SessionManager.getInstance(); + + sessionManager.add(session); + sessionManager.remove(sessionId); + + assertThat(sessionManager.findSession(sessionId)) + .isNull(); + } +} From 9c836eff6620d78dbd9083cd9a08b17902cfd0be Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 13:50:45 +0900 Subject: [PATCH 30/37] =?UTF-8?q?test:=20Session=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/session/SessionTest.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/coyote/session/SessionTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/session/SessionTest.java b/tomcat/src/test/java/org/apache/coyote/session/SessionTest.java new file mode 100644 index 0000000000..f8a5c0500f --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/session/SessionTest.java @@ -0,0 +1,53 @@ +package org.apache.coyote.session; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class SessionTest { + + @Test + @DisplayName("세션에 정보를 저장하고 조회할 수 있다.") + void sessionAddTest () { + Session session = new Session("id"); + + session.setAttribute("key", "value"); + + assertThat(session.getAttribute("key")) + .isEqualTo("value"); + } + + @Test + @DisplayName("세션에 정보를 삭제하면 정보 조회시 null 이 반환된다.") + void sessionAttributeRemoveTest () { + Session session = new Session("id"); + + session.setAttribute("key", "value"); + session.removeAttribute("key"); + + assertThat(session.getAttribute("key")) + .isNull(); + } + + @Test + @DisplayName("세션을 만료 시키면 모든 데이터가 삭제된다..") + void sessionInvalidateTest () { + Session session = new Session("id"); + + session.setAttribute("key1", "value1"); + session.setAttribute("key2", "value2"); + session.setAttribute("key3", "value3"); + session.invalidate(); + + assertAll( + () -> assertThat(session.getAttribute("key1")) + .isNull(), + () -> assertThat(session.getAttribute("key2")) + .isNull(), + () -> assertThat(session.getAttribute("key3")) + .isNull() + ); + } +} From 59adc64dcd51c058e8f5ed30fdb382ef5adc69d2 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 14:18:12 +0900 Subject: [PATCH 31/37] =?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=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/httpmessage/request/HttpRequest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java index 74de827fbc..f0db2f9b5f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/request/HttpRequest.java @@ -78,10 +78,6 @@ public boolean isPost() { return httpRequestLine.isPost(); } - public boolean isStaticResourceRequest() { - return httpRequestLine.isStaticResourceRequest(); - } - public HttpMethod getMethod() { return httpRequestLine.httpMethod(); } From 0c6e4e2c674c20e9f318a7666dfce27baacb1838 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 14:29:59 +0900 Subject: [PATCH 32/37] =?UTF-8?q?test:=20=EC=84=B8=EC=85=98=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EA=B4=80=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../httpmessage/request/HttpMethodTest.java | 43 +++++++ .../http11/request/HttpRequestTest.java | 117 +++++++++++++++--- 2 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpMethodTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpMethodTest.java b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpMethodTest.java new file mode 100644 index 0000000000..b83201eb4b --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/httpmessage/request/HttpMethodTest.java @@ -0,0 +1,43 @@ +package org.apache.coyote.http11.httpmessage.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class HttpMethodTest { + + @Nested + @DisplayName("이름 조회 테스트") + class FindByName { + + @ParameterizedTest + @EnumSource(value = HttpMethod.class) + @DisplayName("Http 메서드 이름으로 HttpMethod 객체를 조회할 수 있다.") + void successTest(HttpMethod givenMethod) { + HttpMethod findMethod = HttpMethod.findByName(givenMethod.name()); + + assertThat(findMethod).isEqualTo(givenMethod); + } + + @Test + @DisplayName("잘못된 이름으로 HttpMethod 를 조회하면 예외가 발생한다.") + void wrongNameTest() { + assertThatThrownBy(() -> HttpMethod.findByName("wrongName")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("잘못된 Http 메서드 입니다."); + } + + @Test + @DisplayName("null 로 HttpMethod 를 조회하면 예외가 발생한다.") + void nullNameTest() { + assertThatThrownBy(() -> HttpMethod.findByName(null)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("잘못된 Http 메서드 입니다."); + } + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestTest.java b/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestTest.java index a4a795a830..6c9eada100 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestTest.java @@ -11,6 +11,8 @@ import org.apache.coyote.http11.httpmessage.request.HttpMethod; import org.apache.coyote.http11.httpmessage.request.HttpRequest; +import org.apache.coyote.session.Session; +import org.apache.coyote.session.SessionManager; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -22,28 +24,115 @@ class HttpRequestTest { class ConstructorTest { @Test - @DisplayName("GET 요청 생성 테스트") + @DisplayName("요청 생성 테스트") void getRequestConstructTest() throws IOException { //given - String input = """ - GET /index.html HTTP/1.1 - Host: localhost:8080 - Connection: keep-alive - - """; + String requestBody = "requestBody"; + String requestMessage = String.join("\r\n", + "POST /target HTTP/1.1", + "Host: localhost:8080", + "Connection: keep-alive", + "Content-Length: " + requestBody.getBytes().length, + "", + requestBody); //when - InputStream requestStream = new ByteArrayInputStream(input.getBytes()); - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(requestStream)); - - - HttpRequest httpRequest = HttpRequest.readFrom(bufferedReader); + HttpRequest request = createRequest(requestMessage); //then assertAll( - () -> assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.GET), - () -> assertThat(httpRequest.getTarget()).isEqualTo("/index.html") + () -> assertThat(request.getMethod()).isEqualTo(HttpMethod.POST), + () -> assertThat(request.getTarget()).isEqualTo("/target"), + () -> assertThat(request.getHttpVersion()).isEqualTo("HTTP/1.1"), + () -> assertThat(request.getBody()).isEqualTo(requestBody) ); } } + + @Nested + @DisplayName("세션 생성 테스트") + class SessionTest { + + @Nested + @DisplayName("쿠키로 JSESSIONID 를 가지고 있는 HttpRequest 객체는") + class ContainCookieTest { + String requestMessage = String.join("\r\n", + "GET /target HTTP/1.1", + "Host: localhost:8080", + "Connection: keep-alive", + "Cookie: JSESSIONID=1234", + ""); + + @Test + @DisplayName("세션을 조회할 수 있다.") + void findSessionTest() throws IOException { + //given + SessionManager.getInstance().add(new Session("1234")); + HttpRequest request = createRequest(requestMessage); + + //when + Session session = request.getSession(false); + + //then + assertThat(session.getId()).isEqualTo("1234"); + } + + @Test + @DisplayName("세션을 생성해도 원래의 세션이 조회된다.") + void createSessionTest() throws IOException { + //given + SessionManager.getInstance().add(new Session("1234")); + HttpRequest request = createRequest(requestMessage); + + //when + Session session = request.getSession(true); + + //then + assertThat(session.getId()).isEqualTo("1234"); + } + } + + @Nested + @DisplayName("쿠키로 JSESSIONID 를 가지고 있지 않은 HttpRequest 객체는") + class NotContainCookieTest { + String requestMessage = String.join("\r\n", + "GET /target HTTP/1.1", + "Host: localhost:8080", + "Connection: keep-alive", + ""); + + @Test + @DisplayName("세션을 조회하면 null 이 반환된다.") + void findSessionTest() throws IOException { + //given + HttpRequest request = createRequest(requestMessage); + + //when + Session session = request.getSession(false); + + //then + assertThat(session).isNull(); + } + + @Test + @DisplayName("세션을 새로 생성할 수 있다.") + void createSessionTest() throws IOException { + //given + HttpRequest request = createRequest(requestMessage); + + //when + Session session = request.getSession(true); + + //then + assertThat(session.getId()).isNotNull(); + } + } + } + + private HttpRequest createRequest(String httpRequestText) throws IOException { + InputStream requestStream = new ByteArrayInputStream(httpRequestText.getBytes()); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(requestStream)); + + return HttpRequest.readFrom(bufferedReader); + } } From c15f56d4c2c3960d19cd04c5ef0e6ccd6d6b3bc7 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 14:39:09 +0900 Subject: [PATCH 33/37] =?UTF-8?q?test:=20=ED=95=99=EC=8A=B5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20stage=200=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thread/stage0/SynchronizationTest.java | 2 +- .../java/thread/stage0/ThreadPoolsTest.java | 20 ++++++++++++++++--- .../test/java/thread/stage0/ThreadTest.java | 19 ++++++++++++------ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/study/src/test/java/thread/stage0/SynchronizationTest.java b/study/src/test/java/thread/stage0/SynchronizationTest.java index 0333c18e3b..b463c2b984 100644 --- a/study/src/test/java/thread/stage0/SynchronizationTest.java +++ b/study/src/test/java/thread/stage0/SynchronizationTest.java @@ -41,7 +41,7 @@ private static final class SynchronizedMethods { private int sum = 0; - public void calculate() { + public synchronized void calculate() { setSum(getSum() + 1); } diff --git a/study/src/test/java/thread/stage0/ThreadPoolsTest.java b/study/src/test/java/thread/stage0/ThreadPoolsTest.java index 238611ebfe..28b6e8f11c 100644 --- a/study/src/test/java/thread/stage0/ThreadPoolsTest.java +++ b/study/src/test/java/thread/stage0/ThreadPoolsTest.java @@ -28,11 +28,14 @@ void testNewFixedThreadPool() { final var executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); executor.submit(logWithSleep("hello fixed thread pools")); executor.submit(logWithSleep("hello fixed thread pools")); + //() -> {} 로 바꾸면 queueSize 가 0으로 줄어듬 executor.submit(logWithSleep("hello fixed thread pools")); // 올바른 값으로 바꿔서 테스트를 통과시키자. - final int expectedPoolSize = 0; - final int expectedQueueSize = 0; + final int expectedPoolSize = 2; + //-> 스레드 개수를 2개로 지정해 두었으니 expectedPoolSize 는 2개 + final int expectedQueueSize = 1; + //-> 아직 2개의 스레드가 모두 종료되지 않았기 때문에 대기중인 스레드 Queue 의 size() 값은 1 assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize()); assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size()); @@ -41,16 +44,27 @@ void testNewFixedThreadPool() { @Test void testNewCachedThreadPool() { final var executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); + //이 테스트는 뭐지?? + //https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool-- executor.submit(logWithSleep("hello cached thread pools")); executor.submit(logWithSleep("hello cached thread pools")); executor.submit(logWithSleep("hello cached thread pools")); // 올바른 값으로 바꿔서 테스트를 통과시키자. - final int expectedPoolSize = 0; + final int expectedPoolSize = 3; final int expectedQueueSize = 0; assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize()); assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size()); + /** + * 정리하면 + * newFixedThreadPool : 최대 스레드 크기를 지정 + * 매번 새로운 스레드 생성? + * + * Cached~ + * : 가용 시스템 리소스가 없을 때 까지 생성 가능 + * : 재활용할 수 있음 + */ } private Runnable logWithSleep(final String message) { diff --git a/study/src/test/java/thread/stage0/ThreadTest.java b/study/src/test/java/thread/stage0/ThreadTest.java index 3ffef18869..c145ad4a55 100644 --- a/study/src/test/java/thread/stage0/ThreadTest.java +++ b/study/src/test/java/thread/stage0/ThreadTest.java @@ -1,5 +1,9 @@ package thread.stage0; +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.Thread.State; + import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,10 +12,10 @@ * 자바로 동시에 여러 작업을 처리할 때 스레드를 사용한다. * 스레드 객체를 직접 생성하는 방법부터 알아보자. * 진행하면서 막히는 부분은 아래 링크를 참고해서 해결한다. - * + *

* Thread Objects * https://docs.oracle.com/javase/tutorial/essential/concurrency/threads.html - * + *

* Defining and Starting a Thread * https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html */ @@ -28,12 +32,15 @@ class ThreadTest { void testExtendedThread() throws InterruptedException { // 하단의 ExtendedThread 클래스를 Thread 클래스로 상속하고 스레드 객체를 생성한다. Thread thread = new ExtendedThread("hello thread"); + assertThat(thread.getState()).isEqualTo(State.NEW); // 생성한 thread 객체를 시작한다. - thread.start(); + thread.start(); + assertThat(thread.getState()).isEqualTo(State.RUNNABLE); // thread의 작업이 완료될 때까지 기다린다. - thread.join(); + thread.join(); + assertThat(thread.getState()).isEqualTo(State.TERMINATED); } /** @@ -46,10 +53,10 @@ void testRunnableThread() throws InterruptedException { Thread thread = new Thread(new RunnableThread("hello thread")); // 생성한 thread 객체를 시작한다. - thread.start(); + thread.start(); // thread의 작업이 완료될 때까지 기다린다. - thread.join(); + thread.join(); } private static final class ExtendedThread extends Thread { From fc516c041b5176f41feb7432b54d6b74231777ac Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 14:40:03 +0900 Subject: [PATCH 34/37] =?UTF-8?q?test:=20=ED=95=99=EC=8A=B5=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20stage=201=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/test/java/thread/stage1/UserServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/study/src/test/java/thread/stage1/UserServlet.java b/study/src/test/java/thread/stage1/UserServlet.java index b180a84c32..a78e7b4ad4 100644 --- a/study/src/test/java/thread/stage1/UserServlet.java +++ b/study/src/test/java/thread/stage1/UserServlet.java @@ -11,7 +11,7 @@ public void service(final User user) { join(user); } - private void join(final User user) { + private synchronized void join(final User user) { if (!users.contains(user)) { users.add(user); } From 3761410757d1aed21430817051b9555f1da7b64f Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 15:28:36 +0900 Subject: [PATCH 35/37] =?UTF-8?q?fix:=20config=20=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=9C=20RequestMapping=20=EC=9D=84=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/com/techcourse/Application.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tomcat/src/main/java/com/techcourse/Application.java b/tomcat/src/main/java/com/techcourse/Application.java index b2ab9852c7..c4b9e86137 100644 --- a/tomcat/src/main/java/com/techcourse/Application.java +++ b/tomcat/src/main/java/com/techcourse/Application.java @@ -1,19 +1,15 @@ package com.techcourse; -import java.util.Map; - import org.apache.catalina.servlet.PathMatchServletContainer; import org.apache.catalina.servlet.RequestMapping; import org.apache.catalina.startup.Tomcat; -import com.techcourse.controller.LoginController; +import com.techcourse.config.RequestMappingConfig; public class Application { public static void main(String[] args) { - RequestMapping requestMapping = new RequestMapping( - Map.of("/login", new LoginController()) - ); + RequestMapping requestMapping = RequestMappingConfig.getRequestMapping(); PathMatchServletContainer servletContainer = new PathMatchServletContainer(requestMapping); var tomcat = new Tomcat(servletContainer); tomcat.start(); From d4b71c5c48006226e5906dd757055f693f1186b5 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 15:49:54 +0900 Subject: [PATCH 36/37] =?UTF-8?q?refactor:=20=ED=9C=B4=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8B=B1=20=EC=BA=90=EC=8B=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 4 ++++ .../httpmessage/response/HttpResponse.java | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) 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 7b916a50a3..cd60a86516 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -54,6 +54,10 @@ public void process(Socket connection) { private void service(HttpRequest httpRequest, HttpResponse httpResponse) { try { servletContainer.service(httpRequest, httpResponse); + if(!httpResponse.containsHeader("Cache-Control")) { + httpResponse.addHeader("Cache-Control", "no-cache, private"); + } + } catch (Exception e) { log.error("request 처리 실패 : ", e); httpResponse.setStatusBadRequest(); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java index da29d1e2bc..1f8829ac82 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/httpmessage/response/HttpResponse.java @@ -29,6 +29,14 @@ public HttpResponse(HttpRequest httpRequest) { ""); } + public boolean containsHeader(String headerName) { + return headers.contains(headerName); + } + + public void addHeader(String name, String value) { + headers.addHeader(name, value); + } + public String toHttpMessage() { if (httpStatusLine == null) { throw new NotCompleteResponseException("응답이 완성되지 않았습니다."); @@ -66,4 +74,14 @@ public void setResponseOfStaticResource(StaticResource resource) throws IOExcept public void addCookie(String key, String value) { httpCookie.addCookie(key, value); } + + @Override + public String toString() { + return "HttpResponse{" + + "httpCookie=" + httpCookie + + ", httpStatusLine=" + httpStatusLine + + ", headers=" + headers + + ", body='" + body + '\'' + + '}'; + } } From 679b8724753d10de3c62fc98f28660d79eed5e13 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 13 Sep 2024 15:51:04 +0900 Subject: [PATCH 37/37] =?UTF-8?q?fix:=20=EC=9A=94=EC=B2=AD=20=EB=A7=A4?= =?UTF-8?q?=ED=95=91=EC=9D=84=20=EC=A0=95=EA=B7=9C=EC=8B=9D=EC=9D=84=20?= =?UTF-8?q?=ED=86=B5=ED=95=B4=20=EC=A7=84=ED=96=89=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/techcourse/config/RequestMappingConfig.java | 7 +------ .../org/apache/catalina/servlet/RequestMapping.java | 11 +++++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java index ce2b78db11..50649c1eb9 100644 --- a/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java +++ b/tomcat/src/main/java/com/techcourse/config/RequestMappingConfig.java @@ -16,12 +16,7 @@ public static RequestMapping getRequestMapping() { "/login", new LoginController(), "/register", new RegisterController(), "/", staticResourceController, - "/index.html", staticResourceController, - "/login.html", staticResourceController, - "/register.html", staticResourceController, - "/css/styles.css", staticResourceController, - "/401.html", staticResourceController, - "/js/scripts.js", staticResourceController + ".*\\.(js|html|css)$", staticResourceController ) ); } diff --git a/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java index f9e2e8cbea..dbc7cdef21 100644 --- a/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java +++ b/tomcat/src/main/java/org/apache/catalina/servlet/RequestMapping.java @@ -13,9 +13,12 @@ public RequestMapping(Map mappedController) { } public Controller getController(HttpRequest request) { - if (mappedController.containsKey(request.getTarget())) { - return mappedController.get(request.getTarget()); - } - throw new NoMatchedControllerException(request.getTarget() + " 요청을 처리할 컨트롤러가 존재하지 않습니다."); + String controllerKey = mappedController.keySet().stream() + .filter(pathRegex -> request.getTarget().matches(pathRegex)) + .findFirst() + .orElseThrow(() -> new NoMatchedControllerException( + request.getTarget() + " 요청을 처리할 컨트롤러가 존재하지 않습니다.") + ); + return mappedController.get(controllerKey); } }