From f54bffd42caf7b6f5625518eea53b06886623e85 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Mon, 4 Sep 2023 19:45:13 +0900 Subject: [PATCH 01/32] =?UTF-8?q?refactor:=20request=EC=97=90=20HttpHeader?= =?UTF-8?q?s=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 8 ++++---- .../http11/{ => request}/HttpRequest.java | 13 ++++++------ .../HttpRequestLine.java} | 0 .../{ => request}/HttpRequestParser.java | 20 ++++++++++--------- .../http11/{ => response}/HttpResponse.java | 0 .../http11/{ => response}/HttpStatusCode.java | 0 6 files changed, 22 insertions(+), 19 deletions(-) rename tomcat/src/main/java/org/apache/coyote/http11/{ => request}/HttpRequest.java (59%) rename tomcat/src/main/java/org/apache/coyote/http11/{RequestLine.java => request/HttpRequestLine.java} (100%) rename tomcat/src/main/java/org/apache/coyote/http11/{ => request}/HttpRequestParser.java (71%) rename tomcat/src/main/java/org/apache/coyote/http11/{ => response}/HttpResponse.java (100%) rename tomcat/src/main/java/org/apache/coyote/http11/{ => response}/HttpStatusCode.java (100%) 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 b45081fb6c..639a065a44 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -46,7 +46,7 @@ public void process(final Socket connection) { final HttpRequestParser httpRequestParser = new HttpRequestParser(reader); final HttpRequest httpRequest = httpRequestParser.parse(); - final HttpCookie httpCookie = HttpCookie.of(httpRequest.getHeader().get("Cookie")); + final HttpCookie httpCookie = HttpCookie.of(httpRequest.getHeaders().get("Cookie")); // TODO: generate RequestHandler final HttpResponse httpResponse = handleRequest(httpRequest); @@ -103,7 +103,7 @@ private HttpResponse handleRegisterRequest(final HttpRequest httpRequest) throws } private HttpResponse handleLoginRequest(final HttpRequest httpRequest) throws IOException { - final HttpCookie httpCookie = HttpCookie.of(httpRequest.getHeader().get("Cookie")); + final HttpCookie httpCookie = HttpCookie.of(httpRequest.getHeaders().get("Cookie")); String sessionId = httpCookie.getCookie("JSESSIONID"); if (httpRequest.getMethod().equals("GET")) { @@ -162,8 +162,8 @@ private HttpResponse handleResourceRequest(final HttpRequest httpRequest, final final HttpResponse httpResponse = HttpResponse.init(); String contentType = "text/html;charset=utf-8"; - if (httpRequest.getHeader().get("Accept") != null) { - contentType = httpRequest.getHeader().get("Accept").split(",")[0]; + if (httpRequest.getHeaders().get("Accept") != null) { + contentType = httpRequest.getHeaders().get("Accept").split(",")[0]; } URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java similarity index 59% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpRequest.java rename to tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index e0a3b573cd..a32398703b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -5,16 +5,16 @@ public class HttpRequest { private final RequestLine requestLine; - private final Map header; + private final HttpHeaders headers; private final Map body; - private HttpRequest(final RequestLine requestLine, final Map header, final Map body) { + private HttpRequest(final RequestLine requestLine, final HttpHeaders headers, final Map body) { this.requestLine = requestLine; - this.header = header; + this.headers = headers; this.body = body; } - public static HttpRequest of(final RequestLine requestLine, final Map header, final Map body) { + public static HttpRequest from(final RequestLine requestLine, final HttpHeaders header, final Map body) { return new HttpRequest(requestLine, header, body); } @@ -30,8 +30,9 @@ public String getVersion() { return requestLine.getVersion(); } - public Map getHeader() { - return header; + public Map getHeaders() { + // TODO: refactoring + return headers.getHeaders(); } public Map getBody() { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java similarity index 100% rename from tomcat/src/main/java/org/apache/coyote/http11/RequestLine.java rename to tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java similarity index 71% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpRequestParser.java rename to tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index bdc19d6c67..374047670b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -6,6 +6,8 @@ import java.util.HashMap; import java.util.Map; +import static org.apache.coyote.http11.HttpHeaderType.CONTENT_LENGTH; + public class HttpRequestParser { private final BufferedReader reader; @@ -17,12 +19,12 @@ public HttpRequestParser(final BufferedReader reader) { public HttpRequest parse() { try { final RequestLine requestLine = parseRequestLine(); - final Map requestHeader = parseRequestHeader(); - if (requestHeader.get("Content-Length") != null) { - final Map body = parseRequestBody(requestHeader.get("Content-Length")); - return HttpRequest.of(requestLine, requestHeader, body); + final HttpHeaders requestHeaders = parseRequestHeader(); + if (requestHeaders.getHeaderValue(CONTENT_LENGTH) != null) { + final Map body = parseRequestBody(requestHeaders.getHeaderValue(CONTENT_LENGTH)); + return HttpRequest.from(requestLine, requestHeaders, body); } - return HttpRequest.of(requestLine, requestHeader, new HashMap<>()); + return HttpRequest.from(requestLine, requestHeaders, new HashMap<>()); } catch (IOException e) { throw new RuntimeException(e); } @@ -34,15 +36,15 @@ private RequestLine parseRequestLine() throws IOException { return RequestLine.from(s[0], s[1], s[2]); } - private Map parseRequestHeader() throws IOException { + private HttpHeaders parseRequestHeader() throws IOException { // TODO: Change to MultiValueMap - final Map header = new HashMap<>(); + final HttpHeaders httpHeaders = new HttpHeaders(); String line; while (!"".equals(line = reader.readLine())) { String[] value = line.split(": "); - header.put(value[0], value[1]); + httpHeaders.setHeaderValue(value[0], value[1]); } - return header; + return httpHeaders; } private Map parseRequestBody(final String contentLengthHeader) throws IOException { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java similarity index 100% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpResponse.java rename to tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java similarity index 100% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpStatusCode.java rename to tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java From f8d24ebea77e78ddcf349d787c0dd398be8053ac Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Mon, 4 Sep 2023 20:02:28 +0900 Subject: [PATCH 02/32] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/catalina/Manager.java | 1 - .../jwp/model => org/apache/catalina}/Session.java | 2 +- .../main/java/org/apache/catalina/SessionManager.java | 1 - .../java/org/apache/coyote/http11/Http11Processor.java | 7 +++++-- .../org/apache/coyote/http11/request/HttpRequest.java | 10 ++++++---- .../apache/coyote/http11/request/HttpRequestLine.java | 10 +++++----- .../coyote/http11/request/HttpRequestParser.java | 10 ++++++---- .../apache/coyote/http11/response/HttpResponse.java | 8 +++++--- .../apache/coyote/http11/response/HttpStatusCode.java | 2 +- 9 files changed, 29 insertions(+), 22 deletions(-) rename tomcat/src/main/java/{nextstep/jwp/model => org/apache/catalina}/Session.java (93%) diff --git a/tomcat/src/main/java/org/apache/catalina/Manager.java b/tomcat/src/main/java/org/apache/catalina/Manager.java index 1153287219..1f7377cfb1 100644 --- a/tomcat/src/main/java/org/apache/catalina/Manager.java +++ b/tomcat/src/main/java/org/apache/catalina/Manager.java @@ -1,7 +1,6 @@ package org.apache.catalina; import java.io.IOException; -import nextstep.jwp.model.Session; /** * A Manager manages the pool of Sessions that are associated with a diff --git a/tomcat/src/main/java/nextstep/jwp/model/Session.java b/tomcat/src/main/java/org/apache/catalina/Session.java similarity index 93% rename from tomcat/src/main/java/nextstep/jwp/model/Session.java rename to tomcat/src/main/java/org/apache/catalina/Session.java index 2ac8ceb637..396dde2b9e 100644 --- a/tomcat/src/main/java/nextstep/jwp/model/Session.java +++ b/tomcat/src/main/java/org/apache/catalina/Session.java @@ -1,4 +1,4 @@ -package nextstep.jwp.model; +package org.apache.catalina; import java.util.HashMap; import java.util.Map; diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/SessionManager.java index 6a5e32e6b1..cc2eb6b38c 100644 --- a/tomcat/src/main/java/org/apache/catalina/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/SessionManager.java @@ -2,7 +2,6 @@ import java.util.HashMap; import java.util.Map; -import nextstep.jwp.model.Session; public class SessionManager implements Manager { 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 639a065a44..12db92512d 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -2,10 +2,13 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.exception.UncheckedServletException; -import nextstep.jwp.model.Session; +import org.apache.catalina.Session; import nextstep.jwp.model.User; import org.apache.catalina.SessionManager; import org.apache.coyote.Processor; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestParser; +import org.apache.coyote.http11.response.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +23,7 @@ import java.util.UUID; import static org.apache.coyote.http11.HttpHeaderType.*; -import static org.apache.coyote.http11.HttpStatusCode.*; +import static org.apache.coyote.http11.response.HttpStatusCode.*; public class Http11Processor implements Runnable, Processor { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index a32398703b..2056599887 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,20 +1,22 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.request; + +import org.apache.coyote.http11.HttpHeaders; import java.util.Map; public class HttpRequest { - private final RequestLine requestLine; + private final HttpRequestLine requestLine; private final HttpHeaders headers; private final Map body; - private HttpRequest(final RequestLine requestLine, final HttpHeaders headers, final Map body) { + private HttpRequest(final HttpRequestLine requestLine, final HttpHeaders headers, final Map body) { this.requestLine = requestLine; this.headers = headers; this.body = body; } - public static HttpRequest from(final RequestLine requestLine, final HttpHeaders header, final Map body) { + public static HttpRequest from(final HttpRequestLine requestLine, final HttpHeaders header, final Map body) { return new HttpRequest(requestLine, header, body); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java index a27f61c3b7..0234515e55 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java @@ -1,19 +1,19 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.request; -public class RequestLine { +public class HttpRequestLine { private final String method; private final String target; private final String version; - private RequestLine(final String method, final String target, final String version) { + private HttpRequestLine(final String method, final String target, final String version) { this.method = method; this.target = target; this.version = version; } - public static RequestLine from(final String method, final String target, final String version) { - return new RequestLine(method, target, version); + public static HttpRequestLine from(final String method, final String target, final String version) { + return new HttpRequestLine(method, target, version); } public String getMethod() { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index 374047670b..e2c0360c87 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -1,4 +1,6 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.request; + +import org.apache.coyote.http11.HttpHeaders; import java.io.BufferedReader; import java.io.IOException; @@ -18,7 +20,7 @@ public HttpRequestParser(final BufferedReader reader) { public HttpRequest parse() { try { - final RequestLine requestLine = parseRequestLine(); + final HttpRequestLine requestLine = parseRequestLine(); final HttpHeaders requestHeaders = parseRequestHeader(); if (requestHeaders.getHeaderValue(CONTENT_LENGTH) != null) { final Map body = parseRequestBody(requestHeaders.getHeaderValue(CONTENT_LENGTH)); @@ -30,10 +32,10 @@ public HttpRequest parse() { } } - private RequestLine parseRequestLine() throws IOException { + private HttpRequestLine parseRequestLine() throws IOException { final String line = reader.readLine(); String[] s = line.split(" "); - return RequestLine.from(s[0], s[1], s[2]); + return HttpRequestLine.from(s[0], s[1], s[2]); } private HttpHeaders parseRequestHeader() throws IOException { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index ae1c03f091..b6d1c668e1 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -1,14 +1,16 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.response; + +import org.apache.coyote.http11.HttpHeaderType; +import org.apache.coyote.http11.HttpHeaders; import java.util.Map; -import static org.apache.coyote.http11.HttpStatusCode.NOT_FOUND; +import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; public class HttpResponse { private HttpStatusCode statusCode; private final HttpHeaders headers; -// private final Map header; private String body; private HttpResponse(final HttpStatusCode statusCode, final HttpHeaders headers, final String body) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java index 634bf44e1e..e55a988cf6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.response; public enum HttpStatusCode { From fe717dd03f09198b307e54068a1963306606b183 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Mon, 4 Sep 2023 20:37:28 +0900 Subject: [PATCH 03/32] =?UTF-8?q?refactor:=20HttpHeaders=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=EC=97=90=20HttpCookie=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 | 8 +++--- .../org/apache/coyote/http11/HttpCookie.java | 4 +++ .../apache/coyote/http11/HttpHeaderType.java | 1 + .../org/apache/coyote/http11/HttpHeaders.java | 25 +++++++++++++++---- .../coyote/http11/request/HttpRequest.java | 5 ++-- .../http11/request/HttpRequestParser.java | 9 +++++-- .../coyote/http11/response/HttpResponse.java | 2 +- 7 files changed, 39 insertions(+), 15 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 12db92512d..18f2649fce 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -49,7 +49,6 @@ public void process(final Socket connection) { final HttpRequestParser httpRequestParser = new HttpRequestParser(reader); final HttpRequest httpRequest = httpRequestParser.parse(); - final HttpCookie httpCookie = HttpCookie.of(httpRequest.getHeaders().get("Cookie")); // TODO: generate RequestHandler final HttpResponse httpResponse = handleRequest(httpRequest); @@ -106,7 +105,7 @@ private HttpResponse handleRegisterRequest(final HttpRequest httpRequest) throws } private HttpResponse handleLoginRequest(final HttpRequest httpRequest) throws IOException { - final HttpCookie httpCookie = HttpCookie.of(httpRequest.getHeaders().get("Cookie")); + final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); String sessionId = httpCookie.getCookie("JSESSIONID"); if (httpRequest.getMethod().equals("GET")) { @@ -165,8 +164,9 @@ private HttpResponse handleResourceRequest(final HttpRequest httpRequest, final final HttpResponse httpResponse = HttpResponse.init(); String contentType = "text/html;charset=utf-8"; - if (httpRequest.getHeaders().get("Accept") != null) { - contentType = httpRequest.getHeaders().get("Accept").split(",")[0]; + final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); + if (acceptHeader != null) { + contentType = acceptHeader.split(",")[0]; } URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java index 6475ac5195..ffc7c85e39 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java @@ -15,6 +15,10 @@ public static HttpCookie of(final String cookies) { return new HttpCookie(parse(cookies)); } + public static HttpCookie empty() { + return new HttpCookie(new HashMap<>()); + } + private static Map parse(final String cookies) { if (cookies == null) { return new HashMap<>(); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderType.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderType.java index ec017785a9..aa9033ec6f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderType.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderType.java @@ -5,6 +5,7 @@ public enum HttpHeaderType { CONTENT_TYPE("Content-Type"), CONTENT_LENGTH("Content-Length"), LOCATION("Location"), + COOKIE("Cookie"), SET_COOKIE("Set-Cookie"), ACCEPT("Accept"); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java index e5e7570c3f..db6a936057 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java @@ -3,14 +3,21 @@ import java.util.HashMap; import java.util.Map; -import static org.apache.coyote.http11.HttpHeaderType.CONTENT_LENGTH; - public class HttpHeaders { - private final Map headers = new HashMap<>(); + private final Map headers; + private HttpCookie cookie = HttpCookie.empty(); + + private HttpHeaders(final Map headers) { + this.headers = headers; + } + + public static HttpHeaders empty() { + return new HttpHeaders(new HashMap<>()); + } - public String getContentLength() { - return headers.get(CONTENT_LENGTH.getName()); + public static HttpHeaders of(final Map headers) { + return new HttpHeaders(headers); } public String getHeaderValue(final HttpHeaderType type) { @@ -25,6 +32,14 @@ public void setHeaderValue(final String type, final String value) { headers.put(type, value); } + public HttpCookie getCookie() { + return cookie; + } + + public void setCookie(final HttpCookie httpCookie) { + this.cookie = httpCookie; + } + public Map getHeaders() { return headers; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 2056599887..748b87ba83 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -32,9 +32,8 @@ public String getVersion() { return requestLine.getVersion(); } - public Map getHeaders() { - // TODO: refactoring - return headers.getHeaders(); + public HttpHeaders getHeaders() { + return headers; } public Map getBody() { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index e2c0360c87..5f7c8af271 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -1,5 +1,6 @@ package org.apache.coyote.http11.request; +import org.apache.coyote.http11.HttpCookie; import org.apache.coyote.http11.HttpHeaders; import java.io.BufferedReader; @@ -9,6 +10,7 @@ import java.util.Map; import static org.apache.coyote.http11.HttpHeaderType.CONTENT_LENGTH; +import static org.apache.coyote.http11.HttpHeaderType.COOKIE; public class HttpRequestParser { @@ -40,12 +42,15 @@ private HttpRequestLine parseRequestLine() throws IOException { private HttpHeaders parseRequestHeader() throws IOException { // TODO: Change to MultiValueMap - final HttpHeaders httpHeaders = new HttpHeaders(); + final Map headers = new HashMap<>(); String line; while (!"".equals(line = reader.readLine())) { String[] value = line.split(": "); - httpHeaders.setHeaderValue(value[0], value[1]); + headers.put(value[0], value[1]); } + final HttpHeaders httpHeaders = HttpHeaders.of(headers); + final HttpCookie httpCookie = HttpCookie.of(headers.get(COOKIE.getName())); + httpHeaders.setCookie(httpCookie); return httpHeaders; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index b6d1c668e1..5188fb17b0 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -20,7 +20,7 @@ private HttpResponse(final HttpStatusCode statusCode, final HttpHeaders headers, } public static HttpResponse init() { - return new HttpResponse(NOT_FOUND, new HttpHeaders(), ""); + return new HttpResponse(NOT_FOUND, HttpHeaders.empty(), ""); } public void addHeader(final String key, final String value) { From 293f988eac5214f8b8fa8ad62523186ce58d7403 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Mon, 4 Sep 2023 21:51:42 +0900 Subject: [PATCH 04/32] =?UTF-8?q?refactor:=20RequestHandler=20=EB=B0=8F=20?= =?UTF-8?q?Controller=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/controller/LoginController.java | 18 ++++++++ .../jwp/controller/RegisterController.java | 18 ++++++++ .../jwp/controller/RootController.java | 18 ++++++++ .../java/org/apache/coyote/Controller.java | 42 +++++++++++++++++++ .../org/apache/coyote/RequestHandler.java | 26 ++++++++++++ .../org/apache/coyote/ResourceController.java | 17 ++++++++ .../apache/coyote/http11/Http11Processor.java | 25 ++++++++--- 7 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 tomcat/src/main/java/nextstep/jwp/controller/LoginController.java create mode 100644 tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java create mode 100644 tomcat/src/main/java/nextstep/jwp/controller/RootController.java create mode 100644 tomcat/src/main/java/org/apache/coyote/Controller.java create mode 100644 tomcat/src/main/java/org/apache/coyote/RequestHandler.java create mode 100644 tomcat/src/main/java/org/apache/coyote/ResourceController.java diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java new file mode 100644 index 0000000000..60fd565f15 --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -0,0 +1,18 @@ +package nextstep.jwp.controller; + +import org.apache.coyote.Controller; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public class LoginController extends Controller { + + @Override + public HttpResponse doGet(final HttpRequest httpRequest) { + return null; + } + + @Override + public HttpResponse doPost(final HttpRequest httpRequest) { + return null; + } +} diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java new file mode 100644 index 0000000000..f2219d4f01 --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -0,0 +1,18 @@ +package nextstep.jwp.controller; + +import org.apache.coyote.Controller; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public class RegisterController extends Controller { + + @Override + public HttpResponse doGet(final HttpRequest httpRequest) { + return null; + } + + @Override + public HttpResponse doPost(final HttpRequest httpRequest) { + return null; + } +} diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java new file mode 100644 index 0000000000..f069c7dd6d --- /dev/null +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -0,0 +1,18 @@ +package nextstep.jwp.controller; + +import org.apache.coyote.Controller; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public class RootController extends Controller { + + @Override + public HttpResponse doGet(final HttpRequest httpRequest) { + return null; + } + + @Override + public HttpResponse doPost(final HttpRequest httpRequest) { + return null; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/Controller.java b/tomcat/src/main/java/org/apache/coyote/Controller.java new file mode 100644 index 0000000000..bdbeba0ea8 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/Controller.java @@ -0,0 +1,42 @@ +package org.apache.coyote; + +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +import java.util.Set; + +public abstract class Controller { + + public HttpResponse handleRequest(final HttpRequest httpRequest) { + final String method = httpRequest.getMethod(); + if (checkMethod(method)) { + return handle(httpRequest); + } + return HttpResponse.init(); + } + + private boolean checkMethod(final String method) { + final Set methods = Set.of("GET", "POST"); + return methods.contains(method); + } + + private HttpResponse handle(final HttpRequest httpRequest) { + final String method = httpRequest.getMethod(); + if ("GET".equals(method)) { + return doGet(httpRequest); + } + if ("POST".equals(method)) { + return doPost(httpRequest); + } + if ("PATCH".equals(method)) { + + } + if ("DELETE".equals(method)) { + + } + return HttpResponse.init(); + } + + public abstract HttpResponse doGet(final HttpRequest httpRequest); + public abstract HttpResponse doPost(final HttpRequest httpRequest); +} diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java new file mode 100644 index 0000000000..f2c7fc1c03 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java @@ -0,0 +1,26 @@ +package org.apache.coyote; + +import org.apache.coyote.http11.request.HttpRequest; + +import java.util.Map; + +public class RequestHandler { + + private final Map controllers; + + public RequestHandler(final Map controllers) { + this.controllers = controllers; + } + + public boolean canHandle(final String target) { + return controllers.containsKey(target); + } + + public Controller getHandler(final HttpRequest httpRequest) { + final String target = httpRequest.getTarget(); + if (controllers.get(target) != null) { + return controllers.get(target); + } + return new ResourceController(); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/ResourceController.java b/tomcat/src/main/java/org/apache/coyote/ResourceController.java new file mode 100644 index 0000000000..aa6f4d12d2 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/ResourceController.java @@ -0,0 +1,17 @@ +package org.apache.coyote; + +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public class ResourceController extends Controller { + + @Override + public HttpResponse doGet(final HttpRequest httpRequest) { + return null; + } + + @Override + public HttpResponse doPost(final HttpRequest httpRequest) { + return null; + } +} 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 18f2649fce..589c16dbe8 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -2,10 +2,15 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.exception.UncheckedServletException; -import org.apache.catalina.Session; import nextstep.jwp.model.User; +import org.apache.catalina.Session; import org.apache.catalina.SessionManager; +import org.apache.coyote.Controller; import org.apache.coyote.Processor; +import org.apache.coyote.RequestHandler; +import nextstep.jwp.controller.LoginController; +import nextstep.jwp.controller.RegisterController; +import nextstep.jwp.controller.RootController; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.request.HttpRequestParser; import org.apache.coyote.http11.response.HttpResponse; @@ -19,6 +24,7 @@ import java.net.Socket; import java.net.URL; import java.nio.file.Files; +import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -50,7 +56,14 @@ public void process(final Socket connection) { final HttpRequestParser httpRequestParser = new HttpRequestParser(reader); final HttpRequest httpRequest = httpRequestParser.parse(); - // TODO: generate RequestHandler + final RequestHandler requestHandler = new RequestHandler(Map.of( + "/", new RootController(), + "/login", new LoginController(), + "/register", new RegisterController() + )); + + final Controller handler = requestHandler.getHandler(httpRequest); +// final HttpResponse httpResponse = handler.handleRequest(httpRequest); final HttpResponse httpResponse = handleRequest(httpRequest); outputStream.write(httpResponse.stringify().getBytes()); outputStream.flush(); @@ -105,12 +118,10 @@ private HttpResponse handleRegisterRequest(final HttpRequest httpRequest) throws } private HttpResponse handleLoginRequest(final HttpRequest httpRequest) throws IOException { - final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); - String sessionId = httpCookie.getCookie("JSESSIONID"); - if (httpRequest.getMethod().equals("GET")) { final HttpResponse httpResponse = HttpResponse.init(); - + final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); + String sessionId = httpCookie.getCookie("JSESSIONID"); final Session session = sessionManager.findSession(sessionId); if (session != null) { // already login user @@ -125,6 +136,8 @@ private HttpResponse handleLoginRequest(final HttpRequest httpRequest) throws IO if (httpRequest.getMethod().equals("POST")) { final HttpResponse httpResponse = HttpResponse.init(); + final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); + String sessionId = httpCookie.getCookie("JSESSIONID"); Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); if (user.isEmpty() || !user.get().checkPassword(httpRequest.getBody().get("password"))) { From fbbd644623b98e568ca20cd11455b432ee33bec5 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Wed, 6 Sep 2023 01:15:00 +0900 Subject: [PATCH 05/32] =?UTF-8?q?test:=20Http=20=ED=99=9C=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/cachecontrol/CacheWebConfig.java | 8 ++++++++ .../example/etag/EtagFilterConfiguration.java | 17 +++++++++++++---- .../example/version/CacheBustingWebConfig.java | 6 +++++- study/src/main/resources/application.yml | 3 +++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java index 305b1f1e1e..9cbf1595aa 100644 --- a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java +++ b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java @@ -1,13 +1,21 @@ package cache.com.example.cachecontrol; import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.mvc.WebContentInterceptor; @Configuration public class CacheWebConfig implements WebMvcConfigurer { @Override public void addInterceptors(final InterceptorRegistry registry) { + final WebContentInterceptor interceptor = new WebContentInterceptor(); + final CacheControl cacheControl = CacheControl + .noCache() + .cachePrivate(); + interceptor.addCacheMapping(cacheControl, "/**"); + registry.addInterceptor(interceptor); } } diff --git a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java index 41ef7a3d9a..0ad869edd0 100644 --- a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java +++ b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java @@ -1,12 +1,21 @@ package cache.com.example.etag; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.ShallowEtagHeaderFilter; + +import static cache.com.example.version.CacheBustingWebConfig.PREFIX_STATIC_RESOURCES; @Configuration public class EtagFilterConfiguration { -// @Bean -// public FilterRegistrationBean shallowEtagHeaderFilter() { -// return null; -// } + @Bean + public FilterRegistrationBean shallowEtagHeaderFilter() { + + FilterRegistrationBean filterFilterRegistrationBean + = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); + filterFilterRegistrationBean.addUrlPatterns("/etag", PREFIX_STATIC_RESOURCES + "/*"); + return filterFilterRegistrationBean; + } } diff --git a/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java b/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java index 6da6d2c795..5a422e5b2e 100644 --- a/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java +++ b/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java @@ -2,9 +2,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import java.time.Duration; + @Configuration public class CacheBustingWebConfig implements WebMvcConfigurer { @@ -20,6 +23,7 @@ public CacheBustingWebConfig(ResourceVersion version) { @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**") - .addResourceLocations("classpath:/static/"); + .addResourceLocations("classpath:/static/") + .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic()); } } diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml index 4e8655a962..522113ace8 100644 --- a/study/src/main/resources/application.yml +++ b/study/src/main/resources/application.yml @@ -2,6 +2,9 @@ handlebars: suffix: .html server: + compression: + enabled: true + min-response-size: 10 tomcat: accept-count: 1 max-connections: 1 From 2bb6e1fe8f03d6b45ebc4cd98eba56c82405bdcd Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Wed, 6 Sep 2023 02:20:58 +0900 Subject: [PATCH 06/32] =?UTF-8?q?refactor:=20Controller=20=ED=95=B8?= =?UTF-8?q?=EB=93=A4=EB=A7=81=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/controller/LoginController.java | 9 +++-- .../jwp/controller/RegisterController.java | 9 +++-- .../jwp/controller/RootController.java | 9 +++-- .../java/org/apache/coyote/Controller.java | 36 ++++++------------- .../org/apache/coyote/RequestHandler.java | 26 -------------- .../org/apache/coyote/RequestMapping.java | 23 ++++++++++++ .../org/apache/coyote/ResourceController.java | 9 +++-- .../apache/coyote/http11/Http11Processor.java | 28 ++++++++------- 8 files changed, 77 insertions(+), 72 deletions(-) delete mode 100644 tomcat/src/main/java/org/apache/coyote/RequestHandler.java create mode 100644 tomcat/src/main/java/org/apache/coyote/RequestMapping.java diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 60fd565f15..7677628a2f 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -7,12 +7,17 @@ public class LoginController extends Controller { @Override - public HttpResponse doGet(final HttpRequest httpRequest) { + public boolean canHandle(final HttpRequest target) { + return false; + } + + @Override + public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } @Override - public HttpResponse doPost(final HttpRequest httpRequest) { + public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } } diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java index f2219d4f01..ce05cc71dd 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -7,12 +7,17 @@ public class RegisterController extends Controller { @Override - public HttpResponse doGet(final HttpRequest httpRequest) { + public boolean canHandle(final HttpRequest target) { + return false; + } + + @Override + public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } @Override - public HttpResponse doPost(final HttpRequest httpRequest) { + public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } } diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java index f069c7dd6d..0514480161 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -7,12 +7,17 @@ public class RootController extends Controller { @Override - public HttpResponse doGet(final HttpRequest httpRequest) { + public boolean canHandle(final HttpRequest target) { + return false; + } + + @Override + public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } @Override - public HttpResponse doPost(final HttpRequest httpRequest) { + public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } } diff --git a/tomcat/src/main/java/org/apache/coyote/Controller.java b/tomcat/src/main/java/org/apache/coyote/Controller.java index bdbeba0ea8..af7b6e2549 100644 --- a/tomcat/src/main/java/org/apache/coyote/Controller.java +++ b/tomcat/src/main/java/org/apache/coyote/Controller.java @@ -3,40 +3,24 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; -import java.util.Set; - public abstract class Controller { - public HttpResponse handleRequest(final HttpRequest httpRequest) { - final String method = httpRequest.getMethod(); - if (checkMethod(method)) { - return handle(httpRequest); + public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) { + if (!canHandle(httpRequest)) { + // TODO: exception - there is any controller to handle } - return HttpResponse.init(); - } - - private boolean checkMethod(final String method) { - final Set methods = Set.of("GET", "POST"); - return methods.contains(method); - } - - private HttpResponse handle(final HttpRequest httpRequest) { final String method = httpRequest.getMethod(); if ("GET".equals(method)) { - return doGet(httpRequest); + doGet(httpRequest, httpResponse); } if ("POST".equals(method)) { - return doPost(httpRequest); + doPost(httpRequest, httpResponse); } - if ("PATCH".equals(method)) { - - } - if ("DELETE".equals(method)) { - - } - return HttpResponse.init(); + // TODO: exception - invalid http method } - public abstract HttpResponse doGet(final HttpRequest httpRequest); - public abstract HttpResponse doPost(final HttpRequest httpRequest); + public abstract boolean canHandle(final HttpRequest target); + + public abstract HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse); + public abstract HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse); } diff --git a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/RequestHandler.java deleted file mode 100644 index f2c7fc1c03..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/RequestHandler.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.apache.coyote; - -import org.apache.coyote.http11.request.HttpRequest; - -import java.util.Map; - -public class RequestHandler { - - private final Map controllers; - - public RequestHandler(final Map controllers) { - this.controllers = controllers; - } - - public boolean canHandle(final String target) { - return controllers.containsKey(target); - } - - public Controller getHandler(final HttpRequest httpRequest) { - final String target = httpRequest.getTarget(); - if (controllers.get(target) != null) { - return controllers.get(target); - } - return new ResourceController(); - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java new file mode 100644 index 0000000000..293bbdba42 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java @@ -0,0 +1,23 @@ +package org.apache.coyote; + +import org.apache.coyote.http11.request.HttpRequest; + +import java.util.List; + +public class RequestMapping { + + private final List controllers; + + public RequestMapping(final List controllers) { + this.controllers = controllers; + } + + public Controller getController(final HttpRequest httpRequest) { + for (final Controller controller : controllers) { + if (controller.canHandle(httpRequest)) { + return controller; + } + } + return null; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/ResourceController.java b/tomcat/src/main/java/org/apache/coyote/ResourceController.java index aa6f4d12d2..ebe0f82097 100644 --- a/tomcat/src/main/java/org/apache/coyote/ResourceController.java +++ b/tomcat/src/main/java/org/apache/coyote/ResourceController.java @@ -6,12 +6,17 @@ public class ResourceController extends Controller { @Override - public HttpResponse doGet(final HttpRequest httpRequest) { + public boolean canHandle(final HttpRequest target) { + return true; + } + + @Override + public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } @Override - public HttpResponse doPost(final HttpRequest httpRequest) { + public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { return null; } } 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 589c16dbe8..e709444c10 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,16 +1,16 @@ package org.apache.coyote.http11; +import nextstep.jwp.controller.LoginController; +import nextstep.jwp.controller.RegisterController; +import nextstep.jwp.controller.RootController; import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.exception.UncheckedServletException; import nextstep.jwp.model.User; import org.apache.catalina.Session; import org.apache.catalina.SessionManager; -import org.apache.coyote.Controller; import org.apache.coyote.Processor; -import org.apache.coyote.RequestHandler; -import nextstep.jwp.controller.LoginController; -import nextstep.jwp.controller.RegisterController; -import nextstep.jwp.controller.RootController; +import org.apache.coyote.RequestMapping; +import org.apache.coyote.ResourceController; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.request.HttpRequestParser; import org.apache.coyote.http11.response.HttpResponse; @@ -24,7 +24,7 @@ import java.net.Socket; import java.net.URL; import java.nio.file.Files; -import java.util.Map; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -56,14 +56,18 @@ public void process(final Socket connection) { final HttpRequestParser httpRequestParser = new HttpRequestParser(reader); final HttpRequest httpRequest = httpRequestParser.parse(); - final RequestHandler requestHandler = new RequestHandler(Map.of( - "/", new RootController(), - "/login", new LoginController(), - "/register", new RegisterController() + final RequestMapping requestMapping = new RequestMapping(List.of( + new RootController(), + new LoginController(), + new RegisterController(), + new ResourceController() )); - final Controller handler = requestHandler.getHandler(httpRequest); -// final HttpResponse httpResponse = handler.handleRequest(httpRequest); + /* handler */ +// final Controller controller = requestMapping.getController(httpRequest); +// final HttpResponse httpResponse = HttpResponse.init(); +// controller.service(httpRequest, httpResponse); + final HttpResponse httpResponse = handleRequest(httpRequest); outputStream.write(httpResponse.stringify().getBytes()); outputStream.flush(); From 9aec72c837daab8dd028f33f4e7aa2ee595abba1 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Wed, 6 Sep 2023 03:04:35 +0900 Subject: [PATCH 07/32] =?UTF-8?q?refactor:=20Controller=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=B3=84=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/controller/LoginController.java | 91 ++++++++++++++++++- .../jwp/controller/RegisterController.java | 59 +++++++++++- .../jwp/controller/RootController.java | 24 ++++- .../java/org/apache/coyote/Controller.java | 10 +- .../org/apache/coyote/ResourceController.java | 40 ++++++-- .../apache/coyote/http11/Http11Processor.java | 12 +-- 6 files changed, 205 insertions(+), 31 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 7677628a2f..016eddea19 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -1,23 +1,104 @@ package nextstep.jwp.controller; +import nextstep.jwp.db.InMemoryUserRepository; +import nextstep.jwp.model.User; +import org.apache.catalina.Session; import org.apache.coyote.Controller; +import org.apache.coyote.http11.HttpCookie; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.util.*; + +import static org.apache.coyote.http11.Http11Processor.sessionManager; +import static org.apache.coyote.http11.HttpHeaderType.*; +import static org.apache.coyote.http11.response.HttpStatusCode.*; + public class LoginController extends Controller { @Override - public boolean canHandle(final HttpRequest target) { + public boolean canHandle(final HttpRequest httpRequest) { + final Map> requestType = new HashMap<>(Map.of( + "/login", new HashSet<>(Set.of("GET", "POST")) + )); + + if (requestType.containsKey(httpRequest.getTarget())) { + final Set methodType = requestType.get(httpRequest.getTarget()); + return methodType.contains(httpRequest.getMethod()); + } return false; } @Override - public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); + String sessionId = httpCookie.getCookie("JSESSIONID"); + final Session session = sessionManager.findSession(sessionId); + if (session != null) { // already login user + httpResponse.setStatusCode(FOUND); + httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(LOCATION, "/index.html"); + } else { // not login user + final String resourceUrl = "login.html"; + String contentType = "text/html;charset=utf-8"; + + final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); + if (acceptHeader != null) { + contentType = acceptHeader.split(",")[0]; + } + + URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); + if (resource != null) { + httpResponse.setStatusCode(OK); + } else { + resource = getClass().getClassLoader().getResource("static/" + "404.html"); + httpResponse.setStatusCode(NOT_FOUND); + contentType = "text/html;charset=utf-8"; + } + + final String responseBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + httpResponse.addHeader(CONTENT_TYPE, contentType); + httpResponse.setBody(responseBody); + } } @Override - public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { + final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); + String sessionId = httpCookie.getCookie("JSESSIONID"); + + Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); + if (user.isEmpty() || !user.get().checkPassword(httpRequest.getBody().get("password"))) { + // invalid user + httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(LOCATION, "/401.html"); + httpResponse.setStatusCode(FOUND); + return; + } + + // valid user +// log.info("user: {}", user.get()); + + if (sessionId != null) { // if already have session + httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(LOCATION, "/index.html"); + httpResponse.setStatusCode(FOUND); + return; + } + + // if no session + Session session = new Session(String.valueOf(UUID.randomUUID())); + session.setAttribute("user", user); + sessionManager.add(session); + sessionId = session.getId(); + + httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(LOCATION, "/index.html"); + httpResponse.addHeader(SET_COOKIE, "JSESSIONID=" + sessionId); + httpResponse.setStatusCode(FOUND); } } diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java index ce05cc71dd..c8a55f8971 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -1,23 +1,72 @@ package nextstep.jwp.controller; +import nextstep.jwp.db.InMemoryUserRepository; +import nextstep.jwp.model.User; import org.apache.coyote.Controller; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static org.apache.coyote.http11.HttpHeaderType.*; +import static org.apache.coyote.http11.response.HttpStatusCode.*; + public class RegisterController extends Controller { @Override - public boolean canHandle(final HttpRequest target) { + public boolean canHandle(final HttpRequest httpRequest) { + final Map> requestType = new HashMap<>(Map.of( + "/register", new HashSet<>(Set.of("GET", "POST")) + )); + + if (requestType.containsKey(httpRequest.getTarget())) { + final Set methodType = requestType.get(httpRequest.getTarget()); + return methodType.contains(httpRequest.getMethod()); + } return false; } @Override - public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + final String resourceUrl = "register.html"; + String contentType = "text/html;charset=utf-8"; + + final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); + if (acceptHeader != null) { + contentType = acceptHeader.split(",")[0]; + } + + URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); + if (resource != null) { + httpResponse.setStatusCode(OK); + } else { + resource = getClass().getClassLoader().getResource("static/" + "404.html"); + httpResponse.setStatusCode(NOT_FOUND); + contentType = "text/html;charset=utf-8"; + } + + final String responseBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + httpResponse.addHeader(CONTENT_TYPE, contentType); + httpResponse.setBody(responseBody); } @Override - public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { + final User newUser = new User( + httpRequest.getBody().get("account"), + httpRequest.getBody().get("password"), + httpRequest.getBody().get("email") + ); + InMemoryUserRepository.save(newUser); + httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(LOCATION, "/index.html"); + httpResponse.setStatusCode(FOUND); } } diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java index 0514480161..20440b3c0a 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -4,20 +4,34 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; +import java.util.*; + +import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.response.HttpStatusCode.OK; + public class RootController extends Controller { @Override - public boolean canHandle(final HttpRequest target) { + public boolean canHandle(final HttpRequest httpRequest) { + final Map> requestType = new HashMap<>(Map.of( + "/", new HashSet<>(Set.of("GET")) + )); + + if (requestType.containsKey(httpRequest.getTarget())) { + final Set methodType = requestType.get(httpRequest.getTarget()); + return methodType.contains(httpRequest.getMethod()); + } return false; } @Override - public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { + httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.setStatusCode(OK); + httpResponse.setBody("Hello world!"); } @Override - public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { } } diff --git a/tomcat/src/main/java/org/apache/coyote/Controller.java b/tomcat/src/main/java/org/apache/coyote/Controller.java index af7b6e2549..207f60a611 100644 --- a/tomcat/src/main/java/org/apache/coyote/Controller.java +++ b/tomcat/src/main/java/org/apache/coyote/Controller.java @@ -3,9 +3,11 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; +import java.io.IOException; + public abstract class Controller { - public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) { + public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { if (!canHandle(httpRequest)) { // TODO: exception - there is any controller to handle } @@ -19,8 +21,8 @@ public void service(final HttpRequest httpRequest, final HttpResponse httpRespon // TODO: exception - invalid http method } - public abstract boolean canHandle(final HttpRequest target); + public abstract boolean canHandle(final HttpRequest httpRequest); - public abstract HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse); - public abstract HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse); + public abstract void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException; + public abstract void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException; } diff --git a/tomcat/src/main/java/org/apache/coyote/ResourceController.java b/tomcat/src/main/java/org/apache/coyote/ResourceController.java index ebe0f82097..63766763cc 100644 --- a/tomcat/src/main/java/org/apache/coyote/ResourceController.java +++ b/tomcat/src/main/java/org/apache/coyote/ResourceController.java @@ -3,20 +3,48 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; + +import static org.apache.coyote.http11.HttpHeaderType.ACCEPT; +import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; +import static org.apache.coyote.http11.response.HttpStatusCode.OK; + public class ResourceController extends Controller { @Override - public boolean canHandle(final HttpRequest target) { - return true; + public boolean canHandle(final HttpRequest httpRequest) { + return "GET".equals(httpRequest.getMethod()); } @Override - public HttpResponse doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + final String resourceUrl = httpRequest.getTarget(); + String contentType = "text/html;charset=utf-8"; + + final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); + if (acceptHeader != null) { + contentType = acceptHeader.split(",")[0]; + } + + URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); + if (resource != null) { + httpResponse.setStatusCode(OK); + } else { + resource = getClass().getClassLoader().getResource("static/" + "404.html"); + httpResponse.setStatusCode(NOT_FOUND); + contentType = "text/html;charset=utf-8"; + } + + final String responseBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + httpResponse.addHeader(CONTENT_TYPE, contentType); + httpResponse.setBody(responseBody); } @Override - public HttpResponse doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { - return null; + public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { } } 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 e709444c10..714c47860f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -8,6 +8,7 @@ import nextstep.jwp.model.User; import org.apache.catalina.Session; import org.apache.catalina.SessionManager; +import org.apache.coyote.Controller; import org.apache.coyote.Processor; import org.apache.coyote.RequestMapping; import org.apache.coyote.ResourceController; @@ -34,7 +35,7 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); - private static final SessionManager sessionManager = new SessionManager(); + public static final SessionManager sessionManager = new SessionManager(); private final Socket connection; public Http11Processor(final Socket connection) { @@ -63,12 +64,11 @@ public void process(final Socket connection) { new ResourceController() )); - /* handler */ -// final Controller controller = requestMapping.getController(httpRequest); -// final HttpResponse httpResponse = HttpResponse.init(); -// controller.service(httpRequest, httpResponse); + final Controller controller = requestMapping.getController(httpRequest); + final HttpResponse httpResponse = HttpResponse.init(); + controller.service(httpRequest, httpResponse); - final HttpResponse httpResponse = handleRequest(httpRequest); +// final HttpResponse httpResponse = handleRequest(httpRequest); outputStream.write(httpResponse.stringify().getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { From f0bf5bba42786e09430c808eae7841d17cd3ca86 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Wed, 6 Sep 2023 03:05:20 +0900 Subject: [PATCH 08/32] =?UTF-8?q?refactor:=20Processor=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=EC=9D=98=20handleRequest=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 137 ------------------ 1 file changed, 137 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 714c47860f..af0e5c4d3b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -3,10 +3,7 @@ import nextstep.jwp.controller.LoginController; import nextstep.jwp.controller.RegisterController; import nextstep.jwp.controller.RootController; -import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.exception.UncheckedServletException; -import nextstep.jwp.model.User; -import org.apache.catalina.Session; import org.apache.catalina.SessionManager; import org.apache.coyote.Controller; import org.apache.coyote.Processor; @@ -19,18 +16,10 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; -import java.net.URL; -import java.nio.file.Files; import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import static org.apache.coyote.http11.HttpHeaderType.*; -import static org.apache.coyote.http11.response.HttpStatusCode.*; public class Http11Processor implements Runnable, Processor { @@ -68,136 +57,10 @@ public void process(final Socket connection) { final HttpResponse httpResponse = HttpResponse.init(); controller.service(httpRequest, httpResponse); -// final HttpResponse httpResponse = handleRequest(httpRequest); outputStream.write(httpResponse.stringify().getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { log.error(e.getMessage(), e); } } - - private HttpResponse handleRequest(final HttpRequest httpRequest) throws IOException { - if (httpRequest.getTarget().equals("/")) { - return handleRootRequest(); - } - - if (httpRequest.getTarget().equals("/login")) { - return handleLoginRequest(httpRequest); - } - - if (httpRequest.getTarget().equals("/register")) { - return handleRegisterRequest(httpRequest); - } - - return handleResourceRequest(httpRequest, httpRequest.getTarget()); - } - - private HttpResponse handleRootRequest() { - final HttpResponse httpResponse = HttpResponse.init(); - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); - httpResponse.setStatusCode(OK); - httpResponse.setBody("Hello world!"); - return httpResponse; - } - - private HttpResponse handleRegisterRequest(final HttpRequest httpRequest) throws IOException { - if (httpRequest.getMethod().equals("GET")) { - return handleResourceRequest(httpRequest, "register.html"); - } - - if (httpRequest.getMethod().equals("POST")) { - final HttpResponse httpResponse = HttpResponse.init(); - final User newUser = new User( - httpRequest.getBody().get("account"), - httpRequest.getBody().get("password"), - httpRequest.getBody().get("email") - ); - InMemoryUserRepository.save(newUser); - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); - httpResponse.addHeader(LOCATION, "/index.html"); - httpResponse.setStatusCode(FOUND); - return httpResponse; - } - return handleResourceRequest(httpRequest, "404.html"); // Method Not Allowed - } - - private HttpResponse handleLoginRequest(final HttpRequest httpRequest) throws IOException { - if (httpRequest.getMethod().equals("GET")) { - final HttpResponse httpResponse = HttpResponse.init(); - final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); - String sessionId = httpCookie.getCookie("JSESSIONID"); - final Session session = sessionManager.findSession(sessionId); - if (session != null) { - // already login user - httpResponse.setStatusCode(FOUND); - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); - httpResponse.addHeader(LOCATION, "/index.html"); - return httpResponse; - } - // not login user - return handleResourceRequest(httpRequest, "login.html"); - } - - if (httpRequest.getMethod().equals("POST")) { - final HttpResponse httpResponse = HttpResponse.init(); - final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); - String sessionId = httpCookie.getCookie("JSESSIONID"); - - Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); - if (user.isEmpty() || !user.get().checkPassword(httpRequest.getBody().get("password"))) { - // invalid user - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); - httpResponse.addHeader(LOCATION, "/401.html"); - httpResponse.setStatusCode(FOUND); - return httpResponse; - } - - // valid user - log.info("user: {}", user.get()); - - if (sessionId != null) { // if already have session - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); - httpResponse.addHeader(LOCATION, "/index.html"); - httpResponse.setStatusCode(FOUND); - return httpResponse; - } - - // if no session - Session session = new Session(String.valueOf(UUID.randomUUID())); - session.setAttribute("user", user); - sessionManager.add(session); - sessionId = session.getId(); - - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); - httpResponse.addHeader(LOCATION, "/index.html"); - httpResponse.addHeader(SET_COOKIE, "JSESSIONID=" + sessionId); - httpResponse.setStatusCode(FOUND); - return httpResponse; - } - return handleResourceRequest(httpRequest, "404.html"); // Method Not Allowed - } - - private HttpResponse handleResourceRequest(final HttpRequest httpRequest, final String resourceUrl) throws IOException { - final HttpResponse httpResponse = HttpResponse.init(); - String contentType = "text/html;charset=utf-8"; - - final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); - if (acceptHeader != null) { - contentType = acceptHeader.split(",")[0]; - } - - URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); - if (resource != null) { - httpResponse.setStatusCode(OK); - } else { - resource = getClass().getClassLoader().getResource("static/" + "404.html"); - httpResponse.setStatusCode(NOT_FOUND); - contentType = "text/html;charset=utf-8"; - } - - final String responseBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); - httpResponse.addHeader(CONTENT_TYPE, contentType); - httpResponse.setBody(responseBody); - return httpResponse; - } } From f5fd662ff56b5c4a969570b15ee0b6ad212b1efb Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Wed, 6 Sep 2023 21:02:47 +0900 Subject: [PATCH 09/32] =?UTF-8?q?refactor:=20ResourceReader=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/catalina/ResourceReader.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/catalina/ResourceReader.java diff --git a/tomcat/src/main/java/org/apache/catalina/ResourceReader.java b/tomcat/src/main/java/org/apache/catalina/ResourceReader.java new file mode 100644 index 0000000000..29d85e76bd --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/ResourceReader.java @@ -0,0 +1,20 @@ +package org.apache.catalina; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; + +public class ResourceReader { + + private static final ClassLoader CLASS_LOADER = ClassLoader.getSystemClassLoader(); + + public static URL getResourceUrl(final String fileName) { + return CLASS_LOADER.getResource("static/" + fileName); + } + + public static String read(final URL resource) throws IOException { + final byte[] bytes = Files.readAllBytes(new File(resource.getFile()).toPath()); + return new String(bytes); + } +} From 968713707563af2811e8b6ed8475946c05d23d03 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Wed, 6 Sep 2023 21:03:45 +0900 Subject: [PATCH 10/32] =?UTF-8?q?refactor:=20ResourceContentTypeResolver?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catalina/ResourceContentTypeResolver.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java diff --git a/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java b/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java new file mode 100644 index 0000000000..df02520aaf --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java @@ -0,0 +1,37 @@ +package org.apache.catalina; + +import org.apache.coyote.http11.HttpHeaders; + +import static org.apache.coyote.http11.HttpHeaderType.ACCEPT; +import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; + +public class ResourceContentTypeResolver { + + public String getContentType(final HttpHeaders headers, final String resourceName) { + final String contentTypeHeader = headers.getHeaderValue(CONTENT_TYPE); + if (contentTypeHeader != null) { + String firstContentType = contentTypeHeader.split(",")[0]; + // TODO: Check whether the content type is supported + return firstContentType; + } + + final String acceptHeader = headers.getHeaderValue(ACCEPT); + if (acceptHeader != null) { + String firstAcceptHeader = acceptHeader.split(",")[0]; + // TODO: Check whether the content type is supported + return firstAcceptHeader; + } + + return getFileExtension(resourceName); + } + + private String getFileExtension(final String fileName) { + final int lastDotIndex = fileName.lastIndexOf('.'); + if (lastDotIndex >= 0) { + final String fileExtension = fileName.substring(lastDotIndex + 1); + // TODO: Check whether the content type is supported + return fileExtension; + } + return null; + } +} From e16df12e06fad7ff539d24f743b3dd5fb3a1362e Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Fri, 8 Sep 2023 00:17:22 +0900 Subject: [PATCH 11/32] =?UTF-8?q?refactor:=20MediaType=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/catalina/MediaType.java | 79 +++++++++++++++++++ .../catalina/ResourceContentTypeResolver.java | 37 ++++++--- .../org/apache/catalina/ResourceReader.java | 2 +- .../java/org/apache/coyote/Controller.java | 3 +- .../org/apache/coyote/ResourceController.java | 36 +++++---- .../apache/coyote/http11/Http11Processor.java | 9 ++- 6 files changed, 135 insertions(+), 31 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/catalina/MediaType.java diff --git a/tomcat/src/main/java/org/apache/catalina/MediaType.java b/tomcat/src/main/java/org/apache/catalina/MediaType.java new file mode 100644 index 0000000000..7115c732fe --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/MediaType.java @@ -0,0 +1,79 @@ +package org.apache.catalina; + +import java.util.Arrays; + +public enum MediaType { + + ALL("*", "*"), + APPLICATION_ATOM_XML("application", "atom+xml"), + APPLICATION_CBOR("application", "cbor"), + APPLICATION_FORM_URLENCODED("application", "x-www-form-urlencoded"), + APPLICATION_GRAPHQL("application", "graphql+json"), + APPLICATION_JSON("application", "json"), + APPLICATION_JSON_UTF8("application", "json"), // TODO: utf-8 + APPLICATION_NDJSON("application", "x-ndjson"), + APPLICATION_OCTET_STREAM("application", "octet-stream"), + APPLICATION_PDF("application", "pdf"), + APPLICATION_PROBLEM_JSON("application", "problem+json"), + APPLICATION_PROBLEM_JSON_UTF8("application", "problem+json"), // TODO: utf-8 + APPLICATION_PROBLEM_XML("application", "problem+xml"), + APPLICATION_RSS_XML("application", "rss+xml"), + APPLICATION_STREAM_JSON("application", "stream+json"), + APPLICATION_XHTML_XML("application", "xhtml+xml"), + APPLICATION_XML("application", "xml"), + IMAGE_GIF("image", "gif"), + IMAGE_JPEG("image", "jpeg"), + IMAGE_PNG("image", "png"), + MULTIPART_FORM_DATA("multipart", "form-data"), + MULTIPART_MIXED("multipart", "mixed"), + MULTIPART_RELATED("multipart", "related"), + TEXT_EVENT_STREAM("text", "event-stream"), + TEXT_HTML("text", "html"), + TEXT_MARKDOWN("text", "markdown"), + TEXT_PLAIN("text", "plain"), + TEXT_XML("text", "xml"), + TEXT_JAVASCRIPT("text", "javascript"), + TEXT_CSS("text", "css"); + + private final String type; + private final String subType; + + MediaType(final String type, final String subType) { + this.type = type; + this.subType = subType; + } + + public static MediaType getMediaType(final String mediaType) { + return Arrays.stream(values()) + .filter(mediaType1 -> mediaType1.stringify().equals(mediaType)) + .findFirst() + .orElse(null); + } + + public static MediaType getMediaTypeByFileExtension(final String fileExtension) { + return Arrays.stream(values()) + .filter(mediaType -> mediaType.getSubType().equals(fileExtension)) + .findFirst() + .orElse(null); + } + + public static boolean isSupported(final MediaType mediaType) { + return mediaType != null && !mediaType.isWildCard(mediaType); + } + + private boolean isWildCard(final MediaType mediaType) { + return mediaType.equals(ALL); + } + + public String stringify() { + return type + "/" + subType; + } + + public String getType() { + return type; + } + + public String getSubType() { + return subType; + } +} diff --git a/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java b/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java index df02520aaf..090a07a581 100644 --- a/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java +++ b/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java @@ -8,29 +8,44 @@ public class ResourceContentTypeResolver { public String getContentType(final HttpHeaders headers, final String resourceName) { - final String contentTypeHeader = headers.getHeaderValue(CONTENT_TYPE); - if (contentTypeHeader != null) { - String firstContentType = contentTypeHeader.split(",")[0]; - // TODO: Check whether the content type is supported - return firstContentType; + final String contentType = getFirstSupportedMediaType(headers.getHeaderValue(CONTENT_TYPE)); + if (contentType != null) { + return contentType; } - final String acceptHeader = headers.getHeaderValue(ACCEPT); + final String acceptHeader = getFirstSupportedMediaType(headers.getHeaderValue(ACCEPT)); if (acceptHeader != null) { - String firstAcceptHeader = acceptHeader.split(",")[0]; - // TODO: Check whether the content type is supported - return firstAcceptHeader; + return acceptHeader; } return getFileExtension(resourceName); } + private String getFirstSupportedMediaType(String headerValue) { + if (headerValue != null) { + String[] mediaTypes = headerValue.split(","); + for (String mediaTypeStr : mediaTypes) { + final MediaType mediaType = MediaType.getMediaType(mediaTypeStr.trim()); + if (MediaType.isSupported(mediaType)) { + return mediaTypeStr.trim(); + } + } + } + return null; + } + private String getFileExtension(final String fileName) { final int lastDotIndex = fileName.lastIndexOf('.'); if (lastDotIndex >= 0) { final String fileExtension = fileName.substring(lastDotIndex + 1); - // TODO: Check whether the content type is supported - return fileExtension; + if ("js".equals(fileExtension)) { + final MediaType javascript = MediaType.getMediaTypeByFileExtension("javascript"); + return javascript.stringify(); + } + final MediaType mediaType = MediaType.getMediaTypeByFileExtension(fileExtension); + if (MediaType.isSupported(mediaType)) { + return mediaType.stringify(); + } } return null; } diff --git a/tomcat/src/main/java/org/apache/catalina/ResourceReader.java b/tomcat/src/main/java/org/apache/catalina/ResourceReader.java index 29d85e76bd..bc77f9e20f 100644 --- a/tomcat/src/main/java/org/apache/catalina/ResourceReader.java +++ b/tomcat/src/main/java/org/apache/catalina/ResourceReader.java @@ -10,7 +10,7 @@ public class ResourceReader { private static final ClassLoader CLASS_LOADER = ClassLoader.getSystemClassLoader(); public static URL getResourceUrl(final String fileName) { - return CLASS_LOADER.getResource("static/" + fileName); + return CLASS_LOADER.getResource("static" + fileName); } public static String read(final URL resource) throws IOException { diff --git a/tomcat/src/main/java/org/apache/coyote/Controller.java b/tomcat/src/main/java/org/apache/coyote/Controller.java index 207f60a611..8861ec635d 100644 --- a/tomcat/src/main/java/org/apache/coyote/Controller.java +++ b/tomcat/src/main/java/org/apache/coyote/Controller.java @@ -9,8 +9,9 @@ public abstract class Controller { public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { if (!canHandle(httpRequest)) { - // TODO: exception - there is any controller to handle + throw new IllegalArgumentException("There is no controller to handle."); } + final String method = httpRequest.getMethod(); if ("GET".equals(method)) { doGet(httpRequest, httpResponse); diff --git a/tomcat/src/main/java/org/apache/coyote/ResourceController.java b/tomcat/src/main/java/org/apache/coyote/ResourceController.java index 63766763cc..ce2b951f75 100644 --- a/tomcat/src/main/java/org/apache/coyote/ResourceController.java +++ b/tomcat/src/main/java/org/apache/coyote/ResourceController.java @@ -1,14 +1,13 @@ package org.apache.coyote; +import org.apache.catalina.ResourceContentTypeResolver; +import org.apache.catalina.ResourceReader; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; -import java.io.File; import java.io.IOException; import java.net.URL; -import java.nio.file.Files; -import static org.apache.coyote.http11.HttpHeaderType.ACCEPT; import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; import static org.apache.coyote.http11.response.HttpStatusCode.OK; @@ -22,24 +21,27 @@ public boolean canHandle(final HttpRequest httpRequest) { @Override public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { - final String resourceUrl = httpRequest.getTarget(); - String contentType = "text/html;charset=utf-8"; - - final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); - if (acceptHeader != null) { - contentType = acceptHeader.split(",")[0]; + final String resourceName = httpRequest.getTarget(); + final URL resourceUrl = ResourceReader.getResourceUrl(resourceName); + if (resourceUrl == null) { +// throw new IllegalArgumentException("The resource corresponding to the request does not exist"); + final URL resource404 = ResourceReader.getResourceUrl("404.html"); + final String responseBody = ResourceReader.read(resource404); + httpResponse.setStatusCode(NOT_FOUND); + httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.setBody(responseBody); + return; } - URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); - if (resource != null) { - httpResponse.setStatusCode(OK); - } else { - resource = getClass().getClassLoader().getResource("static/" + "404.html"); - httpResponse.setStatusCode(NOT_FOUND); - contentType = "text/html;charset=utf-8"; + final ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); + final String contentType = resourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); + + if (contentType == null) { + throw new IllegalArgumentException("Content type is not supported."); } - final String responseBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + final String responseBody = ResourceReader.read(resourceUrl); + httpResponse.setStatusCode(OK); httpResponse.addHeader(CONTENT_TYPE, contentType); httpResponse.setBody(responseBody); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index af0e5c4d3b..3d9e87f667 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -21,6 +21,8 @@ import java.net.Socket; import java.util.List; +import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; + public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); @@ -55,7 +57,12 @@ public void process(final Socket connection) { final Controller controller = requestMapping.getController(httpRequest); final HttpResponse httpResponse = HttpResponse.init(); - controller.service(httpRequest, httpResponse); + try { + controller.service(httpRequest, httpResponse); + } catch (final Exception e) { + httpResponse.setStatusCode(NOT_FOUND); + httpResponse.setBody(e.getMessage()); + } outputStream.write(httpResponse.stringify().getBytes()); outputStream.flush(); From 32a7681eba93fcb0a05c8726c285c665e41c816e Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Fri, 8 Sep 2023 00:18:35 +0900 Subject: [PATCH 12/32] =?UTF-8?q?refactor:=20MediaType=20value=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 --- .../src/main/java/org/apache/catalina/MediaType.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/MediaType.java b/tomcat/src/main/java/org/apache/catalina/MediaType.java index 7115c732fe..b4387e18ff 100644 --- a/tomcat/src/main/java/org/apache/catalina/MediaType.java +++ b/tomcat/src/main/java/org/apache/catalina/MediaType.java @@ -5,21 +5,10 @@ public enum MediaType { ALL("*", "*"), - APPLICATION_ATOM_XML("application", "atom+xml"), - APPLICATION_CBOR("application", "cbor"), APPLICATION_FORM_URLENCODED("application", "x-www-form-urlencoded"), - APPLICATION_GRAPHQL("application", "graphql+json"), APPLICATION_JSON("application", "json"), - APPLICATION_JSON_UTF8("application", "json"), // TODO: utf-8 - APPLICATION_NDJSON("application", "x-ndjson"), APPLICATION_OCTET_STREAM("application", "octet-stream"), APPLICATION_PDF("application", "pdf"), - APPLICATION_PROBLEM_JSON("application", "problem+json"), - APPLICATION_PROBLEM_JSON_UTF8("application", "problem+json"), // TODO: utf-8 - APPLICATION_PROBLEM_XML("application", "problem+xml"), - APPLICATION_RSS_XML("application", "rss+xml"), - APPLICATION_STREAM_JSON("application", "stream+json"), - APPLICATION_XHTML_XML("application", "xhtml+xml"), APPLICATION_XML("application", "xml"), IMAGE_GIF("image", "gif"), IMAGE_JPEG("image", "jpeg"), @@ -27,7 +16,6 @@ public enum MediaType { MULTIPART_FORM_DATA("multipart", "form-data"), MULTIPART_MIXED("multipart", "mixed"), MULTIPART_RELATED("multipart", "related"), - TEXT_EVENT_STREAM("text", "event-stream"), TEXT_HTML("text", "html"), TEXT_MARKDOWN("text", "markdown"), TEXT_PLAIN("text", "plain"), From 407db0a4f2fb0eb81d9a5bf4f85168d79e6fd905 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Fri, 8 Sep 2023 00:35:02 +0900 Subject: [PATCH 13/32] =?UTF-8?q?refactor:=20=EB=A6=AC=EC=86=8C=EC=8A=A4?= =?UTF-8?q?=20=ED=95=B8=EB=93=A4=EB=A7=81=ED=95=98=EB=8A=94=20=EB=A9=94?= =?UTF-8?q?=EC=86=8C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/controller/LoginController.java | 33 +++---------------- .../jwp/controller/RegisterController.java | 29 +++------------- .../org/apache/catalina/ResourceReader.java | 4 +-- .../java/org/apache/coyote/Controller.java | 29 ++++++++++++++++ .../org/apache/coyote/ResourceController.java | 31 +---------------- 5 files changed, 40 insertions(+), 86 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 016eddea19..f3a1705f0e 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -8,15 +8,12 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; -import java.io.File; import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; import java.util.*; import static org.apache.coyote.http11.Http11Processor.sessionManager; import static org.apache.coyote.http11.HttpHeaderType.*; -import static org.apache.coyote.http11.response.HttpStatusCode.*; +import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; public class LoginController extends Controller { @@ -43,26 +40,7 @@ public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); httpResponse.addHeader(LOCATION, "/index.html"); } else { // not login user - final String resourceUrl = "login.html"; - String contentType = "text/html;charset=utf-8"; - - final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); - if (acceptHeader != null) { - contentType = acceptHeader.split(",")[0]; - } - - URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); - if (resource != null) { - httpResponse.setStatusCode(OK); - } else { - resource = getClass().getClassLoader().getResource("static/" + "404.html"); - httpResponse.setStatusCode(NOT_FOUND); - contentType = "text/html;charset=utf-8"; - } - - final String responseBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); - httpResponse.addHeader(CONTENT_TYPE, contentType); - httpResponse.setBody(responseBody); + handleResource("/login.html", httpRequest, httpResponse); } } @@ -71,7 +49,7 @@ public void doPost(final HttpRequest httpRequest, final HttpResponse httpRespons final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); String sessionId = httpCookie.getCookie("JSESSIONID"); - Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); + final Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); if (user.isEmpty() || !user.get().checkPassword(httpRequest.getBody().get("password"))) { // invalid user httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); @@ -80,9 +58,6 @@ public void doPost(final HttpRequest httpRequest, final HttpResponse httpRespons return; } - // valid user -// log.info("user: {}", user.get()); - if (sessionId != null) { // if already have session httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); httpResponse.addHeader(LOCATION, "/index.html"); @@ -91,7 +66,7 @@ public void doPost(final HttpRequest httpRequest, final HttpResponse httpRespons } // if no session - Session session = new Session(String.valueOf(UUID.randomUUID())); + final Session session = new Session(String.valueOf(UUID.randomUUID())); session.setAttribute("user", user); sessionManager.add(session); sessionId = session.getId(); diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java index c8a55f8971..a6c3fb2895 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -6,17 +6,15 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; -import java.io.File; import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import static org.apache.coyote.http11.HttpHeaderType.*; -import static org.apache.coyote.http11.response.HttpStatusCode.*; +import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.HttpHeaderType.LOCATION; +import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; public class RegisterController extends Controller { @@ -35,26 +33,7 @@ public boolean canHandle(final HttpRequest httpRequest) { @Override public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { - final String resourceUrl = "register.html"; - String contentType = "text/html;charset=utf-8"; - - final String acceptHeader = httpRequest.getHeaders().getHeaderValue(ACCEPT); - if (acceptHeader != null) { - contentType = acceptHeader.split(",")[0]; - } - - URL resource = getClass().getClassLoader().getResource("static/" + resourceUrl); - if (resource != null) { - httpResponse.setStatusCode(OK); - } else { - resource = getClass().getClassLoader().getResource("static/" + "404.html"); - httpResponse.setStatusCode(NOT_FOUND); - contentType = "text/html;charset=utf-8"; - } - - final String responseBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); - httpResponse.addHeader(CONTENT_TYPE, contentType); - httpResponse.setBody(responseBody); + handleResource("/register.html", httpRequest, httpResponse); } @Override diff --git a/tomcat/src/main/java/org/apache/catalina/ResourceReader.java b/tomcat/src/main/java/org/apache/catalina/ResourceReader.java index bc77f9e20f..e15ec089a0 100644 --- a/tomcat/src/main/java/org/apache/catalina/ResourceReader.java +++ b/tomcat/src/main/java/org/apache/catalina/ResourceReader.java @@ -9,8 +9,8 @@ public class ResourceReader { private static final ClassLoader CLASS_LOADER = ClassLoader.getSystemClassLoader(); - public static URL getResourceUrl(final String fileName) { - return CLASS_LOADER.getResource("static" + fileName); + public static URL getResourceUrl(final String resourceName) { + return CLASS_LOADER.getResource("static" + resourceName); } public static String read(final URL resource) throws IOException { diff --git a/tomcat/src/main/java/org/apache/coyote/Controller.java b/tomcat/src/main/java/org/apache/coyote/Controller.java index 8861ec635d..dc8179dd75 100644 --- a/tomcat/src/main/java/org/apache/coyote/Controller.java +++ b/tomcat/src/main/java/org/apache/coyote/Controller.java @@ -1,9 +1,15 @@ package org.apache.coyote; +import org.apache.catalina.ResourceContentTypeResolver; +import org.apache.catalina.ResourceReader; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import java.io.IOException; +import java.net.URL; + +import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.response.HttpStatusCode.OK; public abstract class Controller { @@ -22,6 +28,29 @@ public void service(final HttpRequest httpRequest, final HttpResponse httpRespon // TODO: exception - invalid http method } + protected void handleResource( + final String resourceName, + final HttpRequest httpRequest, + final HttpResponse httpResponse + ) throws IOException { + final URL resourceUrl = ResourceReader.getResourceUrl(resourceName); + if (resourceUrl == null) { + throw new IllegalArgumentException("The resource corresponding to the request does not exist"); + } + + final ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); + final String contentType = resourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); + + if (contentType == null) { + throw new IllegalArgumentException("Content type is not supported."); + } + + final String responseBody = ResourceReader.read(resourceUrl); + httpResponse.setStatusCode(OK); + httpResponse.addHeader(CONTENT_TYPE, contentType); + httpResponse.setBody(responseBody); + } + public abstract boolean canHandle(final HttpRequest httpRequest); public abstract void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException; diff --git a/tomcat/src/main/java/org/apache/coyote/ResourceController.java b/tomcat/src/main/java/org/apache/coyote/ResourceController.java index ce2b951f75..286fa8c5b2 100644 --- a/tomcat/src/main/java/org/apache/coyote/ResourceController.java +++ b/tomcat/src/main/java/org/apache/coyote/ResourceController.java @@ -1,16 +1,9 @@ package org.apache.coyote; -import org.apache.catalina.ResourceContentTypeResolver; -import org.apache.catalina.ResourceReader; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import java.io.IOException; -import java.net.URL; - -import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; -import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; -import static org.apache.coyote.http11.response.HttpStatusCode.OK; public class ResourceController extends Controller { @@ -21,29 +14,7 @@ public boolean canHandle(final HttpRequest httpRequest) { @Override public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { - final String resourceName = httpRequest.getTarget(); - final URL resourceUrl = ResourceReader.getResourceUrl(resourceName); - if (resourceUrl == null) { -// throw new IllegalArgumentException("The resource corresponding to the request does not exist"); - final URL resource404 = ResourceReader.getResourceUrl("404.html"); - final String responseBody = ResourceReader.read(resource404); - httpResponse.setStatusCode(NOT_FOUND); - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); - httpResponse.setBody(responseBody); - return; - } - - final ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); - final String contentType = resourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); - - if (contentType == null) { - throw new IllegalArgumentException("Content type is not supported."); - } - - final String responseBody = ResourceReader.read(resourceUrl); - httpResponse.setStatusCode(OK); - httpResponse.addHeader(CONTENT_TYPE, contentType); - httpResponse.setBody(responseBody); + handleResource(httpRequest.getTarget(), httpRequest, httpResponse); } @Override From 33e78260f80d33b6b99ddf662b1d6e92e1cf7e97 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 00:02:02 +0900 Subject: [PATCH 14/32] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/controller/LoginController.java | 8 ++-- .../jwp/controller/RegisterController.java | 8 ++-- .../jwp/controller/RootController.java | 6 +-- .../java/org/apache/catalina/Controller.java | 12 +++++ .../controller/HttpController.java} | 48 ++++++++++++------- .../controller}/ResourceController.java | 4 +- .../org/apache/coyote/RequestMapping.java | 9 ++-- .../apache/coyote/http11/Http11Processor.java | 4 +- .../http11/{ => common}/HttpCookie.java | 2 +- .../http11/{ => common}/HttpHeaderType.java | 2 +- .../http11/{ => common}/HttpHeaders.java | 2 +- .../http11/common}/MediaType.java | 4 +- .../common}/ResourceContentTypeResolver.java | 12 ++--- .../http11/common}/ResourceReader.java | 2 +- .../coyote/http11/request/HttpRequest.java | 2 +- .../http11/request/HttpRequestParser.java | 8 ++-- .../coyote/http11/response/HttpResponse.java | 4 +- 17 files changed, 81 insertions(+), 56 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/catalina/Controller.java rename tomcat/src/main/java/org/apache/{coyote/Controller.java => catalina/controller/HttpController.java} (59%) rename tomcat/src/main/java/org/apache/{coyote => catalina/controller}/ResourceController.java (85%) rename tomcat/src/main/java/org/apache/coyote/http11/{ => common}/HttpCookie.java (95%) rename tomcat/src/main/java/org/apache/coyote/http11/{ => common}/HttpHeaderType.java (89%) rename tomcat/src/main/java/org/apache/coyote/http11/{ => common}/HttpHeaders.java (96%) rename tomcat/src/main/java/org/apache/{catalina => coyote/http11/common}/MediaType.java (94%) rename tomcat/src/main/java/org/apache/{catalina => coyote/http11/common}/ResourceContentTypeResolver.java (81%) rename tomcat/src/main/java/org/apache/{catalina => coyote/http11/common}/ResourceReader.java (93%) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index f3a1705f0e..c0bab88744 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -3,8 +3,8 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.model.User; import org.apache.catalina.Session; -import org.apache.coyote.Controller; -import org.apache.coyote.http11.HttpCookie; +import org.apache.catalina.controller.HttpController; +import org.apache.coyote.http11.common.HttpCookie; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -12,10 +12,10 @@ import java.util.*; import static org.apache.coyote.http11.Http11Processor.sessionManager; -import static org.apache.coyote.http11.HttpHeaderType.*; +import static org.apache.coyote.http11.common.HttpHeaderType.*; import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; -public class LoginController extends Controller { +public class LoginController extends HttpController { @Override public boolean canHandle(final HttpRequest httpRequest) { diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java index a6c3fb2895..45b9a0365f 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -2,7 +2,7 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.model.User; -import org.apache.coyote.Controller; +import org.apache.catalina.controller.HttpController; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -12,11 +12,11 @@ import java.util.Map; import java.util.Set; -import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; -import static org.apache.coyote.http11.HttpHeaderType.LOCATION; +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION; import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; -public class RegisterController extends Controller { +public class RegisterController extends HttpController { @Override public boolean canHandle(final HttpRequest httpRequest) { diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java index 20440b3c0a..a4a0a95470 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -1,15 +1,15 @@ package nextstep.jwp.controller; -import org.apache.coyote.Controller; +import org.apache.catalina.controller.HttpController; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import java.util.*; -import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; import static org.apache.coyote.http11.response.HttpStatusCode.OK; -public class RootController extends Controller { +public class RootController extends HttpController { @Override public boolean canHandle(final HttpRequest httpRequest) { diff --git a/tomcat/src/main/java/org/apache/catalina/Controller.java b/tomcat/src/main/java/org/apache/catalina/Controller.java new file mode 100644 index 0000000000..4254ab5ef9 --- /dev/null +++ b/tomcat/src/main/java/org/apache/catalina/Controller.java @@ -0,0 +1,12 @@ +package org.apache.catalina; + +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.response.HttpResponse; + +public interface Controller { + + void init(); + void destory(); + void service(HttpRequest request, HttpResponse response) throws Exception; + +} diff --git a/tomcat/src/main/java/org/apache/coyote/Controller.java b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java similarity index 59% rename from tomcat/src/main/java/org/apache/coyote/Controller.java rename to tomcat/src/main/java/org/apache/catalina/controller/HttpController.java index dc8179dd75..96b1d26566 100644 --- a/tomcat/src/main/java/org/apache/coyote/Controller.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java @@ -1,31 +1,46 @@ -package org.apache.coyote; +package org.apache.catalina.controller; -import org.apache.catalina.ResourceContentTypeResolver; -import org.apache.catalina.ResourceReader; +import org.apache.catalina.Controller; +import org.apache.coyote.http11.common.ResourceContentTypeResolver; +import org.apache.coyote.http11.common.ResourceReader; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import java.io.IOException; import java.net.URL; -import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; import static org.apache.coyote.http11.response.HttpStatusCode.OK; -public abstract class Controller { +public abstract class HttpController implements Controller { - public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { - if (!canHandle(httpRequest)) { - throw new IllegalArgumentException("There is no controller to handle."); - } + @Override + public void init() { + } - final String method = httpRequest.getMethod(); - if ("GET".equals(method)) { - doGet(httpRequest, httpResponse); - } - if ("POST".equals(method)) { - doPost(httpRequest, httpResponse); + @Override + public void destory() { + } + + @Override + public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + try { + if (!canHandle(httpRequest)) { + throw new IllegalArgumentException("There is no controller to handle."); + } + final String method = httpRequest.getMethod(); + if ("GET".equals(method)) { + doGet(httpRequest, httpResponse); + } + if ("POST".equals(method)) { + doPost(httpRequest, httpResponse); + } + // TODO: exception - invalid http method + } catch (final Exception e) { + httpResponse.setStatusCode(NOT_FOUND); + httpResponse.setBody(e.getMessage()); } - // TODO: exception - invalid http method } protected void handleResource( @@ -52,7 +67,6 @@ protected void handleResource( } public abstract boolean canHandle(final HttpRequest httpRequest); - public abstract void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException; public abstract void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException; } diff --git a/tomcat/src/main/java/org/apache/coyote/ResourceController.java b/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java similarity index 85% rename from tomcat/src/main/java/org/apache/coyote/ResourceController.java rename to tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java index 286fa8c5b2..34f1e7aefb 100644 --- a/tomcat/src/main/java/org/apache/coyote/ResourceController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java @@ -1,11 +1,11 @@ -package org.apache.coyote; +package org.apache.catalina.controller; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; import java.io.IOException; -public class ResourceController extends Controller { +public class ResourceController extends HttpController { @Override public boolean canHandle(final HttpRequest httpRequest) { diff --git a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java index 293bbdba42..b27691b298 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java @@ -1,19 +1,20 @@ package org.apache.coyote; +import org.apache.catalina.controller.HttpController; import org.apache.coyote.http11.request.HttpRequest; import java.util.List; public class RequestMapping { - private final List controllers; + private final List controllers; - public RequestMapping(final List controllers) { + public RequestMapping(final List controllers) { this.controllers = controllers; } - public Controller getController(final HttpRequest httpRequest) { - for (final Controller controller : controllers) { + public HttpController getController(final HttpRequest httpRequest) { + for (final HttpController controller : controllers) { if (controller.canHandle(httpRequest)) { return controller; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 3d9e87f667..6d014e5ab1 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -4,11 +4,11 @@ import nextstep.jwp.controller.RegisterController; import nextstep.jwp.controller.RootController; import nextstep.jwp.exception.UncheckedServletException; +import org.apache.catalina.Controller; import org.apache.catalina.SessionManager; -import org.apache.coyote.Controller; +import org.apache.catalina.controller.ResourceController; import org.apache.coyote.Processor; import org.apache.coyote.RequestMapping; -import org.apache.coyote.ResourceController; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.request.HttpRequestParser; import org.apache.coyote.http11.response.HttpResponse; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/http11/common/HttpCookie.java similarity index 95% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java rename to tomcat/src/main/java/org/apache/coyote/http11/common/HttpCookie.java index ffc7c85e39..93eeb6a3ff 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/HttpCookie.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.common; import java.util.HashMap; import java.util.Map; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderType.java b/tomcat/src/main/java/org/apache/coyote/http11/common/HttpHeaderType.java similarity index 89% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderType.java rename to tomcat/src/main/java/org/apache/coyote/http11/common/HttpHeaderType.java index aa9033ec6f..91d738674a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaderType.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/HttpHeaderType.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.common; public enum HttpHeaderType { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java b/tomcat/src/main/java/org/apache/coyote/http11/common/HttpHeaders.java similarity index 96% rename from tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java rename to tomcat/src/main/java/org/apache/coyote/http11/common/HttpHeaders.java index db6a936057..612534b490 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpHeaders.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/HttpHeaders.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11; +package org.apache.coyote.http11.common; import java.util.HashMap; import java.util.Map; diff --git a/tomcat/src/main/java/org/apache/catalina/MediaType.java b/tomcat/src/main/java/org/apache/coyote/http11/common/MediaType.java similarity index 94% rename from tomcat/src/main/java/org/apache/catalina/MediaType.java rename to tomcat/src/main/java/org/apache/coyote/http11/common/MediaType.java index b4387e18ff..8640e39ad3 100644 --- a/tomcat/src/main/java/org/apache/catalina/MediaType.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/MediaType.java @@ -1,4 +1,4 @@ -package org.apache.catalina; +package org.apache.coyote.http11.common; import java.util.Arrays; @@ -54,7 +54,7 @@ private boolean isWildCard(final MediaType mediaType) { } public String stringify() { - return type + "/" + subType; + return type + "/" + subType + ";" + "charset=utf-8"; } public String getType() { diff --git a/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java similarity index 81% rename from tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java rename to tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java index 090a07a581..2819ba1994 100644 --- a/tomcat/src/main/java/org/apache/catalina/ResourceContentTypeResolver.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java @@ -1,9 +1,7 @@ -package org.apache.catalina; +package org.apache.coyote.http11.common; -import org.apache.coyote.http11.HttpHeaders; - -import static org.apache.coyote.http11.HttpHeaderType.ACCEPT; -import static org.apache.coyote.http11.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.common.HttpHeaderType.ACCEPT; +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; public class ResourceContentTypeResolver { @@ -39,8 +37,8 @@ private String getFileExtension(final String fileName) { if (lastDotIndex >= 0) { final String fileExtension = fileName.substring(lastDotIndex + 1); if ("js".equals(fileExtension)) { - final MediaType javascript = MediaType.getMediaTypeByFileExtension("javascript"); - return javascript.stringify(); + final MediaType jsContentType = MediaType.getMediaTypeByFileExtension("javascript"); + return jsContentType.stringify(); } final MediaType mediaType = MediaType.getMediaTypeByFileExtension(fileExtension); if (MediaType.isSupported(mediaType)) { diff --git a/tomcat/src/main/java/org/apache/catalina/ResourceReader.java b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceReader.java similarity index 93% rename from tomcat/src/main/java/org/apache/catalina/ResourceReader.java rename to tomcat/src/main/java/org/apache/coyote/http11/common/ResourceReader.java index e15ec089a0..7776bb9a18 100644 --- a/tomcat/src/main/java/org/apache/catalina/ResourceReader.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceReader.java @@ -1,4 +1,4 @@ -package org.apache.catalina; +package org.apache.coyote.http11.common; import java.io.File; import java.io.IOException; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index 748b87ba83..d22034faa3 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,6 +1,6 @@ package org.apache.coyote.http11.request; -import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.common.HttpHeaders; import java.util.Map; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index 5f7c8af271..4f8e244f4b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -1,7 +1,7 @@ package org.apache.coyote.http11.request; -import org.apache.coyote.http11.HttpCookie; -import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.common.HttpCookie; +import org.apache.coyote.http11.common.HttpHeaders; import java.io.BufferedReader; import java.io.IOException; @@ -9,8 +9,8 @@ import java.util.HashMap; import java.util.Map; -import static org.apache.coyote.http11.HttpHeaderType.CONTENT_LENGTH; -import static org.apache.coyote.http11.HttpHeaderType.COOKIE; +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_LENGTH; +import static org.apache.coyote.http11.common.HttpHeaderType.COOKIE; public class HttpRequestParser { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java index 5188fb17b0..fa4dc3c7fd 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpResponse.java @@ -1,7 +1,7 @@ package org.apache.coyote.http11.response; -import org.apache.coyote.http11.HttpHeaderType; -import org.apache.coyote.http11.HttpHeaders; +import org.apache.coyote.http11.common.HttpHeaderType; +import org.apache.coyote.http11.common.HttpHeaders; import java.util.Map; From 317e43473a8c979244acdcfb913492d1de02e896 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 18:48:39 +0900 Subject: [PATCH 15/32] =?UTF-8?q?test:=20thread=20test=20=EC=A7=84?= =?UTF-8?q?=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/test/java/thread/stage0/SynchronizationTest.java | 2 +- study/src/test/java/thread/stage0/ThreadPoolsTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 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..03efdabc8d 100644 --- a/study/src/test/java/thread/stage0/ThreadPoolsTest.java +++ b/study/src/test/java/thread/stage0/ThreadPoolsTest.java @@ -31,8 +31,8 @@ void testNewFixedThreadPool() { executor.submit(logWithSleep("hello fixed thread pools")); // 올바른 값으로 바꿔서 테스트를 통과시키자. - final int expectedPoolSize = 0; - final int expectedQueueSize = 0; + final int expectedPoolSize = 2; + final int expectedQueueSize = 1; assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize()); assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size()); @@ -46,7 +46,7 @@ void testNewCachedThreadPool() { executor.submit(logWithSleep("hello cached thread pools")); // 올바른 값으로 바꿔서 테스트를 통과시키자. - final int expectedPoolSize = 0; + final int expectedPoolSize = 3; final int expectedQueueSize = 0; assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize()); From 99a5154050fcadca5c1846fc0d57c8e5c694f842 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 19:24:44 +0900 Subject: [PATCH 16/32] =?UTF-8?q?feat:=20step4=20-=20executors=EB=A1=9C=20?= =?UTF-8?q?thread=20pool=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/catalina/connector/Connector.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java index 3b2c4dda7c..f115714cdc 100644 --- a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java +++ b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java @@ -8,6 +8,8 @@ import java.io.UncheckedIOException; import java.net.ServerSocket; import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class Connector implements Runnable { @@ -15,19 +17,23 @@ public class Connector implements Runnable { private static final int DEFAULT_PORT = 8080; private static final int DEFAULT_ACCEPT_COUNT = 100; + private static final int DEFAULT_MAX_THREADS = 250; private final ServerSocket serverSocket; + private final ExecutorService executor; private boolean stopped; public Connector() { - this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT); + this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_MAX_THREADS); } - public Connector(final int port, final int acceptCount) { + public Connector(final int port, final int acceptCount, final int maxThreads) { this.serverSocket = createServerSocket(port, acceptCount); this.stopped = false; + this.executor = Executors.newFixedThreadPool(maxThreads); } + private ServerSocket createServerSocket(final int port, final int acceptCount) { try { final int checkedPort = checkPort(port); @@ -67,7 +73,7 @@ private void process(final Socket connection) { return; } var processor = new Http11Processor(connection); - new Thread(processor).start(); + executor.submit(processor); } public void stop() { From e66ea7fe517eb726541b5733faaf39859cd84af6 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 19:26:51 +0900 Subject: [PATCH 17/32] =?UTF-8?q?feat:=20step4=20-=20=EB=8F=99=EC=8B=9C?= =?UTF-8?q?=EC=84=B1=20=EC=BB=AC=EB=A0=89=EC=85=98=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/org/apache/catalina/SessionManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/SessionManager.java index cc2eb6b38c..f2d843a0d5 100644 --- a/tomcat/src/main/java/org/apache/catalina/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/SessionManager.java @@ -1,11 +1,11 @@ package org.apache.catalina; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class SessionManager implements Manager { - private static final Map SESSIONS = new HashMap<>(); + private static final Map SESSIONS = new ConcurrentHashMap<>(); @Override public void add(final Session session) { From 7f2ed15c14ca487bb48db8cc135b9c8e7980ae10 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 20:03:35 +0900 Subject: [PATCH 18/32] =?UTF-8?q?refactor:=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/controller/LoginController.java | 2 +- .../main/java/org/apache/catalina/Manager.java | 2 ++ .../apache/coyote/http11/Http11Processor.java | 2 +- .../coyote/http11/request/HttpRequestLine.java | 17 +++++++++++++++-- .../http11/session}/Session.java | 2 +- .../http11/session}/SessionManager.java | 4 +++- 6 files changed, 23 insertions(+), 6 deletions(-) rename tomcat/src/main/java/org/apache/{catalina => coyote/http11/session}/Session.java (90%) rename tomcat/src/main/java/org/apache/{catalina => coyote/http11/session}/SessionManager.java (87%) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index c0bab88744..ac6d26cf15 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -2,7 +2,7 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.model.User; -import org.apache.catalina.Session; +import org.apache.coyote.http11.session.Session; import org.apache.catalina.controller.HttpController; import org.apache.coyote.http11.common.HttpCookie; import org.apache.coyote.http11.request.HttpRequest; diff --git a/tomcat/src/main/java/org/apache/catalina/Manager.java b/tomcat/src/main/java/org/apache/catalina/Manager.java index 1f7377cfb1..3c833fdf70 100644 --- a/tomcat/src/main/java/org/apache/catalina/Manager.java +++ b/tomcat/src/main/java/org/apache/catalina/Manager.java @@ -1,5 +1,7 @@ package org.apache.catalina; +import org.apache.coyote.http11.session.Session; + import java.io.IOException; /** diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index 6d014e5ab1..699f82cd4d 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -5,7 +5,7 @@ import nextstep.jwp.controller.RootController; import nextstep.jwp.exception.UncheckedServletException; import org.apache.catalina.Controller; -import org.apache.catalina.SessionManager; +import org.apache.coyote.http11.session.SessionManager; import org.apache.catalina.controller.ResourceController; import org.apache.coyote.Processor; import org.apache.coyote.RequestMapping; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java index 0234515e55..cc7b5ce7de 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestLine.java @@ -1,19 +1,28 @@ package org.apache.coyote.http11.request; +import java.util.HashMap; +import java.util.Map; + public class HttpRequestLine { private final String method; private final String target; + private final Map queries; private final String version; - private HttpRequestLine(final String method, final String target, final String version) { + private HttpRequestLine(final String method, final String target, final Map queries, final String version) { this.method = method; this.target = target; + this.queries = queries; this.version = version; } public static HttpRequestLine from(final String method, final String target, final String version) { - return new HttpRequestLine(method, target, version); + return new HttpRequestLine(method, target, new HashMap<>(), version); + } + + public static HttpRequestLine from(final String method, final String target, final Map queries, final String version) { + return new HttpRequestLine(method, target, queries, version); } public String getMethod() { @@ -24,6 +33,10 @@ public String getTarget() { return target; } + public Map getQueries() { + return queries; + } + public String getVersion() { return version; } diff --git a/tomcat/src/main/java/org/apache/catalina/Session.java b/tomcat/src/main/java/org/apache/coyote/http11/session/Session.java similarity index 90% rename from tomcat/src/main/java/org/apache/catalina/Session.java rename to tomcat/src/main/java/org/apache/coyote/http11/session/Session.java index 396dde2b9e..89c33546de 100644 --- a/tomcat/src/main/java/org/apache/catalina/Session.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/session/Session.java @@ -1,4 +1,4 @@ -package org.apache.catalina; +package org.apache.coyote.http11.session; import java.util.HashMap; import java.util.Map; diff --git a/tomcat/src/main/java/org/apache/catalina/SessionManager.java b/tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java similarity index 87% rename from tomcat/src/main/java/org/apache/catalina/SessionManager.java rename to tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java index f2d843a0d5..4f1349098b 100644 --- a/tomcat/src/main/java/org/apache/catalina/SessionManager.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java @@ -1,4 +1,6 @@ -package org.apache.catalina; +package org.apache.coyote.http11.session; + +import org.apache.catalina.Manager; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; From ab7dfee437ef87b5e0609847903d6c3554775ba5 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 20:15:34 +0900 Subject: [PATCH 19/32] =?UTF-8?q?refactor:=20HttpController=EC=9D=98=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=AC=EC=B2=B4=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nextstep/jwp/controller/RootController.java | 4 ---- .../org/apache/catalina/controller/HttpController.java | 8 ++++++-- .../apache/catalina/controller/ResourceController.java | 4 ---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java index a4a0a95470..6623dcdb97 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -30,8 +30,4 @@ public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse httpResponse.setStatusCode(OK); httpResponse.setBody("Hello world!"); } - - @Override - public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { - } } diff --git a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java index 96b1d26566..580a87ba60 100644 --- a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java @@ -67,6 +67,10 @@ protected void handleResource( } public abstract boolean canHandle(final HttpRequest httpRequest); - public abstract void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException; - public abstract void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException; + + protected void doGet(final HttpRequest request, final HttpResponse response) throws Exception { + } + + protected void doPost(final HttpRequest request, final HttpResponse response) throws Exception { + } } diff --git a/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java b/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java index 34f1e7aefb..37e6bbb599 100644 --- a/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java @@ -16,8 +16,4 @@ public boolean canHandle(final HttpRequest httpRequest) { public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { handleResource(httpRequest.getTarget(), httpRequest, httpResponse); } - - @Override - public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { - } } From d6b199ccc06234eb46ed78b12bcb01979363a96a Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 20:54:14 +0900 Subject: [PATCH 20/32] =?UTF-8?q?refactor:=20session=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=9C=84=EC=B9=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/nextstep/jwp/controller/LoginController.java | 2 +- tomcat/src/main/java/org/apache/catalina/Manager.java | 2 +- .../org/apache/{coyote/http11 => catalina}/session/Session.java | 2 +- .../{coyote/http11 => catalina}/session/SessionManager.java | 2 +- .../src/main/java/org/apache/coyote/http11/Http11Processor.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename tomcat/src/main/java/org/apache/{coyote/http11 => catalina}/session/Session.java (90%) rename tomcat/src/main/java/org/apache/{coyote/http11 => catalina}/session/SessionManager.java (93%) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index ac6d26cf15..90b6d85e50 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -2,7 +2,7 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.model.User; -import org.apache.coyote.http11.session.Session; +import org.apache.catalina.session.Session; import org.apache.catalina.controller.HttpController; import org.apache.coyote.http11.common.HttpCookie; import org.apache.coyote.http11.request.HttpRequest; diff --git a/tomcat/src/main/java/org/apache/catalina/Manager.java b/tomcat/src/main/java/org/apache/catalina/Manager.java index 3c833fdf70..85abe87dda 100644 --- a/tomcat/src/main/java/org/apache/catalina/Manager.java +++ b/tomcat/src/main/java/org/apache/catalina/Manager.java @@ -1,6 +1,6 @@ package org.apache.catalina; -import org.apache.coyote.http11.session.Session; +import org.apache.catalina.session.Session; import java.io.IOException; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/session/Session.java b/tomcat/src/main/java/org/apache/catalina/session/Session.java similarity index 90% rename from tomcat/src/main/java/org/apache/coyote/http11/session/Session.java rename to tomcat/src/main/java/org/apache/catalina/session/Session.java index 89c33546de..3ebeb662a4 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/session/Session.java +++ b/tomcat/src/main/java/org/apache/catalina/session/Session.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11.session; +package org.apache.catalina.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/catalina/session/SessionManager.java similarity index 93% rename from tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java rename to tomcat/src/main/java/org/apache/catalina/session/SessionManager.java index 4f1349098b..7f4ac7aaae 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/session/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java @@ -1,4 +1,4 @@ -package org.apache.coyote.http11.session; +package org.apache.catalina.session; import org.apache.catalina.Manager; 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 699f82cd4d..0d3129222c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -5,7 +5,7 @@ import nextstep.jwp.controller.RootController; import nextstep.jwp.exception.UncheckedServletException; import org.apache.catalina.Controller; -import org.apache.coyote.http11.session.SessionManager; +import org.apache.catalina.session.SessionManager; import org.apache.catalina.controller.ResourceController; import org.apache.coyote.Processor; import org.apache.coyote.RequestMapping; From 9d1f8ff7a8be714c69a09816b2e602e4bdfd4869 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sat, 9 Sep 2023 22:26:41 +0900 Subject: [PATCH 21/32] =?UTF-8?q?test:=20coyote=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/build.gradle | 1 + .../jwp/controller/LoginController.java | 9 +- .../jwp/controller/RegisterController.java | 3 +- .../jwp/controller/RootController.java | 3 +- .../coyote/http11/common/MediaType.java | 9 +- .../common/ResourceContentTypeResolver.java | 8 +- .../http11/request/HttpRequestParser.java | 31 +++- .../coyote/http11/common/MediaTypeTest.java | 73 +++++++++ .../ResourceContentTypeResolverTest.java | 36 +++++ .../http11/common/ResourceReaderTest.java | 37 +++++ .../http11/request/HttpRequestParserTest.java | 153 ++++++++++++++++++ 11 files changed, 345 insertions(+), 18 deletions(-) create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/common/MediaTypeTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/common/ResourceReaderTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestParserTest.java diff --git a/tomcat/build.gradle b/tomcat/build.gradle index 5e2a76a777..1cae356544 100644 --- a/tomcat/build.gradle +++ b/tomcat/build.gradle @@ -21,5 +21,6 @@ dependencies { testImplementation "org.assertj:assertj-core:3.24.2" testImplementation "org.mockito:mockito-core:5.4.0" testImplementation "org.junit.jupiter:junit-jupiter-api:5.7.2" + testImplementation "org.junit.jupiter:junit-jupiter-params:5.7.2" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.7.2" } diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 90b6d85e50..073061d320 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -13,6 +13,7 @@ import static org.apache.coyote.http11.Http11Processor.sessionManager; import static org.apache.coyote.http11.common.HttpHeaderType.*; +import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; public class LoginController extends HttpController { @@ -37,7 +38,7 @@ public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse final Session session = sessionManager.findSession(sessionId); if (session != null) { // already login user httpResponse.setStatusCode(FOUND); - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); } else { // not login user handleResource("/login.html", httpRequest, httpResponse); @@ -52,14 +53,14 @@ public void doPost(final HttpRequest httpRequest, final HttpResponse httpRespons final Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); if (user.isEmpty() || !user.get().checkPassword(httpRequest.getBody().get("password"))) { // invalid user - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/401.html"); httpResponse.setStatusCode(FOUND); return; } if (sessionId != null) { // if already have session - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); httpResponse.setStatusCode(FOUND); return; @@ -71,7 +72,7 @@ public void doPost(final HttpRequest httpRequest, final HttpResponse httpRespons sessionManager.add(session); sessionId = session.getId(); - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); httpResponse.addHeader(SET_COOKIE, "JSESSIONID=" + sessionId); httpResponse.setStatusCode(FOUND); diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java index 45b9a0365f..a2956f04e6 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -14,6 +14,7 @@ import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION; +import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; public class RegisterController extends HttpController { @@ -44,7 +45,7 @@ public void doPost(final HttpRequest httpRequest, final HttpResponse httpRespons httpRequest.getBody().get("email") ); InMemoryUserRepository.save(newUser); - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); httpResponse.setStatusCode(FOUND); } diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java index 6623dcdb97..7a94b22c71 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -7,6 +7,7 @@ import java.util.*; import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; import static org.apache.coyote.http11.response.HttpStatusCode.OK; public class RootController extends HttpController { @@ -26,7 +27,7 @@ public boolean canHandle(final HttpRequest httpRequest) { @Override public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { - httpResponse.addHeader(CONTENT_TYPE, "text/html;charset=utf-8"); + httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.setStatusCode(OK); httpResponse.setBody("Hello world!"); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/common/MediaType.java b/tomcat/src/main/java/org/apache/coyote/http11/common/MediaType.java index 8640e39ad3..a2be91287a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/common/MediaType.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/MediaType.java @@ -39,12 +39,19 @@ public static MediaType getMediaType(final String mediaType) { } public static MediaType getMediaTypeByFileExtension(final String fileExtension) { + if ("js".equals(fileExtension)) { + return TEXT_JAVASCRIPT; + } return Arrays.stream(values()) .filter(mediaType -> mediaType.getSubType().equals(fileExtension)) .findFirst() .orElse(null); } + private String stringify() { + return type + "/" + subType; + } + public static boolean isSupported(final MediaType mediaType) { return mediaType != null && !mediaType.isWildCard(mediaType); } @@ -53,7 +60,7 @@ private boolean isWildCard(final MediaType mediaType) { return mediaType.equals(ALL); } - public String stringify() { + public String stringifyWithUtf() { return type + "/" + subType + ";" + "charset=utf-8"; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java index 2819ba1994..106b684314 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java @@ -25,7 +25,7 @@ private String getFirstSupportedMediaType(String headerValue) { for (String mediaTypeStr : mediaTypes) { final MediaType mediaType = MediaType.getMediaType(mediaTypeStr.trim()); if (MediaType.isSupported(mediaType)) { - return mediaTypeStr.trim(); + return mediaType.stringifyWithUtf(); } } } @@ -36,13 +36,9 @@ private String getFileExtension(final String fileName) { final int lastDotIndex = fileName.lastIndexOf('.'); if (lastDotIndex >= 0) { final String fileExtension = fileName.substring(lastDotIndex + 1); - if ("js".equals(fileExtension)) { - final MediaType jsContentType = MediaType.getMediaTypeByFileExtension("javascript"); - return jsContentType.stringify(); - } final MediaType mediaType = MediaType.getMediaTypeByFileExtension(fileExtension); if (MediaType.isSupported(mediaType)) { - return mediaType.stringify(); + return mediaType.stringifyWithUtf(); } } return null; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index 4f8e244f4b..9c0e54a42e 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -5,6 +5,7 @@ import java.io.BufferedReader; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; @@ -36,17 +37,36 @@ public HttpRequest parse() { private HttpRequestLine parseRequestLine() throws IOException { final String line = reader.readLine(); - String[] s = line.split(" "); + final String[] s = line.split(" "); + if (s[1].contains("?")) { + String[] split = s[1].split("\\?"); + Map queryString = parseQueryString(split[1]); + return HttpRequestLine.from(s[0], split[0], queryString, s[2]); + } return HttpRequestLine.from(s[0], s[1], s[2]); } + private Map parseQueryString(final String queryStrings) throws UnsupportedEncodingException { + final Map queries = new HashMap<>(); + final String[] keyValuePairs = queryStrings.split("&"); + for (String keyValuePair : keyValuePairs) { + String[] keyValue = keyValuePair.split("="); + if (keyValue.length >= 2) { + queries.put(keyValue[0], URLDecoder.decode(keyValue[1], "UTF-8")); + } + } + return queries; + } + private HttpHeaders parseRequestHeader() throws IOException { // TODO: Change to MultiValueMap final Map headers = new HashMap<>(); String line; - while (!"".equals(line = reader.readLine())) { + while (!"".equals(line = reader.readLine()) && line != null) { String[] value = line.split(": "); - headers.put(value[0], value[1]); + if (value.length >= 2) { + headers.put(value[0], value[1]); + } } final HttpHeaders httpHeaders = HttpHeaders.of(headers); final HttpCookie httpCookie = HttpCookie.of(headers.get(COOKIE.getName())); @@ -61,10 +81,11 @@ private Map parseRequestBody(final String contentLengthHeader) t char[] buffer = new char[contentLength]; reader.read(buffer, 0, contentLength); - // TODO: Query Parse for (String temp : new String(buffer).split("&")) { String[] value = temp.split("="); - body.put(value[0], URLDecoder.decode(value[1], "UTF-8")); + if (value.length >= 2) { + body.put(value[0], URLDecoder.decode(value[1], "UTF-8")); + } } return body; } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/common/MediaTypeTest.java b/tomcat/src/test/java/org/apache/coyote/http11/common/MediaTypeTest.java new file mode 100644 index 0000000000..0e0ef7fd0d --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/common/MediaTypeTest.java @@ -0,0 +1,73 @@ +package org.apache.coyote.http11.common; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +class MediaTypeTest { + + @DisplayName("String 타입의 mediaType이 들어오면, 해당 mediaType에 맞는 MediaType 객체를 반환한다.") + @ParameterizedTest(name = "''{0}'' -> {1}") + @CsvSource({ + "text/html, TEXT_HTML", + "text/javascript, TEXT_JAVASCRIPT", + "text/css, TEXT_CSS", + "image/jpeg, IMAGE_JPEG" + }) + void getMediaType(String mediaType, MediaType expected) { + // given + + // when + MediaType actual = MediaType.getMediaType(mediaType); + + // then + assertThat(actual).isEqualTo(expected); + } + + @DisplayName("지원하지 않는 String 타입의 mediaType이 들어오면, null을 반환한다.") + @Test + void getMediaType_fail() { + // given + String invalidMediaType = "not/supported"; + + // when + MediaType actual = MediaType.getMediaType(invalidMediaType); + + // then + assertThat(actual).isNull(); + } + + @DisplayName("String 타입의 fileExtenstion이 들어오면, 해당 extension에 맞는 MediaType 객체를 반환한다.") + @ParameterizedTest(name = "''{0}'' -> {1}") + @CsvSource({ + "html, TEXT_HTML", + "js, TEXT_JAVASCRIPT", + "css, TEXT_CSS", + "jpeg, IMAGE_JPEG" + }) + void getMediaTypeByFileExtension(String fileExtension, MediaType expected) { + // given + + // when + MediaType actual = MediaType.getMediaTypeByFileExtension(fileExtension); + + // then + assertThat(actual).isEqualTo(expected); + } + + @DisplayName("지원하지 않는 String 타입의 fileExtenstion이 들어오면, null을 반환한다.") + @Test + void getMediaTypeByFileExtension_fail() { + // given + String invalidFileExtension = "invalid"; + + // when + MediaType actual = MediaType.getMediaTypeByFileExtension(invalidFileExtension); + + // then + assertThat(actual).isNull(); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java b/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java new file mode 100644 index 0000000000..46f2baf197 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java @@ -0,0 +1,36 @@ +package org.apache.coyote.http11.common; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.Map; + +import static org.apache.coyote.http11.common.HttpHeaderType.ACCEPT; +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; +import static org.assertj.core.api.Assertions.assertThat; + +class ResourceContentTypeResolverTest { + + @DisplayName("요청한 HttpHeader와 resource에 맞는 contentType을 반환한다.") + @ParameterizedTest(name = "contentType: ''{0}'', accept: ''{1}'', resourceName: ''{2}'' -> {3}") + @CsvSource({ + "text/html, null, null, TEXT_HTML", + "null, text/javascript, null, TEXT_JAVASCRIPT", + "null, null, styles.css, TEXT_CSS", + }) + void getContentType(String contentType, String accept, String resourceName, MediaType expected) { + // given + HttpHeaders headers = HttpHeaders.of(Map.of( + CONTENT_TYPE.getName(), contentType, + ACCEPT.getName(), accept) + ); + + // when + ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); + String actual = resourceContentTypeResolver.getContentType(headers, resourceName); + + // then + assertThat(actual).isEqualTo(expected.stringifyWithUtf()); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceReaderTest.java b/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceReaderTest.java new file mode 100644 index 0000000000..1d2056a8d7 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceReaderTest.java @@ -0,0 +1,37 @@ +package org.apache.coyote.http11.common; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.net.URL; + +import static org.assertj.core.api.Assertions.assertThat; + +class ResourceReaderTest { + + @DisplayName("resource 요청이 들어왔을 때, 해당 리소스의 위치를 URL 객체로 반환한다.") + @Test + void getResourceUrl() { + // given + String resourceName = "/index.html"; + + // when + URL actual = ResourceReader.getResourceUrl(resourceName); + + // then + assertThat(actual.getFile()).endsWith(resourceName); + } + + @DisplayName("존재하지 않는 resource 요청이 들어왔을 때, null 을 반환한다.") + @Test + void getResourceUrl_fail() { + // given + String resourceName = "/invalid.html"; + + // when + URL actual = ResourceReader.getResourceUrl(resourceName); + + // then + assertThat(actual).isNull(); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestParserTest.java b/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestParserTest.java new file mode 100644 index 0000000000..8e9e71194d --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/request/HttpRequestParserTest.java @@ -0,0 +1,153 @@ +package org.apache.coyote.http11.request; + +import org.apache.coyote.http11.common.HttpHeaders; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +class HttpRequestParserTest { + + @DisplayName("request string을 HttpRequest 객체로 파싱한다.") + @Test + void parse() { + // given + String request = String.join("\r\n", + "GET /index.html HTTP/1.1", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding: gzip, deflate, br", + "Accept-Language: en-US,en;q=0.9", + "Connection: keep-alive", + "Host: localhost:8080", + "Referer: http://localhost:8080/index.html", + ""); + + Map headers = new HashMap<>(); + headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); + headers.put("Accept-Encoding", "gzip, deflate, br"); + headers.put("Accept-Language", "en-US,en;q=0.9"); + headers.put("Connection", "keep-alive"); + headers.put("Host", "localhost:8080"); + headers.put("Referer", "http://localhost:8080/index.html"); + + // when + BufferedReader reader = new BufferedReader(new StringReader(request)); + HttpRequestParser parser = new HttpRequestParser(reader); + HttpRequest httpRequest = parser.parse(); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpRequest).extracting("requestLine") + .usingRecursiveComparison() + .isEqualTo(HttpRequestLine.from("GET", "/index.html", "HTTP/1.1")); + softly.assertThat(httpRequest).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + softly.assertThat(httpRequest).extracting("body") + .usingRecursiveComparison() + .isEqualTo(new HashMap<>()); + } + ); + } + + @DisplayName("(queryString) request string을 HttpRequest 객체로 파싱한다.") + @Test + void parse_queryString() { + // given + String request = String.join("\r\n", + "GET /?key1=1&key2=2 HTTP/1.1", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding: gzip, deflate, br", + "Accept-Language: en-US,en;q=0.9", + "Connection: keep-alive", + "Host: localhost:8080", + ""); + + Map query = new HashMap<>(); + query.put("key1", "1"); + query.put("key2", "2"); + + Map headers = new HashMap<>(); + headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); + headers.put("Accept-Encoding", "gzip, deflate, br"); + headers.put("Accept-Language", "en-US,en;q=0.9"); + headers.put("Connection", "keep-alive"); + headers.put("Host", "localhost:8080"); + + // when + BufferedReader reader = new BufferedReader(new StringReader(request)); + HttpRequestParser parser = new HttpRequestParser(reader); + HttpRequest httpRequest = parser.parse(); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpRequest).extracting("requestLine") + .usingRecursiveComparison() + .isEqualTo(HttpRequestLine.from("GET", "/", query,"HTTP/1.1")); + softly.assertThat(httpRequest).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + softly.assertThat(httpRequest).extracting("body") + .usingRecursiveComparison() + .isEqualTo(new HashMap<>()); + } + ); + } + + @DisplayName("(body) request string을 HttpRequest 객체로 파싱한다.") + @Test + void parse_body() { + // given + String request = String.join("\r\n", + "POST /login HTTP/1.1", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + "Accept-Encoding: gzip, deflate, br", + "Accept-Language: en-US,en;q=0.9", + "Connection: keep-alive", + "Host: localhost:8080", + "Content-Length: 30", + "Content-Type: application/x-www-form-urlencoded", + "", + "account=gugu&password=password"); + + Map headers = new HashMap<>(); + headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); + headers.put("Accept-Encoding", "gzip, deflate, br"); + headers.put("Accept-Language", "en-US,en;q=0.9"); + headers.put("Connection", "keep-alive"); + headers.put("Host", "localhost:8080"); + headers.put("Content-Length", "30"); + headers.put("Content-Type", "application/x-www-form-urlencoded"); + + Map body = new HashMap<>(); + body.put("account", "gugu"); + body.put("password", "password"); + + // when + BufferedReader reader = new BufferedReader(new StringReader(request)); + HttpRequestParser parser = new HttpRequestParser(reader); + HttpRequest httpRequest = parser.parse(); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpRequest).extracting("requestLine") + .usingRecursiveComparison() + .isEqualTo(HttpRequestLine.from("POST", "/login","HTTP/1.1")); + softly.assertThat(httpRequest).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + softly.assertThat(httpRequest).extracting("body") + .usingRecursiveComparison() + .isEqualTo(body); + } + ); + } +} From 8237e9e35ca24f329b82df9141ad6530ae25b8be Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sun, 10 Sep 2023 03:37:24 +0900 Subject: [PATCH 22/32] =?UTF-8?q?test:=20Controller=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwp/controller/LoginController.java | 11 +- .../jwp/controller/RootController.java | 2 +- .../catalina/controller/HttpController.java | 12 +- .../controller/ResourceController.java | 2 +- .../apache/coyote/http11/Http11Processor.java | 2 +- .../apache/coyote/http11/HttpException.java | 8 + .../coyote/http11/request/HttpRequest.java | 5 + .../jwp/controller/LoginControllerTest.java | 250 ++++++++++++++++++ .../controller/RegisterControllerTest.java | 147 ++++++++++ .../jwp/controller/RootControllerTest.java | 93 +++++++ .../controller/ResourceControllerTest.java | 134 ++++++++++ 11 files changed, 651 insertions(+), 15 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/HttpException.java create mode 100644 tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java create mode 100644 tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java create mode 100644 tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java create mode 100644 tomcat/src/test/java/org/apache/catalina/controller/ResourceControllerTest.java diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 073061d320..7fd8934000 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -32,11 +32,10 @@ public boolean canHandle(final HttpRequest httpRequest) { } @Override - public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { - final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); + protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + final HttpCookie httpCookie = httpRequest.getCookie(); String sessionId = httpCookie.getCookie("JSESSIONID"); - final Session session = sessionManager.findSession(sessionId); - if (session != null) { // already login user + if (sessionId != null && sessionManager.findSession(sessionId) != null) { // already login user httpResponse.setStatusCode(FOUND); httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); @@ -46,8 +45,8 @@ public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse } @Override - public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { - final HttpCookie httpCookie = httpRequest.getHeaders().getCookie(); + protected void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) { + final HttpCookie httpCookie = httpRequest.getCookie(); String sessionId = httpCookie.getCookie("JSESSIONID"); final Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java index 7a94b22c71..3ea31d440e 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -26,7 +26,7 @@ public boolean canHandle(final HttpRequest httpRequest) { } @Override - public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { + protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) { httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.setStatusCode(OK); httpResponse.setBody("Hello world!"); diff --git a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java index 580a87ba60..10d9269754 100644 --- a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java @@ -1,6 +1,7 @@ package org.apache.catalina.controller; import org.apache.catalina.Controller; +import org.apache.coyote.http11.HttpException; import org.apache.coyote.http11.common.ResourceContentTypeResolver; import org.apache.coyote.http11.common.ResourceReader; import org.apache.coyote.http11.request.HttpRequest; @@ -24,10 +25,10 @@ public void destory() { } @Override - public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) { try { if (!canHandle(httpRequest)) { - throw new IllegalArgumentException("There is no controller to handle."); + throw new HttpException("There is no controller to handle."); } final String method = httpRequest.getMethod(); if ("GET".equals(method)) { @@ -36,7 +37,6 @@ public void service(final HttpRequest httpRequest, final HttpResponse httpRespon if ("POST".equals(method)) { doPost(httpRequest, httpResponse); } - // TODO: exception - invalid http method } catch (final Exception e) { httpResponse.setStatusCode(NOT_FOUND); httpResponse.setBody(e.getMessage()); @@ -50,14 +50,14 @@ protected void handleResource( ) throws IOException { final URL resourceUrl = ResourceReader.getResourceUrl(resourceName); if (resourceUrl == null) { - throw new IllegalArgumentException("The resource corresponding to the request does not exist"); + throw new HttpException("The resource corresponding to the request does not exist"); } final ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); final String contentType = resourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); if (contentType == null) { - throw new IllegalArgumentException("Content type is not supported."); + throw new HttpException("Content type is not supported."); } final String responseBody = ResourceReader.read(resourceUrl); @@ -71,6 +71,6 @@ protected void handleResource( protected void doGet(final HttpRequest request, final HttpResponse response) throws Exception { } - protected void doPost(final HttpRequest request, final HttpResponse response) throws Exception { + protected void doPost(final HttpRequest request, final HttpResponse response) { } } diff --git a/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java b/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java index 37e6bbb599..44604452b1 100644 --- a/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/ResourceController.java @@ -13,7 +13,7 @@ public boolean canHandle(final HttpRequest httpRequest) { } @Override - public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { handleResource(httpRequest.getTarget(), httpRequest, httpResponse); } } 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 0d3129222c..3b2dca7f4c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -5,8 +5,8 @@ import nextstep.jwp.controller.RootController; import nextstep.jwp.exception.UncheckedServletException; import org.apache.catalina.Controller; -import org.apache.catalina.session.SessionManager; import org.apache.catalina.controller.ResourceController; +import org.apache.catalina.session.SessionManager; import org.apache.coyote.Processor; import org.apache.coyote.RequestMapping; import org.apache.coyote.http11.request.HttpRequest; diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpException.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpException.java new file mode 100644 index 0000000000..44732ff432 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpException.java @@ -0,0 +1,8 @@ +package org.apache.coyote.http11; + +public class HttpException extends RuntimeException { + + public HttpException(final String message) { + super(message); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java index d22034faa3..6c4d3e7660 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequest.java @@ -1,5 +1,6 @@ package org.apache.coyote.http11.request; +import org.apache.coyote.http11.common.HttpCookie; import org.apache.coyote.http11.common.HttpHeaders; import java.util.Map; @@ -36,6 +37,10 @@ public HttpHeaders getHeaders() { return headers; } + public HttpCookie getCookie() { + return headers.getCookie(); + } + public Map getBody() { return body; } diff --git a/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java new file mode 100644 index 0000000000..c1d6bae3e1 --- /dev/null +++ b/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java @@ -0,0 +1,250 @@ +package nextstep.jwp.controller; + +import org.apache.catalina.session.Session; +import org.apache.coyote.http11.common.HttpCookie; +import org.apache.coyote.http11.common.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestLine; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.HttpStatusCode; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.apache.coyote.http11.Http11Processor.sessionManager; +import static org.apache.coyote.http11.common.HttpHeaderType.*; +import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +class LoginControllerTest { + + private final LoginController loginController = new LoginController(); + private final HttpHeaders httpHeadersWithNoSession = HttpHeaders.empty(); + private final HttpHeaders httpHeadersWithSession = HttpHeaders.empty(); + + @BeforeEach + void setUp() { + String uuid = String.valueOf(UUID.randomUUID()); + httpHeadersWithSession.setCookie(HttpCookie.of("JSESSIONID=" + uuid)); + Session session = new Session(uuid); + sessionManager.add(session); + } + + @DisplayName("LoginController는 정해진 request를 핸들링할 수 있다.") + @ParameterizedTest(name = "method: {0}, target: {1}") + @CsvSource({ + "POST, /login", + "GET, /login" + }) + void canHandle(String method, String target) { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from(method, target, "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = loginController.canHandle(httpRequest); + + // then + assertThat(actual).isTrue(); + } + + @DisplayName("LoginController는 정해진 request 외의 요청을 핸들링할 수 없다.") + @ParameterizedTest(name = "method: {0}, target: {1}") + @CsvSource({ + "POST, /register", + "GET, /" + }) + void canHandle_fail(String method, String target) { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from(method, target, "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = loginController.canHandle(httpRequest); + + // then + assertThat(actual).isFalse(); + } + + @DisplayName("세션이 없는 경우 GET 요청 시, login.html 리소스를 반환한다.") + @Test + void doGet_hasNoSession() throws IOException { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/login", "HTTP/1.1"), + httpHeadersWithNoSession, + new HashMap<>() + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of(CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf()); + + // when + loginController.doGet(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.OK); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } + + @DisplayName("세션이 이미 있는 경우 GET 요청 시, index.html로 redirect 한다.") + @Test + void doGet_alreadyHasSession() throws IOException { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/login", "HTTP/1.1"), + httpHeadersWithSession, + new HashMap<>() + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of( + CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), + LOCATION.getName(), "/index.html" + ); + + // when + loginController.doGet(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.FOUND); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } + + @DisplayName("유효하지 않은 계정으로 POST 요청 시, 401.html로 redirect 한다.") + @Test + void doPost_invalidAccount() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("POST", "/login", "HTTP/1.1"), + httpHeadersWithNoSession, + Map.of( + "account", "invalid_user", + "password", "invalid_password" + ) + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of( + CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), + LOCATION.getName(), "/401.html" + ); + + // when + loginController.doPost(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.FOUND); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } + + @DisplayName("세션이 이미 있는 경우 POST 요청 시, index.html로 redirect 한다.") + @Test + void doPost_alreadyHasSession() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("POST", "/login", "HTTP/1.1"), + httpHeadersWithSession, + Map.of( + "account", "gugu", + "password", "password" + ) + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of( + CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), + LOCATION.getName(), "/index.html" + ); + + // when + loginController.doPost(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.FOUND); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } + + @DisplayName("세션이 없고, 유효한 유저의 POST 요청 시, set-cookie 설정 후 index.html로 redirect 한다.") + @Test + void doPost_hasNoSessionAndValidUser() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("POST", "/login", "HTTP/1.1"), + httpHeadersWithNoSession, + Map.of( + "account", "gugu", + "password", "password" + ) + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of( + CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), + SET_COOKIE.getName(), "JSESSIONID=", + LOCATION.getName(), "/index.html" + ); + + // when + loginController.doPost(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.FOUND); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .ignoringFields( "headers.Set-Cookie") + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } +} diff --git a/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java new file mode 100644 index 0000000000..5015efd58b --- /dev/null +++ b/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java @@ -0,0 +1,147 @@ +package nextstep.jwp.controller; + +import org.apache.catalina.session.Session; +import org.apache.coyote.http11.common.HttpCookie; +import org.apache.coyote.http11.common.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestLine; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.HttpStatusCode; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static org.apache.coyote.http11.Http11Processor.sessionManager; +import static org.apache.coyote.http11.common.HttpHeaderType.*; +import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +class RegisterControllerTest { + + private final RegisterController registerController = new RegisterController(); + private final HttpHeaders httpHeadersWithNoSession = HttpHeaders.empty(); + private final HttpHeaders httpHeadersWithSession = HttpHeaders.empty(); + + @BeforeEach + void setUp() { + String uuid = String.valueOf(UUID.randomUUID()); + httpHeadersWithSession.setCookie(HttpCookie.of("JSESSIONID=" + uuid)); + Session session = new Session(uuid); + sessionManager.add(session); + } + + @DisplayName("RegisterController는 정해진 request를 핸들링할 수 있다.") + @ParameterizedTest(name = "method: {0}, target: {1}") + @CsvSource({ + "POST, /register", + "GET, /register" + }) + void canHandle(String method, String target) { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from(method, target, "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = registerController.canHandle(httpRequest); + + // then + assertThat(actual).isTrue(); + } + + @DisplayName("RegisterController는 정해진 request 외의 요청을 핸들링할 수 없다.") + @ParameterizedTest(name = "method: {0}, target: {1}") + @CsvSource({ + "POST, /login", + "GET, /" + }) + void canHandle_fail(String method, String target) { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from(method, target, "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = registerController.canHandle(httpRequest); + + // then + assertThat(actual).isFalse(); + } + + @DisplayName("GET 요청 시, register.html 리소스를 반환한다.") + @Test + void doGet_hasNoSession() throws IOException { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/register", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of(CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf()); + + // when + registerController.doGet(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.OK); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } + + @DisplayName("유효한 회원가입 정보로 POST 요청 시, 유저를 저장하고 index.html로 redirect 한다.") + @Test + void doPost() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("POST", "/login", "HTTP/1.1"), + httpHeadersWithNoSession, + Map.of( + "account", "new", + "password", "password", + "email", "new@gmail.com" + ) + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of( + CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), + LOCATION.getName(), "/index.html" + ); + + // when + registerController.doPost(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.FOUND); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } +} diff --git a/tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java new file mode 100644 index 0000000000..26dda1db9c --- /dev/null +++ b/tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java @@ -0,0 +1,93 @@ +package nextstep.jwp.controller; + +import org.apache.coyote.http11.common.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestLine; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.HttpStatusCode; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.HashMap; +import java.util.Map; + +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +class RootControllerTest { + + private final RootController rootController = new RootController(); + + @DisplayName("RootController는 정해진 request를 핸들링할 수 있다.") + @Test + void canHandle() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = rootController.canHandle(httpRequest); + + // then + assertThat(actual).isTrue(); + } + + @DisplayName("RootController는 정해진 request 외의 요청을 핸들링할 수 없다.") + @ParameterizedTest(name = "method: {0}, target: {1}") + @CsvSource({ + "POST, /", + "GET, /login" + }) + void canHandle_fail(String method, String target) { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from(method, target, "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = rootController.canHandle(httpRequest); + + // then + assertThat(actual).isFalse(); + } + + @DisplayName("GET 요청 시, 해당되는 자원을 반환한다.") + @Test + void doGet() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of(CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf()); + + // when + rootController.doGet(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.OK); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + softly.assertThat(httpResponse).extracting("body") + .isEqualTo("Hello world!"); + } + ); + } +} diff --git a/tomcat/src/test/java/org/apache/catalina/controller/ResourceControllerTest.java b/tomcat/src/test/java/org/apache/catalina/controller/ResourceControllerTest.java new file mode 100644 index 0000000000..7219729a33 --- /dev/null +++ b/tomcat/src/test/java/org/apache/catalina/controller/ResourceControllerTest.java @@ -0,0 +1,134 @@ +package org.apache.catalina.controller; + +import org.apache.coyote.http11.HttpException; +import org.apache.coyote.http11.common.HttpHeaders; +import org.apache.coyote.http11.request.HttpRequest; +import org.apache.coyote.http11.request.HttpRequestLine; +import org.apache.coyote.http11.response.HttpResponse; +import org.apache.coyote.http11.response.HttpStatusCode; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; +import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +class ResourceControllerTest { + + private final ResourceController resourceController = new ResourceController(); + @DisplayName("ResourceController는 GET 메서드를 핸들링할 수 있다.") + @Test + void canHandle() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/index.html", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = resourceController.canHandle(httpRequest); + + // then + assertThat(actual).isTrue(); + } + + @DisplayName("ResourceController는 GET 이외의 메서드를 핸들링할 수 없다.") + @Test + void canHandle_fail() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("POST", "/index.html", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + // when + boolean actual = resourceController.canHandle(httpRequest); + + // then + assertThat(actual).isFalse(); + } + + @DisplayName("GET 요청 시, 정적 리소스를 반환한다.") + @Test + void doGet() throws IOException { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/index.html", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + HttpResponse httpResponse = HttpResponse.init(); + Map headers = Map.of(CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf()); + + // when + resourceController.doGet(httpRequest, httpResponse); + + // then + assertSoftly( + softly -> { + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.OK); + softly.assertThat(httpResponse).extracting("headers") + .usingRecursiveComparison() + .isEqualTo(HttpHeaders.of(headers)); + } + ); + } + + @DisplayName("존재하지 않는 리소스에 대한 GET 요청 시, HttpException이 발생한다.") + @Test + void doGet_invalidResource() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/invalid.html", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + HttpResponse httpResponse = HttpResponse.init(); + + // when & then + assertSoftly( + softly -> { + softly.assertThatThrownBy(() -> resourceController.doGet(httpRequest, httpResponse)) + .isInstanceOf(HttpException.class); + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.NOT_FOUND); + } + ); + } + + @DisplayName("지원하지 않는 content-type의 resource에 대한 GET 요청 시, HttpException이 발생한다.") + @Test + void doGet_invalidContentType() { + // given + HttpRequest httpRequest = HttpRequest.from( + HttpRequestLine.from("GET", "/invalid.sql", "HTTP/1.1"), + HttpHeaders.empty(), + new HashMap<>() + ); + + HttpResponse httpResponse = HttpResponse.init(); + + // when & then + assertSoftly( + softly -> { + softly.assertThatThrownBy(() -> resourceController.doGet(httpRequest, httpResponse)) + .isInstanceOf(HttpException.class); + softly.assertThat(httpResponse).extracting("statusCode") + .usingRecursiveComparison() + .isEqualTo(HttpStatusCode.NOT_FOUND); + } + ); + } +} From cbd7b6916b52fc69421b96a6f6ce28f130d2734f Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sun, 10 Sep 2023 03:44:21 +0900 Subject: [PATCH 23/32] =?UTF-8?q?refactor:=20SessionManager=20=EC=8B=B1?= =?UTF-8?q?=EA=B8=80=ED=86=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/jwp/controller/LoginController.java | 8 ++++---- .../java/org/apache/catalina/session/SessionManager.java | 9 +++++++-- .../java/org/apache/coyote/http11/Http11Processor.java | 2 -- .../nextstep/jwp/controller/LoginControllerTest.java | 4 ++-- .../nextstep/jwp/controller/RegisterControllerTest.java | 4 ++-- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 7fd8934000..3d2e5ce218 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -2,8 +2,9 @@ import nextstep.jwp.db.InMemoryUserRepository; import nextstep.jwp.model.User; -import org.apache.catalina.session.Session; import org.apache.catalina.controller.HttpController; +import org.apache.catalina.session.Session; +import org.apache.catalina.session.SessionManager; import org.apache.coyote.http11.common.HttpCookie; import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; @@ -11,7 +12,6 @@ import java.io.IOException; import java.util.*; -import static org.apache.coyote.http11.Http11Processor.sessionManager; import static org.apache.coyote.http11.common.HttpHeaderType.*; import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; @@ -35,7 +35,7 @@ public boolean canHandle(final HttpRequest httpRequest) { protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { final HttpCookie httpCookie = httpRequest.getCookie(); String sessionId = httpCookie.getCookie("JSESSIONID"); - if (sessionId != null && sessionManager.findSession(sessionId) != null) { // already login user + if (sessionId != null && SessionManager.getInstance().findSession(sessionId) != null) { // already login user httpResponse.setStatusCode(FOUND); httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); @@ -68,7 +68,7 @@ protected void doPost(final HttpRequest httpRequest, final HttpResponse httpResp // if no session final Session session = new Session(String.valueOf(UUID.randomUUID())); session.setAttribute("user", user); - sessionManager.add(session); + SessionManager.getInstance().add(session); sessionId = session.getId(); httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); diff --git a/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java b/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java index 7f4ac7aaae..530a07d9aa 100644 --- a/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java +++ b/tomcat/src/main/java/org/apache/catalina/session/SessionManager.java @@ -8,6 +8,13 @@ public class SessionManager implements Manager { private static final Map SESSIONS = new ConcurrentHashMap<>(); + private static final SessionManager instance = new SessionManager(); + + private SessionManager() {} + + public static SessionManager getInstance() { + return instance; + } @Override public void add(final Session session) { @@ -23,6 +30,4 @@ public Session findSession(final String id) { public void remove(final Session session) { SESSIONS.remove(session.getId()); } - - public SessionManager() {} } 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 3b2dca7f4c..77025c99a6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -6,7 +6,6 @@ import nextstep.jwp.exception.UncheckedServletException; import org.apache.catalina.Controller; import org.apache.catalina.controller.ResourceController; -import org.apache.catalina.session.SessionManager; import org.apache.coyote.Processor; import org.apache.coyote.RequestMapping; import org.apache.coyote.http11.request.HttpRequest; @@ -26,7 +25,6 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); - public static final SessionManager sessionManager = new SessionManager(); private final Socket connection; public Http11Processor(final Socket connection) { diff --git a/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java index c1d6bae3e1..7c39fbe9e8 100644 --- a/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java +++ b/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java @@ -1,6 +1,7 @@ package nextstep.jwp.controller; import org.apache.catalina.session.Session; +import org.apache.catalina.session.SessionManager; import org.apache.coyote.http11.common.HttpCookie; import org.apache.coyote.http11.common.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; @@ -18,7 +19,6 @@ import java.util.Map; import java.util.UUID; -import static org.apache.coyote.http11.Http11Processor.sessionManager; import static org.apache.coyote.http11.common.HttpHeaderType.*; import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; import static org.assertj.core.api.Assertions.assertThat; @@ -35,7 +35,7 @@ void setUp() { String uuid = String.valueOf(UUID.randomUUID()); httpHeadersWithSession.setCookie(HttpCookie.of("JSESSIONID=" + uuid)); Session session = new Session(uuid); - sessionManager.add(session); + SessionManager.getInstance().add(session); } @DisplayName("LoginController는 정해진 request를 핸들링할 수 있다.") diff --git a/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java index 5015efd58b..fc64282b32 100644 --- a/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java +++ b/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java @@ -1,6 +1,7 @@ package nextstep.jwp.controller; import org.apache.catalina.session.Session; +import org.apache.catalina.session.SessionManager; import org.apache.coyote.http11.common.HttpCookie; import org.apache.coyote.http11.common.HttpHeaders; import org.apache.coyote.http11.request.HttpRequest; @@ -18,7 +19,6 @@ import java.util.Map; import java.util.UUID; -import static org.apache.coyote.http11.Http11Processor.sessionManager; import static org.apache.coyote.http11.common.HttpHeaderType.*; import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; import static org.assertj.core.api.Assertions.assertThat; @@ -35,7 +35,7 @@ void setUp() { String uuid = String.valueOf(UUID.randomUUID()); httpHeadersWithSession.setCookie(HttpCookie.of("JSESSIONID=" + uuid)); Session session = new Session(uuid); - sessionManager.add(session); + SessionManager.getInstance().add(session); } @DisplayName("RegisterController는 정해진 request를 핸들링할 수 있다.") From 9d6802ed37c490dfa91bd677cc113603ca017d15 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sun, 10 Sep 2023 03:52:34 +0900 Subject: [PATCH 24/32] =?UTF-8?q?refactor:=20todo=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/request/HttpRequestParser.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index 9c0e54a42e..1c8c1c9127 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -5,8 +5,8 @@ import java.io.BufferedReader; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -46,20 +46,19 @@ private HttpRequestLine parseRequestLine() throws IOException { return HttpRequestLine.from(s[0], s[1], s[2]); } - private Map parseQueryString(final String queryStrings) throws UnsupportedEncodingException { + private Map parseQueryString(final String queryStrings) { final Map queries = new HashMap<>(); final String[] keyValuePairs = queryStrings.split("&"); for (String keyValuePair : keyValuePairs) { String[] keyValue = keyValuePair.split("="); if (keyValue.length >= 2) { - queries.put(keyValue[0], URLDecoder.decode(keyValue[1], "UTF-8")); + queries.put(keyValue[0], URLDecoder.decode(keyValue[1], StandardCharsets.UTF_8)); } } return queries; } private HttpHeaders parseRequestHeader() throws IOException { - // TODO: Change to MultiValueMap final Map headers = new HashMap<>(); String line; while (!"".equals(line = reader.readLine()) && line != null) { @@ -75,7 +74,6 @@ private HttpHeaders parseRequestHeader() throws IOException { } private Map parseRequestBody(final String contentLengthHeader) throws IOException { - // TODO: Change to MultiValueMap final Map body = new HashMap<>(); int contentLength = Integer.parseInt(contentLengthHeader); char[] buffer = new char[contentLength]; @@ -84,7 +82,7 @@ private Map parseRequestBody(final String contentLengthHeader) t for (String temp : new String(buffer).split("&")) { String[] value = temp.split("="); if (value.length >= 2) { - body.put(value[0], URLDecoder.decode(value[1], "UTF-8")); + body.put(value[0], URLDecoder.decode(value[1], StandardCharsets.UTF_8)); } } return body; From a0efa423a4d7674318900f3258765c88c346d5d8 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Sun, 10 Sep 2023 04:10:20 +0900 Subject: [PATCH 25/32] =?UTF-8?q?refactor:=20RequestMapping=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/catalina/connector/Connector.java | 3 ++- .../java/org/apache/coyote/RequestMapping.java | 13 +++++++++++-- .../apache/coyote/http11/Http11Processor.java | 16 +++------------- .../coyote/http11/Http11ProcessorTest.java | 5 +++-- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java index f115714cdc..e6e05510d4 100644 --- a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java +++ b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java @@ -1,5 +1,6 @@ package org.apache.catalina.connector; +import org.apache.coyote.RequestMapping; import org.apache.coyote.http11.Http11Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,7 +73,7 @@ private void process(final Socket connection) { if (connection == null) { return; } - var processor = new Http11Processor(connection); + var processor = new Http11Processor(connection, new RequestMapping()); executor.submit(processor); } diff --git a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java index b27691b298..2f372b656a 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestMapping.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestMapping.java @@ -1,6 +1,10 @@ package org.apache.coyote; +import nextstep.jwp.controller.LoginController; +import nextstep.jwp.controller.RegisterController; +import nextstep.jwp.controller.RootController; import org.apache.catalina.controller.HttpController; +import org.apache.catalina.controller.ResourceController; import org.apache.coyote.http11.request.HttpRequest; import java.util.List; @@ -9,8 +13,13 @@ public class RequestMapping { private final List controllers; - public RequestMapping(final List controllers) { - this.controllers = controllers; + public RequestMapping() { + this.controllers = List.of( + new RootController(), + new LoginController(), + new RegisterController(), + new ResourceController() + ); } public HttpController getController(final HttpRequest httpRequest) { 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 77025c99a6..6e6c105788 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,11 +1,7 @@ package org.apache.coyote.http11; -import nextstep.jwp.controller.LoginController; -import nextstep.jwp.controller.RegisterController; -import nextstep.jwp.controller.RootController; import nextstep.jwp.exception.UncheckedServletException; import org.apache.catalina.Controller; -import org.apache.catalina.controller.ResourceController; import org.apache.coyote.Processor; import org.apache.coyote.RequestMapping; import org.apache.coyote.http11.request.HttpRequest; @@ -18,7 +14,6 @@ import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; -import java.util.List; import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; @@ -26,9 +21,11 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); private final Socket connection; + private final RequestMapping requestMapping; - public Http11Processor(final Socket connection) { + public Http11Processor(final Socket connection, final RequestMapping requestMapping) { this.connection = connection; + this.requestMapping = requestMapping; } @Override @@ -46,13 +43,6 @@ public void process(final Socket connection) { final HttpRequestParser httpRequestParser = new HttpRequestParser(reader); final HttpRequest httpRequest = httpRequestParser.parse(); - final RequestMapping requestMapping = new RequestMapping(List.of( - new RootController(), - new LoginController(), - new RegisterController(), - new ResourceController() - )); - final Controller controller = requestMapping.getController(httpRequest); final HttpResponse httpResponse = HttpResponse.init(); try { diff --git a/tomcat/src/test/java/nextstep/org/apache/coyote/http11/Http11ProcessorTest.java b/tomcat/src/test/java/nextstep/org/apache/coyote/http11/Http11ProcessorTest.java index 512b919f09..cf474dea94 100644 --- a/tomcat/src/test/java/nextstep/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/nextstep/org/apache/coyote/http11/Http11ProcessorTest.java @@ -1,5 +1,6 @@ package nextstep.org.apache.coyote.http11; +import org.apache.coyote.RequestMapping; import support.StubSocket; import org.apache.coyote.http11.Http11Processor; import org.junit.jupiter.api.Test; @@ -17,7 +18,7 @@ class Http11ProcessorTest { void process() { // given final var socket = new StubSocket(); - final var processor = new Http11Processor(socket); + final var processor = new Http11Processor(socket, new RequestMapping()); // when processor.process(socket); @@ -44,7 +45,7 @@ void index() throws IOException { ""); final var socket = new StubSocket(httpRequest); - final Http11Processor processor = new Http11Processor(socket); + final Http11Processor processor = new Http11Processor(socket, new RequestMapping()); // when processor.process(socket); From ef23b655be64e760721f8bb5e39eda890e07030e Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Mon, 11 Sep 2023 14:10:58 +0900 Subject: [PATCH 26/32] =?UTF-8?q?refactor:=20content=20type=20=ED=97=A4?= =?UTF-8?q?=EB=8D=94=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/jwp/controller/LoginController.java | 10 +++------- .../jwp/controller/RegisterController.java | 3 --- .../jwp/controller/LoginControllerTest.java | 16 +++------------- .../jwp/controller/RegisterControllerTest.java | 5 +---- 4 files changed, 7 insertions(+), 27 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 3d2e5ce218..0b7b7bd802 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -12,8 +12,8 @@ import java.io.IOException; import java.util.*; -import static org.apache.coyote.http11.common.HttpHeaderType.*; -import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; +import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION; +import static org.apache.coyote.http11.common.HttpHeaderType.SET_COOKIE; import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; public class LoginController extends HttpController { @@ -36,9 +36,8 @@ protected void doGet(final HttpRequest httpRequest, final HttpResponse httpRespo final HttpCookie httpCookie = httpRequest.getCookie(); String sessionId = httpCookie.getCookie("JSESSIONID"); if (sessionId != null && SessionManager.getInstance().findSession(sessionId) != null) { // already login user - httpResponse.setStatusCode(FOUND); - httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); + httpResponse.setStatusCode(FOUND); } else { // not login user handleResource("/login.html", httpRequest, httpResponse); } @@ -52,14 +51,12 @@ protected void doPost(final HttpRequest httpRequest, final HttpResponse httpResp final Optional user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account")); if (user.isEmpty() || !user.get().checkPassword(httpRequest.getBody().get("password"))) { // invalid user - httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/401.html"); httpResponse.setStatusCode(FOUND); return; } if (sessionId != null) { // if already have session - httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); httpResponse.setStatusCode(FOUND); return; @@ -71,7 +68,6 @@ protected void doPost(final HttpRequest httpRequest, final HttpResponse httpResp SessionManager.getInstance().add(session); sessionId = session.getId(); - httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); httpResponse.addHeader(SET_COOKIE, "JSESSIONID=" + sessionId); httpResponse.setStatusCode(FOUND); diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java index a2956f04e6..ba8543cbb2 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -12,9 +12,7 @@ import java.util.Map; import java.util.Set; -import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION; -import static org.apache.coyote.http11.common.MediaType.TEXT_HTML; import static org.apache.coyote.http11.response.HttpStatusCode.FOUND; public class RegisterController extends HttpController { @@ -45,7 +43,6 @@ public void doPost(final HttpRequest httpRequest, final HttpResponse httpRespons httpRequest.getBody().get("email") ); InMemoryUserRepository.save(newUser); - httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf()); httpResponse.addHeader(LOCATION, "/index.html"); httpResponse.setStatusCode(FOUND); } diff --git a/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java index 7c39fbe9e8..e62dd937c3 100644 --- a/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java +++ b/tomcat/src/test/java/nextstep/jwp/controller/LoginControllerTest.java @@ -120,10 +120,7 @@ void doGet_alreadyHasSession() throws IOException { ); HttpResponse httpResponse = HttpResponse.init(); - Map headers = Map.of( - CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), - LOCATION.getName(), "/index.html" - ); + Map headers = Map.of(LOCATION.getName(), "/index.html"); // when loginController.doGet(httpRequest, httpResponse); @@ -155,10 +152,7 @@ void doPost_invalidAccount() { ); HttpResponse httpResponse = HttpResponse.init(); - Map headers = Map.of( - CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), - LOCATION.getName(), "/401.html" - ); + Map headers = Map.of(LOCATION.getName(), "/401.html"); // when loginController.doPost(httpRequest, httpResponse); @@ -190,10 +184,7 @@ void doPost_alreadyHasSession() { ); HttpResponse httpResponse = HttpResponse.init(); - Map headers = Map.of( - CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), - LOCATION.getName(), "/index.html" - ); + Map headers = Map.of(LOCATION.getName(), "/index.html"); // when loginController.doPost(httpRequest, httpResponse); @@ -226,7 +217,6 @@ void doPost_hasNoSessionAndValidUser() { HttpResponse httpResponse = HttpResponse.init(); Map headers = Map.of( - CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), SET_COOKIE.getName(), "JSESSIONID=", LOCATION.getName(), "/index.html" ); diff --git a/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java index fc64282b32..9eceff2a4e 100644 --- a/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java +++ b/tomcat/src/test/java/nextstep/jwp/controller/RegisterControllerTest.java @@ -124,10 +124,7 @@ void doPost() { ); HttpResponse httpResponse = HttpResponse.init(); - Map headers = Map.of( - CONTENT_TYPE.getName(), TEXT_HTML.stringifyWithUtf(), - LOCATION.getName(), "/index.html" - ); + Map headers = Map.of(LOCATION.getName(), "/index.html"); // when registerController.doPost(httpRequest, httpResponse); From a5493f79ad534a3006065f111bb25943c6850b94 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Mon, 11 Sep 2023 23:31:37 +0900 Subject: [PATCH 27/32] =?UTF-8?q?refactor:=20exception=20handling=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/catalina/Controller.java | 4 ++- .../catalina/controller/HttpController.java | 33 +++++++++++-------- .../apache/coyote/http11/Http11Processor.java | 9 +---- .../apache/coyote/http11/HttpException.java | 24 ++++++++++++-- .../http11/response/HttpStatusCode.java | 12 ++++++- 5 files changed, 56 insertions(+), 26 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/Controller.java b/tomcat/src/main/java/org/apache/catalina/Controller.java index 4254ab5ef9..4d2b6fcb43 100644 --- a/tomcat/src/main/java/org/apache/catalina/Controller.java +++ b/tomcat/src/main/java/org/apache/catalina/Controller.java @@ -3,10 +3,12 @@ import org.apache.coyote.http11.request.HttpRequest; import org.apache.coyote.http11.response.HttpResponse; +import java.io.IOException; + public interface Controller { void init(); void destory(); - void service(HttpRequest request, HttpResponse response) throws Exception; + void service(HttpRequest request, HttpResponse response) throws IOException; } diff --git a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java index 10d9269754..0bd1d9e272 100644 --- a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java @@ -11,8 +11,8 @@ import java.net.URL; import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; -import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; -import static org.apache.coyote.http11.response.HttpStatusCode.OK; +import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION; +import static org.apache.coyote.http11.response.HttpStatusCode.*; public abstract class HttpController implements Controller { @@ -25,21 +25,24 @@ public void destory() { } @Override - public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) { + public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException { + final String method = httpRequest.getMethod(); try { - if (!canHandle(httpRequest)) { - throw new HttpException("There is no controller to handle."); - } - final String method = httpRequest.getMethod(); if ("GET".equals(method)) { doGet(httpRequest, httpResponse); } if ("POST".equals(method)) { doPost(httpRequest, httpResponse); } - } catch (final Exception e) { - httpResponse.setStatusCode(NOT_FOUND); - httpResponse.setBody(e.getMessage()); + } + catch (final HttpException e) { + if (e.getStatusCode() == NOT_FOUND) { + httpResponse.setStatusCode(NOT_FOUND); + httpResponse.addHeader(LOCATION, "/404.html"); + } else { + httpResponse.setStatusCode(e.getStatusCode()); + httpResponse.setBody(e.getMessage()); + } } } @@ -50,14 +53,14 @@ protected void handleResource( ) throws IOException { final URL resourceUrl = ResourceReader.getResourceUrl(resourceName); if (resourceUrl == null) { - throw new HttpException("The resource corresponding to the request does not exist"); + throw new HttpException(NOT_FOUND, "The resource corresponding to the request does not exist"); } final ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); final String contentType = resourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); if (contentType == null) { - throw new HttpException("Content type is not supported."); + throw new HttpException(BAD_REQUEST, "Content type is not supported."); } final String responseBody = ResourceReader.read(resourceUrl); @@ -68,9 +71,11 @@ protected void handleResource( public abstract boolean canHandle(final HttpRequest httpRequest); - protected void doGet(final HttpRequest request, final HttpResponse response) throws Exception { + protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { + response.setStatusCode(METHOD_NOT_ALLOWED); } - protected void doPost(final HttpRequest request, final HttpResponse response) { + protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { + response.setStatusCode(METHOD_NOT_ALLOWED); } } 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 6e6c105788..a04123580f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -15,8 +15,6 @@ import java.io.InputStreamReader; import java.net.Socket; -import static org.apache.coyote.http11.response.HttpStatusCode.NOT_FOUND; - public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); @@ -45,13 +43,8 @@ public void process(final Socket connection) { final Controller controller = requestMapping.getController(httpRequest); final HttpResponse httpResponse = HttpResponse.init(); - try { - controller.service(httpRequest, httpResponse); - } catch (final Exception e) { - httpResponse.setStatusCode(NOT_FOUND); - httpResponse.setBody(e.getMessage()); - } + controller.service(httpRequest, httpResponse); outputStream.write(httpResponse.stringify().getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/HttpException.java b/tomcat/src/main/java/org/apache/coyote/http11/HttpException.java index 44732ff432..bc5df2628e 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/HttpException.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/HttpException.java @@ -1,8 +1,28 @@ package org.apache.coyote.http11; +import org.apache.coyote.http11.response.HttpStatusCode; + public class HttpException extends RuntimeException { - public HttpException(final String message) { - super(message); + private final HttpStatusCode statusCode; + private final String errMsg; + + + public HttpException(final HttpStatusCode statusCode, final String errMsg) { + super(String.join("\n", + "title: " + statusCode.getMessage(), + "status: " + statusCode.getCode(), + "detail: " + errMsg)); + + this.statusCode = statusCode; + this.errMsg = errMsg; + } + + public HttpStatusCode getStatusCode() { + return statusCode; + } + + public String getErrMsg() { + return errMsg; } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java index e55a988cf6..7f6a6fb15e 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/HttpStatusCode.java @@ -4,7 +4,9 @@ public enum HttpStatusCode { OK(200, "OK"), FOUND(302, "Found"), - NOT_FOUND(404, "Not Found"); + BAD_REQUEST(400, "Bad Request"), + NOT_FOUND(404, "Not Found"), + METHOD_NOT_ALLOWED(405, "Method Not Allowed"); private final int code; private final String message; @@ -17,4 +19,12 @@ public enum HttpStatusCode { public String stringify() { return code + " " + message; } + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } } From dea46b02040feb0e402b04f9d417e401e8e065f3 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Mon, 11 Sep 2023 23:36:05 +0900 Subject: [PATCH 28/32] =?UTF-8?q?refactor:=20ResourceContentTypeResolver?= =?UTF-8?q?=20static=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=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 --- .../java/org/apache/catalina/controller/HttpController.java | 4 +--- .../coyote/http11/common/ResourceContentTypeResolver.java | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java index 0bd1d9e272..11f73c9dee 100644 --- a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java @@ -56,9 +56,7 @@ protected void handleResource( throw new HttpException(NOT_FOUND, "The resource corresponding to the request does not exist"); } - final ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); - final String contentType = resourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); - + final String contentType = ResourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); if (contentType == null) { throw new HttpException(BAD_REQUEST, "Content type is not supported."); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java index 106b684314..1da22521a5 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java @@ -5,7 +5,7 @@ public class ResourceContentTypeResolver { - public String getContentType(final HttpHeaders headers, final String resourceName) { + public static String getContentType(final HttpHeaders headers, final String resourceName) { final String contentType = getFirstSupportedMediaType(headers.getHeaderValue(CONTENT_TYPE)); if (contentType != null) { return contentType; @@ -19,7 +19,7 @@ public String getContentType(final HttpHeaders headers, final String resourceNam return getFileExtension(resourceName); } - private String getFirstSupportedMediaType(String headerValue) { + private static String getFirstSupportedMediaType(String headerValue) { if (headerValue != null) { String[] mediaTypes = headerValue.split(","); for (String mediaTypeStr : mediaTypes) { @@ -32,7 +32,7 @@ private String getFirstSupportedMediaType(String headerValue) { return null; } - private String getFileExtension(final String fileName) { + private static String getFileExtension(final String fileName) { final int lastDotIndex = fileName.lastIndexOf('.'); if (lastDotIndex >= 0) { final String fileExtension = fileName.substring(lastDotIndex + 1); From 4a969710c824bd6c7d01b0c2b6f09fb7f51303fb Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Tue, 12 Sep 2023 00:01:59 +0900 Subject: [PATCH 29/32] =?UTF-8?q?refactor:=20getResourceContentType=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../catalina/controller/HttpController.java | 9 ++------ .../common/ResourceContentTypeResolver.java | 21 ++++++------------- .../ResourceContentTypeResolverTest.java | 21 ++++++------------- 3 files changed, 14 insertions(+), 37 deletions(-) diff --git a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java index 11f73c9dee..04bfa5afe3 100644 --- a/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java +++ b/tomcat/src/main/java/org/apache/catalina/controller/HttpController.java @@ -10,8 +10,7 @@ import java.io.IOException; import java.net.URL; -import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; -import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION; +import static org.apache.coyote.http11.common.HttpHeaderType.*; import static org.apache.coyote.http11.response.HttpStatusCode.*; public abstract class HttpController implements Controller { @@ -56,11 +55,7 @@ protected void handleResource( throw new HttpException(NOT_FOUND, "The resource corresponding to the request does not exist"); } - final String contentType = ResourceContentTypeResolver.getContentType(httpRequest.getHeaders(), resourceName); - if (contentType == null) { - throw new HttpException(BAD_REQUEST, "Content type is not supported."); - } - + final String contentType = ResourceContentTypeResolver.getResourceContentType(httpRequest.getHeaders().getHeaderValue(ACCEPT), resourceName); final String responseBody = ResourceReader.read(resourceUrl); httpResponse.setStatusCode(OK); httpResponse.addHeader(CONTENT_TYPE, contentType); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java index 1da22521a5..962fdf389b 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java @@ -1,27 +1,18 @@ package org.apache.coyote.http11.common; -import static org.apache.coyote.http11.common.HttpHeaderType.ACCEPT; -import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; - public class ResourceContentTypeResolver { - public static String getContentType(final HttpHeaders headers, final String resourceName) { - final String contentType = getFirstSupportedMediaType(headers.getHeaderValue(CONTENT_TYPE)); - if (contentType != null) { - return contentType; - } - - final String acceptHeader = getFirstSupportedMediaType(headers.getHeaderValue(ACCEPT)); + public static String getResourceContentType(final String acceptValue, final String resourceName) { + final String acceptHeader = getFirstSupportedMediaType(acceptValue); if (acceptHeader != null) { return acceptHeader; } - return getFileExtension(resourceName); } - private static String getFirstSupportedMediaType(String headerValue) { - if (headerValue != null) { - String[] mediaTypes = headerValue.split(","); + private static String getFirstSupportedMediaType(final String acceptValue) { + if (acceptValue != null) { + String[] mediaTypes = acceptValue.split(","); for (String mediaTypeStr : mediaTypes) { final MediaType mediaType = MediaType.getMediaType(mediaTypeStr.trim()); if (MediaType.isSupported(mediaType)) { @@ -41,6 +32,6 @@ private static String getFileExtension(final String fileName) { return mediaType.stringifyWithUtf(); } } - return null; + return MediaType.ALL.stringifyWithUtf(); } } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java b/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java index 46f2baf197..cd0e2200c0 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/common/ResourceContentTypeResolverTest.java @@ -4,31 +4,22 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import java.util.Map; - -import static org.apache.coyote.http11.common.HttpHeaderType.ACCEPT; -import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE; import static org.assertj.core.api.Assertions.assertThat; class ResourceContentTypeResolverTest { @DisplayName("요청한 HttpHeader와 resource에 맞는 contentType을 반환한다.") - @ParameterizedTest(name = "contentType: ''{0}'', accept: ''{1}'', resourceName: ''{2}'' -> {3}") + @ParameterizedTest(name = "accept: ''{1}'', resourceName: ''{2}'' -> {3}") @CsvSource({ - "text/html, null, null, TEXT_HTML", - "null, text/javascript, null, TEXT_JAVASCRIPT", - "null, null, styles.css, TEXT_CSS", + "null, null, ALL", + "text/javascript, null, TEXT_JAVASCRIPT", + "null, styles.css, TEXT_CSS", }) - void getContentType(String contentType, String accept, String resourceName, MediaType expected) { + void getContentType(String accept, String resourceName, MediaType expected) { // given - HttpHeaders headers = HttpHeaders.of(Map.of( - CONTENT_TYPE.getName(), contentType, - ACCEPT.getName(), accept) - ); // when - ResourceContentTypeResolver resourceContentTypeResolver = new ResourceContentTypeResolver(); - String actual = resourceContentTypeResolver.getContentType(headers, resourceName); + String actual = ResourceContentTypeResolver.getResourceContentType(accept, resourceName); // then assertThat(actual).isEqualTo(expected.stringifyWithUtf()); From 1e6d57cce97ad6c7fc1c0b31740ef9ba48193a59 Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Tue, 12 Sep 2023 00:14:34 +0900 Subject: [PATCH 30/32] =?UTF-8?q?refactor:=20url=20encoded=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http11/request/HttpRequestParser.java | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index 1c8c1c9127..62d842000a 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -48,14 +48,7 @@ private HttpRequestLine parseRequestLine() throws IOException { private Map parseQueryString(final String queryStrings) { final Map queries = new HashMap<>(); - final String[] keyValuePairs = queryStrings.split("&"); - for (String keyValuePair : keyValuePairs) { - String[] keyValue = keyValuePair.split("="); - if (keyValue.length >= 2) { - queries.put(keyValue[0], URLDecoder.decode(keyValue[1], StandardCharsets.UTF_8)); - } - } - return queries; + return parseUrlEncoded(queryStrings, queries); } private HttpHeaders parseRequestHeader() throws IOException { @@ -78,13 +71,16 @@ private Map parseRequestBody(final String contentLengthHeader) t int contentLength = Integer.parseInt(contentLengthHeader); char[] buffer = new char[contentLength]; reader.read(buffer, 0, contentLength); + return parseUrlEncoded(new String(buffer), body); + } - for (String temp : new String(buffer).split("&")) { - String[] value = temp.split("="); - if (value.length >= 2) { - body.put(value[0], URLDecoder.decode(value[1], StandardCharsets.UTF_8)); + private Map parseUrlEncoded(final String queryStrings, final Map queries) { + for (String keyValuePair : queryStrings.split("&")) { + String[] keyValue = keyValuePair.split("="); + if (keyValue.length >= 2) { + queries.put(keyValue[0], URLDecoder.decode(keyValue[1], StandardCharsets.UTF_8)); } } - return body; + return queries; } } From 8039dde1108e07f4e97883f3b16412069de46f7f Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Tue, 12 Sep 2023 00:40:09 +0900 Subject: [PATCH 31/32] =?UTF-8?q?refactor:=20null=20=EB=B0=98=ED=99=98=20O?= =?UTF-8?q?ptional=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http11/common/ResourceContentTypeResolver.java | 14 ++++++-------- .../coyote/http11/request/HttpRequestParser.java | 5 +++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java index 962fdf389b..d697940555 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/common/ResourceContentTypeResolver.java @@ -1,26 +1,24 @@ package org.apache.coyote.http11.common; +import java.util.Optional; + public class ResourceContentTypeResolver { public static String getResourceContentType(final String acceptValue, final String resourceName) { - final String acceptHeader = getFirstSupportedMediaType(acceptValue); - if (acceptHeader != null) { - return acceptHeader; - } - return getFileExtension(resourceName); + return getFirstSupportedMediaType(acceptValue).orElse(getFileExtension(resourceName)); } - private static String getFirstSupportedMediaType(final String acceptValue) { + private static Optional getFirstSupportedMediaType(final String acceptValue) { if (acceptValue != null) { String[] mediaTypes = acceptValue.split(","); for (String mediaTypeStr : mediaTypes) { final MediaType mediaType = MediaType.getMediaType(mediaTypeStr.trim()); if (MediaType.isSupported(mediaType)) { - return mediaType.stringifyWithUtf(); + return Optional.of(mediaType.stringifyWithUtf()); } } } - return null; + return Optional.empty(); } private static String getFileExtension(final String fileName) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java index 62d842000a..6e8bc169b7 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/HttpRequestParser.java @@ -25,8 +25,9 @@ public HttpRequest parse() { try { final HttpRequestLine requestLine = parseRequestLine(); final HttpHeaders requestHeaders = parseRequestHeader(); - if (requestHeaders.getHeaderValue(CONTENT_LENGTH) != null) { - final Map body = parseRequestBody(requestHeaders.getHeaderValue(CONTENT_LENGTH)); + final String contentLength = requestHeaders.getHeaderValue(CONTENT_LENGTH); + if (contentLength != null) { + final Map body = parseRequestBody(contentLength); return HttpRequest.from(requestLine, requestHeaders, body); } return HttpRequest.from(requestLine, requestHeaders, new HashMap<>()); From f6e401cfc8dc8379d4d3d5d51364aa793cfcbabf Mon Sep 17 00:00:00 2001 From: mcodnjs Date: Tue, 12 Sep 2023 01:13:21 +0900 Subject: [PATCH 32/32] =?UTF-8?q?refactor:=20Controller=EC=9D=98=20handle?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/jwp/controller/LoginController.java | 11 ++--------- .../jwp/controller/RegisterController.java | 14 ++------------ .../nextstep/jwp/controller/RootController.java | 11 ++--------- .../jwp/controller/RootControllerTest.java | 2 +- 4 files changed, 7 insertions(+), 31 deletions(-) diff --git a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java index 0b7b7bd802..48acdb2147 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/LoginController.java @@ -20,15 +20,8 @@ public class LoginController extends HttpController { @Override public boolean canHandle(final HttpRequest httpRequest) { - final Map> requestType = new HashMap<>(Map.of( - "/login", new HashSet<>(Set.of("GET", "POST")) - )); - - if (requestType.containsKey(httpRequest.getTarget())) { - final Set methodType = requestType.get(httpRequest.getTarget()); - return methodType.contains(httpRequest.getMethod()); - } - return false; + final Set requestType = Set.of("/login"); + return requestType.contains(httpRequest.getTarget()); } @Override diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java index ba8543cbb2..ff57fca868 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RegisterController.java @@ -7,9 +7,6 @@ import org.apache.coyote.http11.response.HttpResponse; import java.io.IOException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; import java.util.Set; import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION; @@ -19,15 +16,8 @@ public class RegisterController extends HttpController { @Override public boolean canHandle(final HttpRequest httpRequest) { - final Map> requestType = new HashMap<>(Map.of( - "/register", new HashSet<>(Set.of("GET", "POST")) - )); - - if (requestType.containsKey(httpRequest.getTarget())) { - final Set methodType = requestType.get(httpRequest.getTarget()); - return methodType.contains(httpRequest.getMethod()); - } - return false; + final Set requestType = Set.of("/register"); + return requestType.contains(httpRequest.getTarget()); } @Override diff --git a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java index 3ea31d440e..f761b817bc 100644 --- a/tomcat/src/main/java/nextstep/jwp/controller/RootController.java +++ b/tomcat/src/main/java/nextstep/jwp/controller/RootController.java @@ -14,15 +14,8 @@ public class RootController extends HttpController { @Override public boolean canHandle(final HttpRequest httpRequest) { - final Map> requestType = new HashMap<>(Map.of( - "/", new HashSet<>(Set.of("GET")) - )); - - if (requestType.containsKey(httpRequest.getTarget())) { - final Set methodType = requestType.get(httpRequest.getTarget()); - return methodType.contains(httpRequest.getMethod()); - } - return false; + final Set requestType = Set.of("/"); + return requestType.contains(httpRequest.getTarget()); } @Override diff --git a/tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java b/tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java index 26dda1db9c..8bfe083476 100644 --- a/tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java +++ b/tomcat/src/test/java/nextstep/jwp/controller/RootControllerTest.java @@ -42,7 +42,7 @@ void canHandle() { @DisplayName("RootController는 정해진 request 외의 요청을 핸들링할 수 없다.") @ParameterizedTest(name = "method: {0}, target: {1}") @CsvSource({ - "POST, /", + "POST, /register", "GET, /login" }) void canHandle_fail(String method, String target) {