From 20b10391a9d7829b9ae76dad6efa7438ae9c6901 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 15:21:12 +0900 Subject: [PATCH 01/36] =?UTF-8?q?refactor:=20ContentType=20=EC=B6=94?= =?UTF-8?q?=EC=B6=9C=EC=9D=84=20=EC=9E=90=EB=B0=94=20Files=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http/ContentType.java | 33 ------------------- .../apache/coyote/request/HttpRequest.java | 5 ++- .../apache/coyote/request/RequestLine.java | 13 +++++--- .../apache/coyote/response/HttpResponse.java | 4 +-- 4 files changed, 13 insertions(+), 42 deletions(-) delete mode 100644 tomcat/src/main/java/org/apache/coyote/http/ContentType.java diff --git a/tomcat/src/main/java/org/apache/coyote/http/ContentType.java b/tomcat/src/main/java/org/apache/coyote/http/ContentType.java deleted file mode 100644 index e0838e42f8..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http/ContentType.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.apache.coyote.http; - -import java.util.Arrays; - -public enum ContentType { - HTML(".html", "text/html"), - CSS(".css", "text/css"), - JS(".js", "application/javascript"); - - private final String format; - private final String response; - - ContentType(String format, String response) { - this.format = format; - this.response = response; - } - - public static ContentType findByPath(String path) { - return Arrays.stream(values()) - .filter(type -> path.endsWith(type.format)) - .findFirst() - .orElse(HTML); - } - - public static boolean isStaticFile(String path) { - return Arrays.stream(values()) - .anyMatch(type -> path.endsWith(type.format)); - } - - public String getResponse() { - return response + "; charset=utf-8"; - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java index 575b174441..384161a510 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -6,9 +6,8 @@ import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; -import org.apache.coyote.http.ContentType; -import org.apache.coyote.http.HeaderName; import org.apache.coyote.coockie.HttpCookie; +import org.apache.coyote.http.HeaderName; import org.apache.coyote.http.HttpMethod; public class HttpRequest { @@ -60,7 +59,7 @@ public boolean isPathWithQuery(String path) { return requestLine.isPathWithQuery(path); } - public ContentType getContentType() { + public String getContentType() throws IOException { return requestLine.getContentType(); } diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java index 5c516a95c7..f83697a6e6 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java @@ -1,8 +1,12 @@ package org.apache.coyote.request; +import java.io.File; +import java.io.IOException; +import java.net.FileNameMap; +import java.net.URLConnection; +import java.nio.file.Files; import java.util.HashMap; import java.util.Map; -import org.apache.coyote.http.ContentType; import org.apache.coyote.http.HttpMethod; public class RequestLine { @@ -68,12 +72,13 @@ private Map mapQueryParam(String requestLineEntry) { return mappedQueryParams; } - public ContentType getContentType() { - return ContentType.findByPath(path); + public String getContentType() throws IOException { + return Files.probeContentType(new File(path).toPath()); } public boolean isStaticRequest() { - return ContentType.isStaticFile(path); + FileNameMap fileNameMap = URLConnection.getFileNameMap(); + return fileNameMap.getContentTypeFor(path) != null; } public boolean isPath(String path) { diff --git a/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java index 86ca8ca4c5..5fff4a4ed3 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java @@ -56,10 +56,10 @@ private String getHeaderResponse() { return String.valueOf(response); } - private Map mapHeader(HttpRequest httpRequest, ResourceType resourceType) { + private Map mapHeader(HttpRequest httpRequest, ResourceType resourceType) throws IOException { Map headerEntry = new HashMap<>(); headerEntry.put(HeaderName.SET_COOKIE.getValue(), httpRequest.getCookieResponse()); - headerEntry.put(HeaderName.CONTENT_TYPE.getValue(), httpRequest.getContentType().getResponse()); + headerEntry.put(HeaderName.CONTENT_TYPE.getValue(), httpRequest.getContentType()); if (resourceType == ResourceType.STATIC) { headerEntry.put(HeaderName.CONTENT_LENGTH.getValue(), String.valueOf(body.getBytes().length)); } From b8901fc13c06c58e31a0f7a2a57f82a774309c39 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 15:23:25 +0900 Subject: [PATCH 02/36] =?UTF-8?q?refactor:=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EC=9D=98=20=EC=83=81=EC=88=98=EB=AA=85?= =?UTF-8?q?=EC=9D=84=20=EB=AC=B8=EC=9E=90=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/http/StatusCode.java | 8 ++++---- .../apache/coyote/processor/Http11Processor.java | 14 +++++++------- .../org/apache/coyote/response/StatusLine.java | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http/StatusCode.java b/tomcat/src/main/java/org/apache/coyote/http/StatusCode.java index f2d9341b48..d521fda212 100644 --- a/tomcat/src/main/java/org/apache/coyote/http/StatusCode.java +++ b/tomcat/src/main/java/org/apache/coyote/http/StatusCode.java @@ -1,10 +1,10 @@ package org.apache.coyote.http; public enum StatusCode { - _200(200, "OK"), - _302(302, "FOUND"), - _401(401, "UNAUTHORIZED"), - _404(404, "NOT FOUND"), + OK(200, "OK"), + FOUND(302, "FOUND"), + UNAUTHORIZED(401, "UNAUTHORIZED"), + NOT_FOUND(404, "NOT FOUND"), ; private final int code; diff --git a/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java index b1210f30ed..7305defaa5 100644 --- a/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java @@ -52,18 +52,18 @@ public void process(final Socket connection) { if (!httpRequest.isStaticRequest()) { if (httpRequest.isPath("/")) { - httpResponse.setStatusCode(StatusCode._200); + httpResponse.setStatusCode(StatusCode.OK); httpResponse.setBody("/index.html"); } if (httpRequest.isPath("/login")) { if (httpRequest.hasSession() && sessionManager.isSessionExist(httpRequest.getJESSIONID())) { - httpResponse.setStatusCode(StatusCode._302); + httpResponse.setStatusCode(StatusCode.FOUND); httpResponse.setHeader(HeaderName.LOCATION, "/index.html"); } if (!httpRequest.hasCookie() || !httpRequest.hasJESSIONID() || !sessionManager.isSessionExist(httpRequest.getJESSIONID())) { - httpResponse.setStatusCode(StatusCode._200); + httpResponse.setStatusCode(StatusCode.OK); httpResponse.setBody("/login.html"); } } @@ -73,11 +73,11 @@ public void process(final Socket connection) { String password = httpRequest.getQueryParam("password"); Optional user = InMemoryUserRepository.findByAccount(account); if (user.isEmpty() || !user.get().checkPassword(password)) { - httpResponse.setStatusCode(StatusCode._401); + httpResponse.setStatusCode(StatusCode.UNAUTHORIZED); httpResponse.setBody("/401.html"); } if (user.isPresent() && user.get().checkPassword(password)) { - httpResponse.setStatusCode(StatusCode._302); + httpResponse.setStatusCode(StatusCode.FOUND); httpResponse.setBody("/index.html"); httpResponse.generateJSESSIONID(); Session session = new Session(httpResponse.getJESSIONID()); @@ -87,7 +87,7 @@ public void process(final Socket connection) { } if (httpRequest.isPath("/register")) { - httpResponse.setStatusCode(StatusCode._200); + httpResponse.setStatusCode(StatusCode.OK); httpResponse.setBody("/register.html"); } } @@ -101,7 +101,7 @@ public void process(final Socket connection) { String email = requestBody.get("email"); InMemoryUserRepository.save(new User(account, password, email)); - httpResponse.setStatusCode(StatusCode._302); + httpResponse.setStatusCode(StatusCode.FOUND); httpResponse.setHeader(HeaderName.LOCATION, "/index.html"); } } diff --git a/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java b/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java index 52eb959f86..6c99bee4a2 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java @@ -10,8 +10,8 @@ public class StatusLine { public StatusLine() { this.versionOfProtocol = "HTTP/1.1"; - this.statusCode = StatusCode._200.getCode(); - this.statusMessage = StatusCode._200.getMessage(); + this.statusCode = StatusCode.OK.getCode(); + this.statusMessage = StatusCode.OK.getMessage(); } public String getStatusLineResponse() { From e5da5f695db684dcc78d43051e38b0a276a85572 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 15:28:36 +0900 Subject: [PATCH 03/36] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EC=88=9C=EC=84=9C=20=EC=BB=A8=EB=B2=A4=EC=85=98=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/request/HttpRequest.java | 82 +++++++++---------- .../apache/coyote/request/RequestBody.java | 8 +- .../apache/coyote/request/RequestLine.java | 46 +++++------ .../apache/coyote/response/HttpResponse.java | 48 +++++------ 4 files changed, 92 insertions(+), 92 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java index 384161a510..5dbfd53bb5 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -27,28 +27,51 @@ public HttpRequest(InputStream inputStream) throws IOException { this.httpCookie = new HttpCookie(header.get(HeaderName.COOKIE.getValue())); } - public boolean isMethod(HttpMethod httpMethod) { - return requestLine.isMethod(httpMethod); + private Map mapHeader(BufferedReader bufferedReader) throws IOException { + Map rawHeader = new HashMap<>(); + String rawLine; + + while ((rawLine = bufferedReader.readLine()) != null && !rawLine.isEmpty()) { + String[] headerEntry = rawLine.split(": ", 2); + rawHeader.put(headerEntry[0], headerEntry[1]); + } + + return rawHeader; + } + + private RequestBody mapBody(BufferedReader bufferedReader, String bodyLength) throws IOException { + if (requestLine.isMethod(HttpMethod.POST)) { + return new RequestBody(bufferedReader, bodyLength); + } + return new RequestBody(); } public String getPath() { return requestLine.getPath(); } + public String getQueryParam(String paramName) { + return requestLine.getQueryParam(paramName); + } + + public String getContentType() throws IOException { + return requestLine.getContentType(); + } + public String get(HeaderName headerName) { return header.get(headerName.getValue()); } - public boolean hasCookie() { - return header.containsKey(HeaderName.COOKIE.getValue()); + public String getCookieResponse() { + return httpCookie.getResponse(); } - public String getQueryParam(String paramName) { - return requestLine.getQueryParam(paramName); + public String getJESSIONID() { + return httpCookie.getJESSIONID(); } - public boolean isStaticRequest() { - return requestLine.isStaticRequest(); + public boolean isMethod(HttpMethod httpMethod) { + return requestLine.isMethod(httpMethod); } public boolean isPath(String path) { @@ -59,50 +82,27 @@ public boolean isPathWithQuery(String path) { return requestLine.isPathWithQuery(path); } - public String getContentType() throws IOException { - return requestLine.getContentType(); - } - - public String getCookieResponse() { - return httpCookie.getResponse(); + public boolean isStaticRequest() { + return requestLine.isStaticRequest(); } - public boolean hasJESSIONID() { - return httpCookie.hasJESSIONID(); + public boolean hasCookie() { + return header.containsKey(HeaderName.COOKIE.getValue()); } - public String getJESSIONID() { - return httpCookie.getJESSIONID(); + public boolean hasSession() { + return hasCookie() && httpCookie.hasJESSIONID(); } - public HttpCookie getHttpCookie() { - return httpCookie; + public boolean hasJESSIONID() { + return httpCookie.hasJESSIONID(); } public RequestBody getBody() { return body; } - private Map mapHeader(BufferedReader bufferedReader) throws IOException { - Map rawHeader = new HashMap<>(); - String rawLine; - - while ((rawLine = bufferedReader.readLine()) != null && !rawLine.isEmpty()) { - String[] headerEntry = rawLine.split(": ", 2); - rawHeader.put(headerEntry[0], headerEntry[1]); - } - - return rawHeader; - } - - private RequestBody mapBody(BufferedReader bufferedReader, String bodyLength) throws IOException { - if (requestLine.isMethod(HttpMethod.POST)) { - return new RequestBody(bufferedReader, bodyLength); - } - return new RequestBody(); - } - - public boolean hasSession() { - return hasCookie() && httpCookie.hasJESSIONID(); + public HttpCookie getHttpCookie() { + return httpCookie; } } diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java b/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java index 8042a7e830..ae54daf32c 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java @@ -9,6 +9,10 @@ public class RequestBody { private final Map body; + public RequestBody() { + this.body = new HashMap<>(); + } + public RequestBody(BufferedReader bufferedReader, String bodyLength) throws IOException { this.body = mapBody(bufferedReader, bodyLength); } @@ -29,10 +33,6 @@ private Map mapBody(BufferedReader bufferedReader, String bodyLe return rawBody; } - public RequestBody() { - this.body = new HashMap<>(); - } - public String get(String key) { return body.get(key); } diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java index f83697a6e6..682696fd1a 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java @@ -29,6 +29,25 @@ public RequestLine(String requestLine) { this.versionOfProtocol = requestLineEntries[2]; } + private Map mapQueryParam(String requestLineEntry) { + Map mappedQueryParams = new HashMap<>(); + if (!requestLineEntry.contains(QUERY_INDICATOR)) { + return mappedQueryParams; + } + + int queryParamIndex = requestLineEntry.indexOf(QUERY_INDICATOR); + String queryString = requestLineEntry.substring(queryParamIndex + 1); + String[] splittedQueryString = queryString.split(QUERY_COMPONENT_DELIMITER); + + for (String queryParamEntry : splittedQueryString) { + mappedQueryParams.put( + queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[0], + queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[1] + ); + } + return mappedQueryParams; + } + private String mapPath(String path) { if (!queryParams.isEmpty()) { int queryStringIndex = path.indexOf("?"); @@ -41,10 +60,6 @@ public boolean isMethod(HttpMethod httpMethod) { return this.httpMethod == httpMethod; } - public String getPath() { - return path; - } - public boolean hasQueryParam() { return !queryParams.isEmpty(); } @@ -53,25 +68,6 @@ public String getQueryParam(String paramName) { return queryParams.get(paramName); } - private Map mapQueryParam(String requestLineEntry) { - Map mappedQueryParams = new HashMap<>(); - if (!requestLineEntry.contains(QUERY_INDICATOR)) { - return mappedQueryParams; - } - - int queryParamIndex = requestLineEntry.indexOf(QUERY_INDICATOR); - String queryString = requestLineEntry.substring(queryParamIndex + 1); - String[] splittedQueryString = queryString.split(QUERY_COMPONENT_DELIMITER); - - for (String queryParamEntry : splittedQueryString) { - mappedQueryParams.put( - queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[0], - queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[1] - ); - } - return mappedQueryParams; - } - public String getContentType() throws IOException { return Files.probeContentType(new File(path).toPath()); } @@ -88,4 +84,8 @@ public boolean isPath(String path) { public boolean isPathWithQuery(String path) { return isPath(path) && hasQueryParam(); } + + public String getPath() { + return path; + } } diff --git a/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java index 5fff4a4ed3..80c52fc9ee 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java @@ -33,6 +33,25 @@ public HttpResponse(HttpRequest httpRequest, ResourceType resourceType) throws I this.cookie = httpRequest.getHttpCookie(); } + private String mapBody(String resource) throws IOException { + StringBuilder rawBody = new StringBuilder(); + Path path = Path.of(getClass().getResource(STATIC_PATH + resource).getPath()); + + Files.readAllLines(path) + .forEach(line -> rawBody.append(line).append("\r\n")); + return String.valueOf(rawBody); + } + + private Map mapHeader(HttpRequest httpRequest, ResourceType resourceType) throws IOException { + Map headerEntry = new HashMap<>(); + headerEntry.put(HeaderName.SET_COOKIE.getValue(), httpRequest.getCookieResponse()); + headerEntry.put(HeaderName.CONTENT_TYPE.getValue(), httpRequest.getContentType()); + if (resourceType == ResourceType.STATIC) { + headerEntry.put(HeaderName.CONTENT_LENGTH.getValue(), String.valueOf(body.getBytes().length)); + } + return headerEntry; + } + public String getReponse() { StringBuilder response = new StringBuilder(); @@ -56,25 +75,6 @@ private String getHeaderResponse() { return String.valueOf(response); } - private Map mapHeader(HttpRequest httpRequest, ResourceType resourceType) throws IOException { - Map headerEntry = new HashMap<>(); - headerEntry.put(HeaderName.SET_COOKIE.getValue(), httpRequest.getCookieResponse()); - headerEntry.put(HeaderName.CONTENT_TYPE.getValue(), httpRequest.getContentType()); - if (resourceType == ResourceType.STATIC) { - headerEntry.put(HeaderName.CONTENT_LENGTH.getValue(), String.valueOf(body.getBytes().length)); - } - return headerEntry; - } - - private String mapBody(String resource) throws IOException { - StringBuilder rawBody = new StringBuilder(); - Path path = Path.of(getClass().getResource(STATIC_PATH + resource).getPath()); - - Files.readAllLines(path) - .forEach(line -> rawBody.append(line).append("\r\n")); - return String.valueOf(rawBody); - } - public void setStatusCode(StatusCode statusCode) { statusLine.setStatusCode(statusCode); } @@ -83,11 +83,6 @@ public void setHeader(HeaderName headerName, String value) { header.put(headerName.getValue(), value); } - public void setBody(String resource) throws IOException { - this.body = mapBody(resource); - header.put(HeaderName.CONTENT_LENGTH.getValue(), String.valueOf(body.getBytes().length)); - } - public void generateJSESSIONID() { cookie.generateJSESSIONID(); header.put(HeaderName.SET_COOKIE.getValue(), cookie.getResponse()); @@ -96,4 +91,9 @@ public void generateJSESSIONID() { public String getJESSIONID() { return cookie.getJESSIONID(); } + + public void setBody(String resource) throws IOException { + this.body = mapBody(resource); + header.put(HeaderName.CONTENT_LENGTH.getValue(), String.valueOf(body.getBytes().length)); + } } From 9d0b62cbb15d07a11868672ba33790560a1d5492 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:29:13 +0900 Subject: [PATCH 04/36] =?UTF-8?q?refactor:=20request=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=9B=90=EC=8B=9C=EA=B0=92=20=ED=8F=AC=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/ProtocolVersion.java | 21 +++++++++ .../apache/coyote/request/QueuryParam.java | 44 +++++++++++++++++++ .../apache/coyote/request/RequestHeader.java | 40 +++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java create mode 100644 tomcat/src/main/java/org/apache/coyote/request/QueuryParam.java create mode 100644 tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java b/tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java new file mode 100644 index 0000000000..6eaf63faf9 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java @@ -0,0 +1,21 @@ +package org.apache.coyote.http11; + +import java.util.Arrays; + +public enum ProtocolVersion { + HTTP1_1("HTTP/1.1"), + HTTP2("HTTP/2.0"); + + private final String value; + + ProtocolVersion(String value) { + this.value = value; + } + + public static ProtocolVersion findByVersion(String input) { + return Arrays.stream(values()) + .filter(version -> version.value.equals(input)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Protocol version not found - input: " + input)); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/request/QueuryParam.java b/tomcat/src/main/java/org/apache/coyote/request/QueuryParam.java new file mode 100644 index 0000000000..063ee3b15c --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/request/QueuryParam.java @@ -0,0 +1,44 @@ +package org.apache.coyote.request; + +import java.util.HashMap; +import java.util.Map; + +public class QueuryParam { + + public static final String QUERY_INDICATOR = "?"; + public static final String QUERY_COMPONENT_DELIMITER = "&"; + public static final String QUERY_COMPONENT_VALUE_DELIMITER = "="; + + private final Map params; + + public QueuryParam(String requestLineEntry) { + this.params = mapQueryParam(requestLineEntry); + } + + private Map mapQueryParam(String requestLineEntry) { + Map mappedQueryParams = new HashMap<>(); + if (!requestLineEntry.contains(QUERY_INDICATOR)) { + return mappedQueryParams; + } + + int queryParamIndex = requestLineEntry.indexOf(QUERY_INDICATOR); + String queryString = requestLineEntry.substring(queryParamIndex + 1); + String[] splittedQueryString = queryString.split(QUERY_COMPONENT_DELIMITER); + + for (String queryParamEntry : splittedQueryString) { + mappedQueryParams.put( + queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[0], + queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[1] + ); + } + return mappedQueryParams; + } + + public boolean hasQueryParam() { + return !params.isEmpty(); + } + + public String getQueryParam(String paramName) { + return params.get(paramName); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java b/tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java new file mode 100644 index 0000000000..11f1f7b7b5 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java @@ -0,0 +1,40 @@ +package org.apache.coyote.request; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.coyote.coockie.HttpCookie; +import org.apache.coyote.http.HeaderName; + +public class RequestHeader { + + private final Map header; + private final HttpCookie httpCookie; + + public RequestHeader(List headerLines) { + this.header = mapHeader(headerLines); + this.httpCookie = new HttpCookie(header.get(HeaderName.COOKIE)); + } + + private Map mapHeader(List headerLines) { + Map rawHeader = new HashMap<>(); + + for (String line : headerLines) { + String[] headerEntry = line.split(": ", 2); + rawHeader.put(HeaderName.findByName(headerEntry[0]), headerEntry[1]); + } + return rawHeader; + } + + public boolean hasSession() { + return header.containsKey(HeaderName.COOKIE) && httpCookie.hasSessionId(); + } + + public String getSessionId() { + return httpCookie.getSessionId(); + } + + public String getHttpCookie() { + return httpCookie.getResponse(); + } +} From cf1933cd0f41f72cc9fae78a233927dcba2a01d9 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:29:50 +0900 Subject: [PATCH 05/36] =?UTF-8?q?refactor:=20HttpRequest=EC=97=90=20?= =?UTF-8?q?=EC=9B=90=EC=8B=9C=EA=B0=92=20=ED=8F=AC=EC=9E=A5=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http/HeaderName.java | 9 +++ .../apache/coyote/request/HttpRequest.java | 73 ++++--------------- 2 files changed, 24 insertions(+), 58 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http/HeaderName.java b/tomcat/src/main/java/org/apache/coyote/http/HeaderName.java index 322948502c..b29f1f2c8c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http/HeaderName.java +++ b/tomcat/src/main/java/org/apache/coyote/http/HeaderName.java @@ -1,5 +1,7 @@ package org.apache.coyote.http; +import java.util.Arrays; + public enum HeaderName { CONTENT_LENGTH("Content-Length"), COOKIE("Cookie"), @@ -15,6 +17,13 @@ public enum HeaderName { this.value = value; } + public static HeaderName findByName(String name) { + return Arrays.stream(values()) + .filter(headerName -> headerName.value.equals(name)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("HeaderName not found")); + } + public String getValue() { return value; } diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java index 5dbfd53bb5..6b0961e3f2 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -1,47 +1,24 @@ package org.apache.coyote.request; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Map; -import org.apache.coyote.coockie.HttpCookie; -import org.apache.coyote.http.HeaderName; +import java.util.List; import org.apache.coyote.http.HttpMethod; public class HttpRequest { private final RequestLine requestLine; - private final Map header; - private final HttpCookie httpCookie; + private final RequestHeader header; private final RequestBody body; - public HttpRequest(InputStream inputStream) throws IOException { - InputStreamReader inputStreamReader = new InputStreamReader(inputStream); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - - this.requestLine = new RequestLine(bufferedReader.readLine()); - this.header = mapHeader(bufferedReader); - this.body = mapBody(bufferedReader, header.get(HeaderName.CONTENT_LENGTH.getValue())); - this.httpCookie = new HttpCookie(header.get(HeaderName.COOKIE.getValue())); - } - - private Map mapHeader(BufferedReader bufferedReader) throws IOException { - Map rawHeader = new HashMap<>(); - String rawLine; - - while ((rawLine = bufferedReader.readLine()) != null && !rawLine.isEmpty()) { - String[] headerEntry = rawLine.split(": ", 2); - rawHeader.put(headerEntry[0], headerEntry[1]); - } - - return rawHeader; + public HttpRequest(List headerLines, String bodyLine) { + this.requestLine = new RequestLine(headerLines.getFirst()); + this.header = new RequestHeader(headerLines); + this.body = mapBody(bodyLine); } - private RequestBody mapBody(BufferedReader bufferedReader, String bodyLength) throws IOException { + private RequestBody mapBody(String bodyLine) { if (requestLine.isMethod(HttpMethod.POST)) { - return new RequestBody(bufferedReader, bodyLength); + return new RequestBody(bodyLine); } return new RequestBody(); } @@ -58,51 +35,31 @@ public String getContentType() throws IOException { return requestLine.getContentType(); } - public String get(HeaderName headerName) { - return header.get(headerName.getValue()); - } - - public String getCookieResponse() { - return httpCookie.getResponse(); + public String getSessionId() { + return header.getSessionId(); } - public String getJESSIONID() { - return httpCookie.getJESSIONID(); + public String getHttpCookie() { + return header.getHttpCookie(); } public boolean isMethod(HttpMethod httpMethod) { return requestLine.isMethod(httpMethod); } - public boolean isPath(String path) { - return requestLine.isPath(path); - } - - public boolean isPathWithQuery(String path) { - return requestLine.isPathWithQuery(path); - } - public boolean isStaticRequest() { return requestLine.isStaticRequest(); } - public boolean hasCookie() { - return header.containsKey(HeaderName.COOKIE.getValue()); + public boolean hasQueryParam() { + return requestLine.hasQueryParam(); } public boolean hasSession() { - return hasCookie() && httpCookie.hasJESSIONID(); - } - - public boolean hasJESSIONID() { - return httpCookie.hasJESSIONID(); + return header.hasSession(); } public RequestBody getBody() { return body; } - - public HttpCookie getHttpCookie() { - return httpCookie; - } } From 1c6ee10804c5e26e5b44a0c4398d22fd18de4cf2 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:32:00 +0900 Subject: [PATCH 06/36] =?UTF-8?q?refactor:=20=EC=9E=85=EB=A0=A5=EC=9D=84?= =?UTF-8?q?=20HttpRequest=EB=A1=9C=20=EB=B3=80=ED=99=98=ED=95=98=EB=8A=94?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/RequestReader.java | 37 +++++++++++++++++++ .../apache/coyote/request/RequestBody.java | 13 ++----- 2 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/RequestReader.java diff --git a/tomcat/src/main/java/org/apache/coyote/RequestReader.java b/tomcat/src/main/java/org/apache/coyote/RequestReader.java new file mode 100644 index 0000000000..5ef134c66d --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/RequestReader.java @@ -0,0 +1,37 @@ +package org.apache.coyote; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import org.apache.coyote.request.HttpRequest; + +public class RequestReader { + + public static HttpRequest readRequest(InputStream inputStream) throws IOException { + InputStreamReader inputStreamReader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + + List headerLines = new ArrayList<>(); + String rawLine; + int contentLength = 0; + int headerCount = 0; + boolean isBody = false; + while ((rawLine = bufferedReader.readLine()) != null) { + headerLines.add(rawLine); + if (rawLine.isEmpty()) { + isBody = true; + } + if (!isBody) { + headerCount++; + } + if (rawLine.startsWith("Content-Length")) { + contentLength = Integer.parseInt(rawLine.split(": ")[1]); + } + } + String bodyLine = headerLines.get(headerCount + 1); + return new HttpRequest(headerLines, bodyLine); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java b/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java index ae54daf32c..75827379bd 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestBody.java @@ -1,7 +1,5 @@ package org.apache.coyote.request; -import java.io.BufferedReader; -import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -13,18 +11,13 @@ public RequestBody() { this.body = new HashMap<>(); } - public RequestBody(BufferedReader bufferedReader, String bodyLength) throws IOException { - this.body = mapBody(bufferedReader, bodyLength); + public RequestBody(String bodyLine) { + this.body = mapBody(bodyLine); } - private Map mapBody(BufferedReader bufferedReader, String bodyLength) throws IOException { + private Map mapBody(String bodyLine) { Map rawBody = new HashMap<>(); - int contentLength = Integer.parseInt(bodyLength); - char[] buffer = new char[contentLength]; - bufferedReader.read(buffer, 0, contentLength); - String bodyLine = new String(buffer); - String[] bodyElements = bodyLine.split("&"); for (int i = 0; i < bodyElements.length; i++) { String[] info = bodyElements[i].split("="); From a386ff37c6acf10925128d4a6d52ad46370b8ad3 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:33:04 +0900 Subject: [PATCH 07/36] =?UTF-8?q?refactor:=20response=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=9B=90=EC=8B=9C=EA=B0=92=20=ED=8F=AC=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/response/ResponseBody.java | 31 +++++++++++++++++++ .../coyote/response/ResponseHeader.java | 31 +++++++++++++++++++ .../apache/coyote/response/StatusLine.java | 20 ++++++------ 3 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java create mode 100644 tomcat/src/main/java/org/apache/coyote/response/ResponseHeader.java diff --git a/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java b/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java new file mode 100644 index 0000000000..86a4028c3b --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java @@ -0,0 +1,31 @@ +package org.apache.coyote.response; + +import java.nio.file.Files; +import java.nio.file.Path; + +public class ResponseBody { + + public static final String STATIC_PATH = "/static"; + + private final String content; + + public ResponseBody() { + this.content = ""; + } + + public void setBody(String resource) { + StringBuilder rawBody = new StringBuilder(); + Path path = Path.of(getClass().getResource(STATIC_PATH + resource).getPath()); + + Files.readAllLines(path) + .forEach(line -> rawBody.append(line).append("\r\n")); + } + + public int getLength() { + return content.length(); + } + + public String getContent() { + return content; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/response/ResponseHeader.java b/tomcat/src/main/java/org/apache/coyote/response/ResponseHeader.java new file mode 100644 index 0000000000..9079199079 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/response/ResponseHeader.java @@ -0,0 +1,31 @@ +package org.apache.coyote.response; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.apache.coyote.http.HeaderName; + +public class ResponseHeader { + + private final Map header; + + public ResponseHeader() { + this.header = new HashMap<>(); + } + + public void addHeader(HeaderName headerName, String value) { + header.put(headerName.getValue(), value); + } + + public String getResponse() { + StringBuilder response = new StringBuilder(); + + for (Entry headerEntry : header.entrySet()) { + response.append(headerEntry.getKey()) + .append(": ") + .append(headerEntry.getValue()) + .append("\r\n"); + } + return String.valueOf(response); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java b/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java index 6c99bee4a2..a626400d33 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java @@ -1,31 +1,29 @@ package org.apache.coyote.response; import org.apache.coyote.http.StatusCode; +import org.apache.coyote.http11.ProtocolVersion; public class StatusLine { - private final String versionOfProtocol; - private int statusCode; - private String statusMessage; + private final ProtocolVersion versionOfProtocol; + private StatusCode statusCode; public StatusLine() { - this.versionOfProtocol = "HTTP/1.1"; - this.statusCode = StatusCode.OK.getCode(); - this.statusMessage = StatusCode.OK.getMessage(); + this.versionOfProtocol = ProtocolVersion.HTTP1_1; + this.statusCode = StatusCode.OK; } - public String getStatusLineResponse() { + public String getResponse() { StringBuilder response = new StringBuilder(); response.append(versionOfProtocol) .append(" ") - .append(statusCode) + .append(statusCode.getCode()) .append(" ") - .append(statusMessage); + .append(statusCode.getMessage()); return String.valueOf(response); } public void setStatusCode(StatusCode statusCode) { - this.statusCode = statusCode.getCode(); - this.statusMessage = statusCode.getMessage(); + this.statusCode = statusCode; } } From 4701b0411ca0c6ae68bd34567d555a0b12ef93ca Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:33:24 +0900 Subject: [PATCH 08/36] =?UTF-8?q?refactor:=20HttpResponse=EC=97=90=20?= =?UTF-8?q?=EC=9B=90=EC=8B=9C=EA=B0=92=20=ED=8F=AC=EC=9E=A5=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/response/HttpResponse.java | 84 +++---------------- 1 file changed, 13 insertions(+), 71 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java b/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java index 80c52fc9ee..05c460a468 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java +++ b/tomcat/src/main/java/org/apache/coyote/response/HttpResponse.java @@ -1,77 +1,28 @@ package org.apache.coyote.response; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; import org.apache.coyote.http.HeaderName; -import org.apache.coyote.coockie.HttpCookie; -import org.apache.coyote.http.ResourceType; import org.apache.coyote.http.StatusCode; -import org.apache.coyote.request.HttpRequest; public class HttpResponse { - public static final String STATIC_PATH = "/static"; - private final StatusLine statusLine; - private final Map header; - private final HttpCookie cookie; - private String body; + private final ResponseHeader header; + private final ResponseBody body; - public HttpResponse(HttpRequest httpRequest, ResourceType resourceType) throws IOException { + public HttpResponse() { this.statusLine = new StatusLine(); - if (resourceType == ResourceType.NON_STATIC) { - this.body = ""; - } - if (resourceType == ResourceType.STATIC) { - this.body = mapBody(httpRequest.getPath()); - } - this.header = mapHeader(httpRequest, resourceType); - this.cookie = httpRequest.getHttpCookie(); - } - - private String mapBody(String resource) throws IOException { - StringBuilder rawBody = new StringBuilder(); - Path path = Path.of(getClass().getResource(STATIC_PATH + resource).getPath()); - - Files.readAllLines(path) - .forEach(line -> rawBody.append(line).append("\r\n")); - return String.valueOf(rawBody); - } - - private Map mapHeader(HttpRequest httpRequest, ResourceType resourceType) throws IOException { - Map headerEntry = new HashMap<>(); - headerEntry.put(HeaderName.SET_COOKIE.getValue(), httpRequest.getCookieResponse()); - headerEntry.put(HeaderName.CONTENT_TYPE.getValue(), httpRequest.getContentType()); - if (resourceType == ResourceType.STATIC) { - headerEntry.put(HeaderName.CONTENT_LENGTH.getValue(), String.valueOf(body.getBytes().length)); - } - return headerEntry; + this.header = new ResponseHeader(); + this.body = new ResponseBody(); } public String getReponse() { StringBuilder response = new StringBuilder(); - response.append(statusLine.getStatusLineResponse()) + response.append(statusLine.getResponse()) .append("\r\n") - .append(getHeaderResponse()) + .append(header.getResponse()) .append("\r\n") - .append(body); - return String.valueOf(response); - } - - private String getHeaderResponse() { - StringBuilder response = new StringBuilder(); - - for (Entry headerEntry : header.entrySet()) { - response.append(headerEntry.getKey()) - .append(": ") - .append(headerEntry.getValue()) - .append("\r\n"); - } + .append(body.getContent()); return String.valueOf(response); } @@ -79,21 +30,12 @@ public void setStatusCode(StatusCode statusCode) { statusLine.setStatusCode(statusCode); } - public void setHeader(HeaderName headerName, String value) { - header.put(headerName.getValue(), value); - } - - public void generateJSESSIONID() { - cookie.generateJSESSIONID(); - header.put(HeaderName.SET_COOKIE.getValue(), cookie.getResponse()); - } - - public String getJESSIONID() { - return cookie.getJESSIONID(); + public void addHeader(HeaderName headerName, String value) { + header.addHeader(headerName, value); } - public void setBody(String resource) throws IOException { - this.body = mapBody(resource); - header.put(HeaderName.CONTENT_LENGTH.getValue(), String.valueOf(body.getBytes().length)); + public void setBody(String resource) { + body.setBody(resource); + header.addHeader(HeaderName.CONTENT_LENGTH, String.valueOf(body.getLength())); } } From f0b3442fd0dc9c7af9eb3d1073861db27e6678af Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:34:10 +0900 Subject: [PATCH 09/36] =?UTF-8?q?refactor:=20request=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=9B=90=EC=8B=9C=EA=B0=92=20=ED=8F=AC=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/request/RequestLine.java | 50 ++++--------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java index 682696fd1a..6e9c7a6bb5 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java @@ -5,51 +5,27 @@ import java.net.FileNameMap; import java.net.URLConnection; import java.nio.file.Files; -import java.util.HashMap; -import java.util.Map; import org.apache.coyote.http.HttpMethod; public class RequestLine { - public static final String QUERY_INDICATOR = "?"; - public static final String QUERY_COMPONENT_DELIMITER = "&"; - public static final String QUERY_COMPONENT_VALUE_DELIMITER = "="; - private final HttpMethod httpMethod; private final String path; private final String versionOfProtocol; - private final Map queryParams; + private final QueuryParam queryParams; - public RequestLine(String requestLine) { - String[] requestLineEntries = requestLine.split(" "); + public RequestLine(String headerLines) { + String[] requestLineEntries = headerLines.split(" "); this.httpMethod = HttpMethod.valueOf(requestLineEntries[0]); - this.queryParams = mapQueryParam(requestLineEntries[1]); + this.queryParams = new QueuryParam(requestLineEntries[1]); this.path = mapPath(requestLineEntries[1]); this.versionOfProtocol = requestLineEntries[2]; } - private Map mapQueryParam(String requestLineEntry) { - Map mappedQueryParams = new HashMap<>(); - if (!requestLineEntry.contains(QUERY_INDICATOR)) { - return mappedQueryParams; - } - - int queryParamIndex = requestLineEntry.indexOf(QUERY_INDICATOR); - String queryString = requestLineEntry.substring(queryParamIndex + 1); - String[] splittedQueryString = queryString.split(QUERY_COMPONENT_DELIMITER); - - for (String queryParamEntry : splittedQueryString) { - mappedQueryParams.put( - queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[0], - queryParamEntry.split(QUERY_COMPONENT_VALUE_DELIMITER)[1] - ); - } - return mappedQueryParams; - } private String mapPath(String path) { - if (!queryParams.isEmpty()) { + if (queryParams.hasQueryParam()) { int queryStringIndex = path.indexOf("?"); return path.substring(0, queryStringIndex); } @@ -60,14 +36,6 @@ public boolean isMethod(HttpMethod httpMethod) { return this.httpMethod == httpMethod; } - public boolean hasQueryParam() { - return !queryParams.isEmpty(); - } - - public String getQueryParam(String paramName) { - return queryParams.get(paramName); - } - public String getContentType() throws IOException { return Files.probeContentType(new File(path).toPath()); } @@ -77,12 +45,12 @@ public boolean isStaticRequest() { return fileNameMap.getContentTypeFor(path) != null; } - public boolean isPath(String path) { - return this.path.equals(path); + public boolean hasQueryParam() { + return queryParams.hasQueryParam(); } - public boolean isPathWithQuery(String path) { - return isPath(path) && hasQueryParam(); + public String getQueryParam(String paramName) { + return queryParams.getQueryParam(paramName); } public String getPath() { From 8ff3b013069707017b9ddaca15dceeecacd60370 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:37:32 +0900 Subject: [PATCH 10/36] =?UTF-8?q?refactor:=20session=EC=9C=BC=EB=A1=9C=20s?= =?UTF-8?q?essionId=20=EC=83=9D=EC=84=B1=20=EC=B1=85=EC=9E=84=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/session/Session.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/session/Session.java b/tomcat/src/main/java/org/apache/coyote/session/Session.java index cefedb2055..71b179e577 100644 --- a/tomcat/src/main/java/org/apache/coyote/session/Session.java +++ b/tomcat/src/main/java/org/apache/coyote/session/Session.java @@ -1,19 +1,25 @@ package org.apache.coyote.session; +import com.techcourse.model.User; import java.util.HashMap; import java.util.Map; +import java.util.UUID; public class Session { private final String id; - private final Map values = new HashMap<>(); + private final Map user; - public Session(final String id) { - this.id = id; + public Session(User user) { + this.id = UUID.randomUUID().toString(); + this.user = mapUser(user); } - public void setAttribute(final String name, final Object value) { - values.put(name, value); + private Map mapUser(User user) { + Map mappedUser = new HashMap<>(); + mappedUser.put("account", user.getAccount()); + mappedUser.put("password", user.getPassword()); + return mappedUser; } public String getId() { From 73c59d37ba4d59fc5e88b8eb45765aa6397f9f26 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:38:14 +0900 Subject: [PATCH 11/36] =?UTF-8?q?refactor:=20sessionManager=EB=A1=9C=20ses?= =?UTF-8?q?sion=20=EC=83=9D=EC=84=B1=20=EC=B1=85=EC=9E=84=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/manager/SessionManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java b/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java index 04c8ba4372..377bcc4445 100644 --- a/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java +++ b/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java @@ -1,5 +1,6 @@ package org.apache.coyote.manager; +import com.techcourse.model.User; import java.util.HashMap; import java.util.Map; import org.apache.coyote.session.Session; @@ -29,4 +30,10 @@ public void remove(Session session) { public boolean isSessionExist(String id) { return SESSIONS.containsKey(id); } + + public String generateSession(User user) { + Session session = new Session(user); + add(session); + return session.getId(); + } } From d7949f4f4063287a3bf3543555796e6a3bc5f62e Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:38:24 +0900 Subject: [PATCH 12/36] =?UTF-8?q?refactor:=20sessionManager=EC=97=90=20?= =?UTF-8?q?=EC=8B=B1=EA=B8=80=ED=86=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/manager/SessionManager.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java b/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java index 377bcc4445..fe0c706c63 100644 --- a/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java +++ b/tomcat/src/main/java/org/apache/coyote/manager/SessionManager.java @@ -6,10 +6,17 @@ import org.apache.coyote.session.Session; public class SessionManager implements Manager { - // static! private static final Map SESSIONS = new HashMap<>(); + private static SessionManager instance; - public SessionManager() { + private SessionManager() { + } + + public static SessionManager getInstance() { + if (instance == null) { + return new SessionManager(); + } + return instance; } @Override From b7c16b89c052d3deccbe35fe52ff04af321a0534 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:38:38 +0900 Subject: [PATCH 13/36] =?UTF-8?q?refactor:=20getter=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/src/main/java/com/techcourse/model/User.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tomcat/src/main/java/com/techcourse/model/User.java b/tomcat/src/main/java/com/techcourse/model/User.java index e8cf4c8e68..aace600728 100644 --- a/tomcat/src/main/java/com/techcourse/model/User.java +++ b/tomcat/src/main/java/com/techcourse/model/User.java @@ -22,6 +22,14 @@ public boolean checkPassword(String password) { return this.password.equals(password); } + public Long getId() { + return id; + } + + public String getPassword() { + return password; + } + public String getAccount() { return account; } From 4d68698e094a7db5c448d4fa389f769f85d6daaa Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:38:58 +0900 Subject: [PATCH 14/36] =?UTF-8?q?refactor:=20cookie=EC=97=90=EC=84=9C=20se?= =?UTF-8?q?ssionId=20=EC=83=9D=EC=84=B1=20=EC=B1=85=EC=9E=84=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/coockie/HttpCookie.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java index eb36d20243..d6101bd6af 100644 --- a/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java @@ -3,11 +3,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import java.util.UUID; public class HttpCookie { private static final String JSESSIONID_VALUE = "JSESSIONID"; + private final Map cookies; public HttpCookie(String rawCookies) { @@ -27,18 +27,11 @@ private static Map mapCookies(String rawCookies) { return cookieGroup; } - public boolean hasJESSIONID() { + public boolean hasSessionId() { return cookies.containsKey(JSESSIONID_VALUE); } - public void generateJSESSIONID() { - if (!cookies.containsKey(JSESSIONID_VALUE)) { - UUID uuid = UUID.randomUUID(); - cookies.put(JSESSIONID_VALUE, uuid.toString()); - } - } - - public String getJESSIONID() { + public String getSessionId() { return cookies.get(JSESSIONID_VALUE); } From 246de12679e74696deb8bbefd37c745235b14502 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:43:13 +0900 Subject: [PATCH 15/36] =?UTF-8?q?refactor:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EB=A7=A4=ED=95=91=20=EC=B1=85=EC=9E=84=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http11/Dispatcher.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java b/tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java new file mode 100644 index 0000000000..a52d032b3f --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java @@ -0,0 +1,39 @@ +package org.apache.coyote.http11; + +import java.util.Map; +import org.apache.coyote.controller.Controller; +import org.apache.coyote.controller.HomeController; +import org.apache.coyote.controller.LoginController; +import org.apache.coyote.controller.RegisterController; +import org.apache.coyote.controller.StaticController; +import org.apache.coyote.http.HeaderName; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponse; + +public class Dispatcher { + + private final Map controllers; + private final Controller staticController; + + public Dispatcher() { + this.controllers = Map.of( + "/login", new LoginController(), + "/register", new RegisterController(), + "/", new HomeController() + ); + this.staticController = new StaticController(); + } + + public void run(HttpRequest httpRequest, HttpResponse httpResponse) throws Exception { + httpResponse.addHeader(HeaderName.CONTENT_TYPE, httpRequest.getContentType()); + httpResponse.addHeader(HeaderName.SET_COOKIE, httpRequest.getHttpCookie()); + + if (httpRequest.isStaticRequest()) { + staticController.service(httpRequest, httpResponse); + } + if (!httpRequest.isStaticRequest()) { + Controller controller = controllers.get(httpRequest.getPath()); + controller.service(httpRequest, httpResponse); + } + } +} From b2a79f5b5c91ee8710c374404bfabef1cc563691 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:43:55 +0900 Subject: [PATCH 16/36] =?UTF-8?q?refactor:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=B6=94=EC=83=81=ED=99=94=20=EB=B0=8F=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EB=B3=84=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/controller/AbstractController.java | 23 ++++++++ .../apache/coyote/controller/Controller.java | 9 +++ .../coyote/controller/HomeController.java | 14 +++++ .../coyote/controller/LoginController.java | 58 +++++++++++++++++++ .../coyote/controller/RegisterController.java | 30 ++++++++++ .../coyote/controller/StaticController.java | 14 +++++ 6 files changed, 148 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java create mode 100644 tomcat/src/main/java/org/apache/coyote/controller/Controller.java create mode 100644 tomcat/src/main/java/org/apache/coyote/controller/HomeController.java create mode 100644 tomcat/src/main/java/org/apache/coyote/controller/LoginController.java create mode 100644 tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java create mode 100644 tomcat/src/main/java/org/apache/coyote/controller/StaticController.java diff --git a/tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java b/tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java new file mode 100644 index 0000000000..704e1c3445 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java @@ -0,0 +1,23 @@ +package org.apache.coyote.controller; + +import org.apache.coyote.http.HttpMethod; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponse; + +public abstract class AbstractController implements Controller { + + @Override + public void service(HttpRequest request, HttpResponse response) throws Exception { + if (request.isMethod(HttpMethod.GET)) { + doGet(request, response); + } + if (request.isMethod(HttpMethod.POST)) { + doPost(request, response); + } + } + + protected void doPost(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } + + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } +} + diff --git a/tomcat/src/main/java/org/apache/coyote/controller/Controller.java b/tomcat/src/main/java/org/apache/coyote/controller/Controller.java new file mode 100644 index 0000000000..38b8bcb856 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/controller/Controller.java @@ -0,0 +1,9 @@ +package org.apache.coyote.controller; + +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponse; + +public interface Controller { + + void service(HttpRequest request, HttpResponse response) throws Exception; +} diff --git a/tomcat/src/main/java/org/apache/coyote/controller/HomeController.java b/tomcat/src/main/java/org/apache/coyote/controller/HomeController.java new file mode 100644 index 0000000000..958c3a1ed9 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/controller/HomeController.java @@ -0,0 +1,14 @@ +package org.apache.coyote.controller; + +import org.apache.coyote.http.StatusCode; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponse; + +public class HomeController extends AbstractController { + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + response.setStatusCode(StatusCode.OK); + response.setBody("/index.html"); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java new file mode 100644 index 0000000000..5dc11bc227 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java @@ -0,0 +1,58 @@ +package org.apache.coyote.controller; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; +import java.util.Optional; +import org.apache.coyote.http.HeaderName; +import org.apache.coyote.http.StatusCode; +import org.apache.coyote.manager.SessionManager; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponse; + +public class LoginController extends AbstractController { + + private final SessionManager sessionManager; + + public LoginController() { + this.sessionManager = SessionManager.getInstance(); + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) { + if (request.hasQueryParam()) { + login(request, response, sessionManager); + } + if (!request.hasQueryParam()) { + showLogin(request, response, sessionManager); + } + } + + private static void login(HttpRequest request, HttpResponse response, SessionManager sessionManager) { + String account = request.getQueryParam("account"); // TODO: dto 처리 + String password = request.getQueryParam("password"); + Optional user = InMemoryUserRepository.findByAccount(account); + + if (user.isEmpty() || !user.get().checkPassword(password)) { + response.setStatusCode(StatusCode.UNAUTHORIZED); + response.setBody("/401.html"); + } + if (user.isPresent() && user.get().checkPassword(password)) { + response.setStatusCode(StatusCode.FOUND); + response.setBody("/index.html"); + + String sessionId = sessionManager.generateSession(user.get()); + response.addHeader(HeaderName.SET_COOKIE, sessionId); + } + } + + private static void showLogin(HttpRequest request, HttpResponse response, SessionManager sessionManager) { + if (request.hasSession() && sessionManager.isSessionExist(request.getSessionId())) { + response.setStatusCode(StatusCode.FOUND); + response.addHeader(HeaderName.LOCATION, "/index.html"); + } + if (!request.hasSession() || !sessionManager.isSessionExist(request.getSessionId())) { + response.setStatusCode(StatusCode.OK); + response.setBody("/login.html"); + } + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java b/tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java new file mode 100644 index 0000000000..622dc4360d --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java @@ -0,0 +1,30 @@ +package org.apache.coyote.controller; + +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; +import org.apache.coyote.http.HeaderName; +import org.apache.coyote.http.StatusCode; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.request.RequestBody; +import org.apache.coyote.response.HttpResponse; + +public class RegisterController extends AbstractController { + + @Override + protected void doPost(HttpRequest request, HttpResponse response) { + RequestBody requestBody = request.getBody(); + String account = requestBody.get("account"); // TODO: DTO + String password = requestBody.get("password"); + String email = requestBody.get("email"); + InMemoryUserRepository.save(new User(account, password, email)); + + response.setStatusCode(StatusCode.FOUND); + response.addHeader(HeaderName.LOCATION, "/index.html"); + } + + @Override + protected void doGet(HttpRequest request, HttpResponse response) { + response.setStatusCode(StatusCode.OK); + response.setBody("/register.html"); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/controller/StaticController.java b/tomcat/src/main/java/org/apache/coyote/controller/StaticController.java new file mode 100644 index 0000000000..1e733772ee --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/controller/StaticController.java @@ -0,0 +1,14 @@ +package org.apache.coyote.controller; + +import org.apache.coyote.http.StatusCode; +import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.response.HttpResponse; + +public class StaticController extends AbstractController { + + @Override + protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + response.setStatusCode(StatusCode.OK); + response.setBody(request.getPath()); + } +} From 1620cd53cfa702bb06c1e69bca44b631cd226a4a Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:44:04 +0900 Subject: [PATCH 17/36] =?UTF-8?q?refactor:=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=20=EC=B1=85=EC=9E=84=20=EB=B0=8F=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD,=20=EC=9D=91=EB=8B=B5=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/processor/Http11Processor.java | 82 ++----------------- 1 file changed, 7 insertions(+), 75 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java index 7305defaa5..191763cfd6 100644 --- a/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java @@ -1,21 +1,13 @@ package org.apache.coyote.processor; -import com.techcourse.db.InMemoryUserRepository; import com.techcourse.exception.UncheckedServletException; -import com.techcourse.model.User; import java.io.IOException; import java.net.Socket; -import java.util.Optional; -import org.apache.coyote.http.HeaderName; -import org.apache.coyote.http.HttpMethod; -import org.apache.coyote.http.ResourceType; -import org.apache.coyote.http.StatusCode; +import org.apache.coyote.Processor; +import org.apache.coyote.RequestReader; +import org.apache.coyote.http11.Dispatcher; import org.apache.coyote.request.HttpRequest; import org.apache.coyote.response.HttpResponse; -import org.apache.coyote.request.RequestBody; -import org.apache.coyote.session.Session; -import org.apache.coyote.manager.SessionManager; -import org.apache.coyote.Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,11 +16,9 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); private final Socket connection; - private final SessionManager sessionManager; public Http11Processor(final Socket connection) { this.connection = connection; - this.sessionManager = new SessionManager(); } @Override @@ -42,69 +32,11 @@ public void process(final Socket connection) { try (final var inputStream = connection.getInputStream(); final var outputStream = connection.getOutputStream()) { - HttpRequest httpRequest = new HttpRequest(inputStream); - HttpResponse httpResponse = new HttpResponse(httpRequest, ResourceType.NON_STATIC); - - if (httpRequest.isMethod(HttpMethod.GET)) { - if (httpRequest.isStaticRequest()) { - httpResponse = new HttpResponse(httpRequest, ResourceType.STATIC); - } - - if (!httpRequest.isStaticRequest()) { - if (httpRequest.isPath("/")) { - httpResponse.setStatusCode(StatusCode.OK); - httpResponse.setBody("/index.html"); - } - - if (httpRequest.isPath("/login")) { - if (httpRequest.hasSession() && sessionManager.isSessionExist(httpRequest.getJESSIONID())) { - httpResponse.setStatusCode(StatusCode.FOUND); - httpResponse.setHeader(HeaderName.LOCATION, "/index.html"); - } - if (!httpRequest.hasCookie() || !httpRequest.hasJESSIONID() - || !sessionManager.isSessionExist(httpRequest.getJESSIONID())) { - httpResponse.setStatusCode(StatusCode.OK); - httpResponse.setBody("/login.html"); - } - } - - if (httpRequest.isPathWithQuery("/login")) { - String account = httpRequest.getQueryParam("account"); - String password = httpRequest.getQueryParam("password"); - Optional user = InMemoryUserRepository.findByAccount(account); - if (user.isEmpty() || !user.get().checkPassword(password)) { - httpResponse.setStatusCode(StatusCode.UNAUTHORIZED); - httpResponse.setBody("/401.html"); - } - if (user.isPresent() && user.get().checkPassword(password)) { - httpResponse.setStatusCode(StatusCode.FOUND); - httpResponse.setBody("/index.html"); - httpResponse.generateJSESSIONID(); - Session session = new Session(httpResponse.getJESSIONID()); - session.setAttribute("user", user.get()); - sessionManager.add(session); - } - } - - if (httpRequest.isPath("/register")) { - httpResponse.setStatusCode(StatusCode.OK); - httpResponse.setBody("/register.html"); - } - } - } - - if (httpRequest.isMethod(HttpMethod.POST)) { - if (httpRequest.isPath("/register")) { - RequestBody requestBody = httpRequest.getBody(); - String account = requestBody.get("account"); - String password = requestBody.get("password"); - String email = requestBody.get("email"); - InMemoryUserRepository.save(new User(account, password, email)); + HttpRequest httpRequest = RequestReader.readRequest(inputStream); + HttpResponse httpResponse = new HttpResponse(); - httpResponse.setStatusCode(StatusCode.FOUND); - httpResponse.setHeader(HeaderName.LOCATION, "/index.html"); - } - } + Dispatcher dispatcher = new Dispatcher(); + dispatcher.run(httpRequest, httpResponse); outputStream.write(httpResponse.getReponse().getBytes()); outputStream.flush(); From 1bd2ac58ca603a64d3f14e47d3630accd59ca6d8 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Thu, 12 Sep 2024 22:44:16 +0900 Subject: [PATCH 18/36] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/http/ResourceType.java | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 tomcat/src/main/java/org/apache/coyote/http/ResourceType.java diff --git a/tomcat/src/main/java/org/apache/coyote/http/ResourceType.java b/tomcat/src/main/java/org/apache/coyote/http/ResourceType.java deleted file mode 100644 index 33978d65b5..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/http/ResourceType.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.apache.coyote.http; - -public enum ResourceType { - NON_STATIC, STATIC -} From 26f425fe602ba4bf6584204eff0521f94fbdc42d Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 08:05:08 +0900 Subject: [PATCH 19/36] =?UTF-8?q?refactor:=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/RequestReader.java | 27 ++++++++++--------- .../coyote/controller/AbstractController.java | 9 ++++--- .../apache/coyote/controller/Controller.java | 2 +- .../coyote/controller/HomeController.java | 2 +- .../coyote/controller/StaticController.java | 2 +- .../org/apache/coyote/http11/Dispatcher.java | 2 +- .../apache/coyote/request/HttpRequest.java | 2 +- .../apache/coyote/request/RequestLine.java | 8 ++++-- .../apache/coyote/response/ResponseBody.java | 15 +++++++---- 9 files changed, 41 insertions(+), 28 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/RequestReader.java b/tomcat/src/main/java/org/apache/coyote/RequestReader.java index 5ef134c66d..b2ec029d32 100644 --- a/tomcat/src/main/java/org/apache/coyote/RequestReader.java +++ b/tomcat/src/main/java/org/apache/coyote/RequestReader.java @@ -10,28 +10,29 @@ public class RequestReader { - public static HttpRequest readRequest(InputStream inputStream) throws IOException { + public static HttpRequest readRequest(InputStream inputStream) { InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); List headerLines = new ArrayList<>(); String rawLine; - int contentLength = 0; int headerCount = 0; - boolean isBody = false; - while ((rawLine = bufferedReader.readLine()) != null) { - headerLines.add(rawLine); - if (rawLine.isEmpty()) { - isBody = true; - } - if (!isBody) { - headerCount++; - } - if (rawLine.startsWith("Content-Length")) { - contentLength = Integer.parseInt(rawLine.split(": ")[1]); + try { + boolean isBody = false; + while ((rawLine = bufferedReader.readLine()) != null) { + headerLines.add(rawLine); + if (rawLine.isEmpty()) { + isBody = true; + } + if (!isBody) { + headerCount++; + } } + } catch (IOException e) { + throw new InternalError("Internal error when read input"); } String bodyLine = headerLines.get(headerCount + 1); + return new HttpRequest(headerLines, bodyLine); } } diff --git a/tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java b/tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java index 704e1c3445..996689650a 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/AbstractController.java @@ -7,17 +7,20 @@ public abstract class AbstractController implements Controller { @Override - public void service(HttpRequest request, HttpResponse response) throws Exception { + public void service(HttpRequest request, HttpResponse response) { if (request.isMethod(HttpMethod.GET)) { doGet(request, response); + return; } if (request.isMethod(HttpMethod.POST)) { doPost(request, response); + return; } + throw new IllegalArgumentException("HttpMethod not found"); } - protected void doPost(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } + protected void doPost(HttpRequest request, HttpResponse response) { /* NOOP */ } - protected void doGet(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ } + protected void doGet(HttpRequest request, HttpResponse response) { /* NOOP */ } } diff --git a/tomcat/src/main/java/org/apache/coyote/controller/Controller.java b/tomcat/src/main/java/org/apache/coyote/controller/Controller.java index 38b8bcb856..d97ddb99bb 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/Controller.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/Controller.java @@ -5,5 +5,5 @@ public interface Controller { - void service(HttpRequest request, HttpResponse response) throws Exception; + void service(HttpRequest request, HttpResponse response); } diff --git a/tomcat/src/main/java/org/apache/coyote/controller/HomeController.java b/tomcat/src/main/java/org/apache/coyote/controller/HomeController.java index 958c3a1ed9..7b47ba6fdd 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/HomeController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/HomeController.java @@ -7,7 +7,7 @@ public class HomeController extends AbstractController { @Override - protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + protected void doGet(HttpRequest request, HttpResponse response) { response.setStatusCode(StatusCode.OK); response.setBody("/index.html"); } diff --git a/tomcat/src/main/java/org/apache/coyote/controller/StaticController.java b/tomcat/src/main/java/org/apache/coyote/controller/StaticController.java index 1e733772ee..8611504b89 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/StaticController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/StaticController.java @@ -7,7 +7,7 @@ public class StaticController extends AbstractController { @Override - protected void doGet(HttpRequest request, HttpResponse response) throws Exception { + protected void doGet(HttpRequest request, HttpResponse response) { response.setStatusCode(StatusCode.OK); response.setBody(request.getPath()); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java b/tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java index a52d032b3f..ee0807aef8 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Dispatcher.java @@ -24,7 +24,7 @@ public Dispatcher() { this.staticController = new StaticController(); } - public void run(HttpRequest httpRequest, HttpResponse httpResponse) throws Exception { + public void run(HttpRequest httpRequest, HttpResponse httpResponse) { httpResponse.addHeader(HeaderName.CONTENT_TYPE, httpRequest.getContentType()); httpResponse.addHeader(HeaderName.SET_COOKIE, httpRequest.getHttpCookie()); diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java index 6b0961e3f2..ae8cc66c2a 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -31,7 +31,7 @@ public String getQueryParam(String paramName) { return requestLine.getQueryParam(paramName); } - public String getContentType() throws IOException { + public String getContentType() { return requestLine.getContentType(); } diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java index 6e9c7a6bb5..da3557eff9 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java @@ -36,8 +36,12 @@ public boolean isMethod(HttpMethod httpMethod) { return this.httpMethod == httpMethod; } - public String getContentType() throws IOException { - return Files.probeContentType(new File(path).toPath()); + public String getContentType() { + try { + return Files.probeContentType(new File(path).toPath()); + } catch (IOException e) { + throw new IllegalArgumentException("Not found path"); + } } public boolean isStaticRequest() { diff --git a/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java b/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java index 86a4028c3b..cf8fca5890 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java +++ b/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java @@ -1,5 +1,6 @@ package org.apache.coyote.response; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -7,7 +8,7 @@ public class ResponseBody { public static final String STATIC_PATH = "/static"; - private final String content; + private String content; public ResponseBody() { this.content = ""; @@ -15,10 +16,14 @@ public ResponseBody() { public void setBody(String resource) { StringBuilder rawBody = new StringBuilder(); - Path path = Path.of(getClass().getResource(STATIC_PATH + resource).getPath()); - - Files.readAllLines(path) - .forEach(line -> rawBody.append(line).append("\r\n")); + try { + Path path = Path.of(getClass().getResource(STATIC_PATH + resource).getPath()); + Files.readAllLines(path) + .forEach(line -> rawBody.append(line).append("\r\n")); + } catch (NullPointerException | IOException e) { + throw new IllegalArgumentException("Not found resource"); + } + content = rawBody.toString(); } public int getLength() { From f448cc02adb49f46564572f3545d27fad8347761 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 10:57:47 +0900 Subject: [PATCH 20/36] =?UTF-8?q?refactor:=20=EC=BF=A0=ED=82=A4=EA=B0=80?= =?UTF-8?q?=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/coockie/HttpCookie.java | 12 +++++++++--- .../apache/coyote/request/RequestHeader.java | 19 +++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java index d6101bd6af..b88ae5b460 100644 --- a/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java @@ -10,6 +10,10 @@ public class HttpCookie { private final Map cookies; + public HttpCookie() { + this.cookies = new HashMap<>(); + } + public HttpCookie(String rawCookies) { this.cookies = mapCookies(rawCookies); } @@ -19,9 +23,11 @@ private static Map mapCookies(String rawCookies) { if (rawCookies != null && !rawCookies.isBlank()) { String[] cookiesElements = rawCookies.split("; "); - for (int i = 0; i < cookiesElements.length; i++) { - String[] cookiePair = cookiesElements[i].split("="); - cookieGroup.put(cookiePair[0], cookiePair[1]); + if (cookiesElements.length > 1) { + for (int i = 0; i < cookiesElements.length; i++) { + String[] cookiePair = cookiesElements[i].split("="); + cookieGroup.put(cookiePair[0], cookiePair[1]); + } } } return cookieGroup; diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java b/tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java index 11f1f7b7b5..1b478cd98b 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestHeader.java @@ -8,26 +8,33 @@ public class RequestHeader { - private final Map header; + private final Map header; private final HttpCookie httpCookie; public RequestHeader(List headerLines) { this.header = mapHeader(headerLines); - this.httpCookie = new HttpCookie(header.get(HeaderName.COOKIE)); + this.httpCookie = mapCookie(); } - private Map mapHeader(List headerLines) { - Map rawHeader = new HashMap<>(); + private HttpCookie mapCookie() { + if (header.containsKey(HeaderName.COOKIE.getValue())) { + return new HttpCookie(header.get(HeaderName.COOKIE.getValue())); + } + return new HttpCookie(); + } + + private Map mapHeader(List headerLines) { + Map rawHeader = new HashMap<>(); for (String line : headerLines) { String[] headerEntry = line.split(": ", 2); - rawHeader.put(HeaderName.findByName(headerEntry[0]), headerEntry[1]); + rawHeader.put(headerEntry[0], headerEntry[1]); } return rawHeader; } public boolean hasSession() { - return header.containsKey(HeaderName.COOKIE) && httpCookie.hasSessionId(); + return header.containsKey(HeaderName.COOKIE.getValue()) && httpCookie.hasSessionId(); } public String getSessionId() { From 31ab060676e7aa10688ded4998d2187e0af4cbe1 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 10:59:16 +0900 Subject: [PATCH 21/36] =?UTF-8?q?refactor:=20=EC=83=81=EC=88=98=EA=B0=92?= =?UTF-8?q?=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/http11/ProtocolVersion.java | 9 ++------- .../main/java/org/apache/coyote/response/StatusLine.java | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java b/tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java index 6eaf63faf9..1955a3942c 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/ProtocolVersion.java @@ -1,7 +1,5 @@ package org.apache.coyote.http11; -import java.util.Arrays; - public enum ProtocolVersion { HTTP1_1("HTTP/1.1"), HTTP2("HTTP/2.0"); @@ -12,10 +10,7 @@ public enum ProtocolVersion { this.value = value; } - public static ProtocolVersion findByVersion(String input) { - return Arrays.stream(values()) - .filter(version -> version.value.equals(input)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Protocol version not found - input: " + input)); + public String getValue() { + return value; } } diff --git a/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java b/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java index a626400d33..189b283e71 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java +++ b/tomcat/src/main/java/org/apache/coyote/response/StatusLine.java @@ -15,7 +15,7 @@ public StatusLine() { public String getResponse() { StringBuilder response = new StringBuilder(); - response.append(versionOfProtocol) + response.append(versionOfProtocol.getValue()) .append(" ") .append(statusCode.getCode()) .append(" ") From 15e1ae396ab52e705d74e619a44aaabedf7db4ea Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 11:00:00 +0900 Subject: [PATCH 22/36] =?UTF-8?q?fix:=20favicon=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/request/RequestLine.java | 10 ++++++---- .../java/org/apache/coyote/response/ResponseBody.java | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java index da3557eff9..350fa4d465 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestLine.java @@ -2,9 +2,8 @@ import java.io.File; import java.io.IOException; -import java.net.FileNameMap; -import java.net.URLConnection; import java.nio.file.Files; +import java.nio.file.Paths; import org.apache.coyote.http.HttpMethod; public class RequestLine { @@ -45,8 +44,11 @@ public String getContentType() { } public boolean isStaticRequest() { - FileNameMap fileNameMap = URLConnection.getFileNameMap(); - return fileNameMap.getContentTypeFor(path) != null; + try { + return Files.probeContentType(Paths.get(path)) != null; + } catch (IOException e) { + return false; + } } public boolean hasQueryParam() { diff --git a/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java b/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java index cf8fca5890..105921ce7b 100644 --- a/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java +++ b/tomcat/src/main/java/org/apache/coyote/response/ResponseBody.java @@ -15,6 +15,11 @@ public ResponseBody() { } public void setBody(String resource) { + if ("/favicon.ico".equals(resource)) { + content = ""; + return; + } + StringBuilder rawBody = new StringBuilder(); try { Path path = Path.of(getClass().getResource(STATIC_PATH + resource).getPath()); From 3fabd20445335f0da328a9ea4d7b37a405f7637f Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 11:02:41 +0900 Subject: [PATCH 23/36] =?UTF-8?q?fix:=20header=20=EB=A7=A4=ED=95=91=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/request/HttpRequest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java index ae8cc66c2a..d372935685 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -1,6 +1,5 @@ package org.apache.coyote.request; -import java.io.IOException; import java.util.List; import org.apache.coyote.http.HttpMethod; @@ -12,7 +11,7 @@ public class HttpRequest { public HttpRequest(List headerLines, String bodyLine) { this.requestLine = new RequestLine(headerLines.getFirst()); - this.header = new RequestHeader(headerLines); + this.header = new RequestHeader(headerLines.subList(1, headerLines.size())); this.body = mapBody(bodyLine); } From baa5bd43f4b1fa83053407f4a0734fd12b80f06a Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 11:03:19 +0900 Subject: [PATCH 24/36] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/RequestReader.java | 38 --------------- .../coyote/processor/Http11Processor.java | 2 +- .../apache/coyote/request/RequestReader.java | 46 +++++++++++++++++++ 3 files changed, 47 insertions(+), 39 deletions(-) delete mode 100644 tomcat/src/main/java/org/apache/coyote/RequestReader.java create mode 100644 tomcat/src/main/java/org/apache/coyote/request/RequestReader.java diff --git a/tomcat/src/main/java/org/apache/coyote/RequestReader.java b/tomcat/src/main/java/org/apache/coyote/RequestReader.java deleted file mode 100644 index b2ec029d32..0000000000 --- a/tomcat/src/main/java/org/apache/coyote/RequestReader.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.apache.coyote; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import org.apache.coyote.request.HttpRequest; - -public class RequestReader { - - public static HttpRequest readRequest(InputStream inputStream) { - InputStreamReader inputStreamReader = new InputStreamReader(inputStream); - BufferedReader bufferedReader = new BufferedReader(inputStreamReader); - - List headerLines = new ArrayList<>(); - String rawLine; - int headerCount = 0; - try { - boolean isBody = false; - while ((rawLine = bufferedReader.readLine()) != null) { - headerLines.add(rawLine); - if (rawLine.isEmpty()) { - isBody = true; - } - if (!isBody) { - headerCount++; - } - } - } catch (IOException e) { - throw new InternalError("Internal error when read input"); - } - String bodyLine = headerLines.get(headerCount + 1); - - return new HttpRequest(headerLines, bodyLine); - } -} diff --git a/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java index 191763cfd6..c7260d3a59 100644 --- a/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/processor/Http11Processor.java @@ -4,9 +4,9 @@ import java.io.IOException; import java.net.Socket; import org.apache.coyote.Processor; -import org.apache.coyote.RequestReader; import org.apache.coyote.http11.Dispatcher; import org.apache.coyote.request.HttpRequest; +import org.apache.coyote.request.RequestReader; import org.apache.coyote.response.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/tomcat/src/main/java/org/apache/coyote/request/RequestReader.java b/tomcat/src/main/java/org/apache/coyote/request/RequestReader.java new file mode 100644 index 0000000000..6925b67851 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/request/RequestReader.java @@ -0,0 +1,46 @@ +package org.apache.coyote.request; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +public class RequestReader { + + public static HttpRequest readRequest(InputStream inputStream) { + InputStreamReader inputStreamReader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + + List headerLines = new ArrayList<>(); + String rawLine; + String contentLengthHeader = ""; + try { + while ((rawLine = bufferedReader.readLine()) != null && !rawLine.isEmpty()) { + headerLines.add(rawLine); + + if (rawLine.startsWith("Content-Length")) { + contentLengthHeader = rawLine.split(": ")[1]; + } + } + + String bodyLine = ""; + if (!contentLengthHeader.isEmpty()) { + bodyLine = readBody(bufferedReader, contentLengthHeader); + } + + return new HttpRequest(headerLines, bodyLine); + + } catch (IOException e) { + throw new IllegalStateException("Error reading input stream", e); + } + } + + private static String readBody(BufferedReader bufferedReader, String contentLengthHeader) throws IOException { + int contentLength = Integer.parseInt(contentLengthHeader); + char[] buffer = new char[contentLength]; + bufferedReader.read(buffer, 0, contentLength); // 본문을 버퍼로 읽어들임 + return new String(buffer); // 읽은 버퍼를 문자열로 변환 + } +} From aa8bdbf982060da894623c4208cdfe90722fdc6e Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 11:03:33 +0900 Subject: [PATCH 25/36] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/coockie/HttpCookieTest.java | 55 +++++++++++++++++++ .../coyote/request/QueuryParamTest.java | 21 +++++++ .../coyote/request/RequestBodyTest.java | 15 +++++ .../coyote/request/RequestHeaderTest.java | 22 ++++++++ .../coyote/request/RequestLineTest.java | 39 +++++++++++++ .../coyote/request/RequestReaderTest.java | 31 +++++++++++ .../coyote/response/HttpResponseTest.java | 47 ++++++++++++++++ .../coyote/response/ResponseBodyTest.java | 19 +++++++ .../coyote/response/ResponseHeaderTest.java | 20 +++++++ .../coyote/response/StatusLineTest.java | 19 +++++++ 10 files changed, 288 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/coyote/coockie/HttpCookieTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/request/QueuryParamTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/request/RequestBodyTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/request/RequestHeaderTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/request/RequestLineTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/response/HttpResponseTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/response/ResponseBodyTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/response/ResponseHeaderTest.java create mode 100644 tomcat/src/test/java/org/apache/coyote/response/StatusLineTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/coockie/HttpCookieTest.java b/tomcat/src/test/java/org/apache/coyote/coockie/HttpCookieTest.java new file mode 100644 index 0000000000..101a9a1f94 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/coockie/HttpCookieTest.java @@ -0,0 +1,55 @@ +package org.apache.coyote.coockie; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; + +class HttpCookieTest { + + @Test + void 세션이_있으면_true() { + // given + String rawCookies = "JSESSIONID=1234; wrongCookie=value"; + + // when + HttpCookie httpCookie = new HttpCookie(rawCookies); + + // then + assertThat(httpCookie.hasSessionId()).isTrue(); + } + + @Test + void 세션이_없으면_false() { + // given + String rawCookies = "wrongCookie=value"; + + // when + HttpCookie httpCookie = new HttpCookie(rawCookies); + + // then + assertThat(httpCookie.hasSessionId()).isFalse(); + } + + @Test + void 세션ID를_반환한다() { + // given + String rawCookies = "JSESSIONID=1234;"; + + // when + HttpCookie httpCookie = new HttpCookie(rawCookies); + + // then + assertThat(httpCookie.getSessionId()).isEqualTo("1234;"); + } + + @Test + void 쿠키_문자열을_반환한다() { + // given + String rawCookies = "JSESSIONID=1234;"; + + // when + HttpCookie httpCookie = new HttpCookie(rawCookies); + + // then + assertThat(httpCookie.getResponse()).contains("JSESSIONID=1234;"); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/request/QueuryParamTest.java b/tomcat/src/test/java/org/apache/coyote/request/QueuryParamTest.java new file mode 100644 index 0000000000..835a948993 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/request/QueuryParamTest.java @@ -0,0 +1,21 @@ +package org.apache.coyote.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class QueuryParamTest { + + @Test + void hasQueryParam() { + QueuryParam queuryParam = new QueuryParam("GET /index.html?name=kirby&part=backend HTTP/1.1"); + assertThat(queuryParam.hasQueryParam()).isTrue(); + } + + @Test + void getQueryParam() { + QueuryParam queuryParam = new QueuryParam("GET /index.html?name=kirby&part=backend HTTP/1.1"); + assertThat(queuryParam.getQueryParam("name")).isEqualTo("kirby"); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/request/RequestBodyTest.java b/tomcat/src/test/java/org/apache/coyote/request/RequestBodyTest.java new file mode 100644 index 0000000000..756c4c534e --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/request/RequestBodyTest.java @@ -0,0 +1,15 @@ +package org.apache.coyote.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class RequestBodyTest { + + @Test + void get() { + RequestBody requestBody = new RequestBody("account=account&password=password&email=email"); + assertThat(requestBody.get("account")).isEqualTo("account"); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/request/RequestHeaderTest.java b/tomcat/src/test/java/org/apache/coyote/request/RequestHeaderTest.java new file mode 100644 index 0000000000..1f982c12bf --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/request/RequestHeaderTest.java @@ -0,0 +1,22 @@ +package org.apache.coyote.request; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class RequestHeaderTest { + + @Test + void hasSession() { + // given + List headerLines = List.of("Cookie: JSESSIONID=1234"); + RequestHeader requestHeader = new RequestHeader(headerLines); + + // when + boolean actual = requestHeader.hasSession(); + + // then + assertThat(actual).isTrue(); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/request/RequestLineTest.java b/tomcat/src/test/java/org/apache/coyote/request/RequestLineTest.java new file mode 100644 index 0000000000..fea726836e --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/request/RequestLineTest.java @@ -0,0 +1,39 @@ +package org.apache.coyote.request; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.coyote.http.HttpMethod; +import org.junit.jupiter.api.Test; + +class RequestLineTest { + + @Test + void isMethod() { + RequestLine requestLine = new RequestLine("GET /index.html HTTP/1.1"); + assertThat(requestLine.isMethod(HttpMethod.GET)).isTrue(); + } + + @Test + void getContentType() { + RequestLine requestLine = new RequestLine("GET /index.html HTTP/1.1"); + assertThat(requestLine.getContentType()).isEqualTo("text/html"); + } + + @Test + void isStaticRequest() { + RequestLine requestLine = new RequestLine("GET /index.html HTTP/1.1"); + assertThat(requestLine.isStaticRequest()).isTrue(); + } + + @Test + void hasQueryParam() { + RequestLine requestLine = new RequestLine("GET /index.html?name=kirby HTTP/1.1"); + assertThat(requestLine.hasQueryParam()).isTrue(); + } + + @Test + void getQueryParam() { + RequestLine requestLine = new RequestLine("GET /index.html?name=kirby HTTP/1.1"); + assertThat(requestLine.getQueryParam("name")).isEqualTo("kirby"); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java b/tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java new file mode 100644 index 0000000000..e1afbd9b3c --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java @@ -0,0 +1,31 @@ +package org.apache.coyote.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import org.junit.jupiter.api.Test; + +class RequestReaderTest { + @Test // TODO: RequestReader 클래스의 readRequest 메서드를 테스트하는 코드를 작성하라. + void 요청을_읽는다() { + // given + String mockHttpRequest = "GET /index.html HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "User-Agent: Test\r\n" + + "\r\n" + + "account=gugu"; // HTTP 헤더 끝에 바디가 붙음 + + ByteArrayInputStream inputStream = new ByteArrayInputStream(mockHttpRequest.getBytes(StandardCharsets.UTF_8)); + + // when + HttpRequest httpRequest = RequestReader.readRequest(inputStream); + + // then + assertAll( + () -> assertThat(httpRequest.getPath()).isEqualTo("/index"), + () -> assertThat(httpRequest.getBody().get("account")).isEqualTo("gugu") + ); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/response/HttpResponseTest.java b/tomcat/src/test/java/org/apache/coyote/response/HttpResponseTest.java new file mode 100644 index 0000000000..32a627ed7e --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/response/HttpResponseTest.java @@ -0,0 +1,47 @@ +package org.apache.coyote.response; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.coyote.http.HeaderName; +import org.apache.coyote.http.StatusCode; +import org.junit.jupiter.api.Test; + +class HttpResponseTest { + + @Test + void 상태코드를_추가한다() { + // given + HttpResponse response = new HttpResponse(); + + // when + response.setStatusCode(StatusCode.OK); + + // then + String expected = "HTTP/1.1 200 OK\r\n"; + assertThat(response.getReponse()).startsWith(expected); + } + + @Test + void 헤더를_추가한다() { + // given + HttpResponse response = new HttpResponse(); + + // when + response.addHeader(HeaderName.CONTENT_TYPE, "text/html"); + + // then + assertThat(response.getReponse()).contains("Content-Type: text/html"); + } + + @Test + void 바디를_추가한다() { + // given + HttpResponse response = new HttpResponse(); + + // when + response.setBody("/index.html"); + + // then + assertThat(response.getReponse()).contains("대시보드"); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/response/ResponseBodyTest.java b/tomcat/src/test/java/org/apache/coyote/response/ResponseBodyTest.java new file mode 100644 index 0000000000..9f16c17bd0 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/response/ResponseBodyTest.java @@ -0,0 +1,19 @@ +package org.apache.coyote.response; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class ResponseBodyTest { + @Test + void body를_추가한다() { + // given + ResponseBody responseBody = new ResponseBody(); + + // when + responseBody.setBody("/index.html"); + + // then + assertThat(responseBody.getContent()).isNotEmpty(); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/response/ResponseHeaderTest.java b/tomcat/src/test/java/org/apache/coyote/response/ResponseHeaderTest.java new file mode 100644 index 0000000000..3f575452d4 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/response/ResponseHeaderTest.java @@ -0,0 +1,20 @@ +package org.apache.coyote.response; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.coyote.http.HeaderName; +import org.junit.jupiter.api.Test; + +class ResponseHeaderTest { + @Test + void 헤더_요소를_추가한다() { + // given + ResponseHeader responseHeader = new ResponseHeader(); + + // when + responseHeader.addHeader(HeaderName.CONTENT_TYPE, "text/html"); + + // then + assertThat(responseHeader.getResponse()).isEqualTo("Content-Type: text/html\r\n"); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/response/StatusLineTest.java b/tomcat/src/test/java/org/apache/coyote/response/StatusLineTest.java new file mode 100644 index 0000000000..cd06411390 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/response/StatusLineTest.java @@ -0,0 +1,19 @@ +package org.apache.coyote.response; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class StatusLineTest { + @Test + void statusLine의_응답을_생성한다() { + // given + StatusLine statusLine = new StatusLine(); + + // when + String response = statusLine.getResponse(); + + // then + assertThat(response).isEqualTo("HTTP/1.1 200 OK"); + } +} From a5a7384280ffde7c9f7c6554cb6a621c182b0b61 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 11:51:16 +0900 Subject: [PATCH 26/36] =?UTF-8?q?refactor:=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 --- .../java/org/apache/coyote/controller/LoginController.java | 4 ++-- .../java/org/apache/coyote/controller/RegisterController.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java index 5dc11bc227..baa0631ab0 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java @@ -28,7 +28,7 @@ protected void doGet(HttpRequest request, HttpResponse response) { } private static void login(HttpRequest request, HttpResponse response, SessionManager sessionManager) { - String account = request.getQueryParam("account"); // TODO: dto 처리 + String account = request.getQueryParam("account"); String password = request.getQueryParam("password"); Optional user = InMemoryUserRepository.findByAccount(account); @@ -47,7 +47,7 @@ private static void login(HttpRequest request, HttpResponse response, SessionMan private static void showLogin(HttpRequest request, HttpResponse response, SessionManager sessionManager) { if (request.hasSession() && sessionManager.isSessionExist(request.getSessionId())) { - response.setStatusCode(StatusCode.FOUND); + response.setStatusCode(StatusCode.FOUND); // response.addHeader(HeaderName.LOCATION, "/index.html"); } if (!request.hasSession() || !sessionManager.isSessionExist(request.getSessionId())) { diff --git a/tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java b/tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java index 622dc4360d..79a0b1be5b 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/RegisterController.java @@ -13,7 +13,7 @@ public class RegisterController extends AbstractController { @Override protected void doPost(HttpRequest request, HttpResponse response) { RequestBody requestBody = request.getBody(); - String account = requestBody.get("account"); // TODO: DTO + String account = requestBody.get("account"); String password = requestBody.get("password"); String email = requestBody.get("email"); InMemoryUserRepository.save(new User(account, password, email)); From 301e3ccef6b2c917104b4205d18df5991b3143d4 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 11:51:29 +0900 Subject: [PATCH 27/36] =?UTF-8?q?refactor:=20=EC=BF=A0=ED=82=A4=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/coockie/HttpCookie.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java b/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java index b88ae5b460..c8f5ccd3b1 100644 --- a/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java +++ b/tomcat/src/main/java/org/apache/coyote/coockie/HttpCookie.java @@ -23,9 +23,9 @@ private static Map mapCookies(String rawCookies) { if (rawCookies != null && !rawCookies.isBlank()) { String[] cookiesElements = rawCookies.split("; "); - if (cookiesElements.length > 1) { - for (int i = 0; i < cookiesElements.length; i++) { - String[] cookiePair = cookiesElements[i].split("="); + for (int i = 0; i < cookiesElements.length; i++) { + String[] cookiePair = cookiesElements[i].split("="); + if (cookiePair.length > 1) { cookieGroup.put(cookiePair[0], cookiePair[1]); } } From 1426556e64c6233b9b3e0b1d8a2bb9a9269b038c Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 12:30:36 +0900 Subject: [PATCH 28/36] =?UTF-8?q?refactor:=203=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=ED=95=99=EC=8A=B5=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9E=AC=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/build.gradle | 1 - .../example/cachecontrol/CacheWebConfig.java | 19 --- .../example/etag/EtagFilterConfiguration.java | 19 --- .../version/CacheBustingWebConfig.java | 25 ---- study/src/main/resources/application.yml | 12 -- study/src/test/java/study/FileTest.java | 26 ++--- study/src/test/java/study/IOStreamTest.java | 110 +++++++++--------- 7 files changed, 62 insertions(+), 150 deletions(-) delete mode 100644 study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java delete mode 100644 study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java delete mode 100644 study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java delete mode 100644 study/src/main/resources/application.yml diff --git a/study/build.gradle b/study/build.gradle index 5c69542f84..87a1f0313c 100644 --- a/study/build.gradle +++ b/study/build.gradle @@ -19,7 +19,6 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-webflux' - implementation 'ch.qos.logback:logback-classic:1.5.7' implementation 'org.apache.commons:commons-lang3:3.14.0' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1' diff --git a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java deleted file mode 100644 index e413dd2926..0000000000 --- a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package cache.com.example.cachecontrol; - -import org.springframework.context.annotation.Configuration; -import org.springframework.http.CacheControl; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.mvc.WebContentInterceptor; - -@Configuration -public class CacheWebConfig implements WebMvcConfigurer { - - @Override - public void addInterceptors(final InterceptorRegistry registry) { - CacheControl cacheControl = CacheControl.noCache().cachePrivate(); - WebContentInterceptor webContentInterceptor = new WebContentInterceptor(); - webContentInterceptor.addCacheMapping(cacheControl, "/**"); - registry.addInterceptor(webContentInterceptor); - } -} diff --git a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java deleted file mode 100644 index a67f775eb2..0000000000 --- a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java +++ /dev/null @@ -1,19 +0,0 @@ -package cache.com.example.etag; - -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.filter.ShallowEtagHeaderFilter; - -@Configuration -public class EtagFilterConfiguration { - - @Bean - public FilterRegistrationBean shallowEtagHeaderFilter() { - FilterRegistrationBean filterFilterRegistrationBean = new FilterRegistrationBean<>( - new ShallowEtagHeaderFilter()); - filterFilterRegistrationBean.addUrlPatterns("/**"); - filterFilterRegistrationBean.setName("etagFilter"); - 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 deleted file mode 100644 index 6da6d2c795..0000000000 --- a/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package cache.com.example.version; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class CacheBustingWebConfig implements WebMvcConfigurer { - - public static final String PREFIX_STATIC_RESOURCES = "/resources"; - - private final ResourceVersion version; - - @Autowired - public CacheBustingWebConfig(ResourceVersion version) { - this.version = version; - } - - @Override - public void addResourceHandlers(final ResourceHandlerRegistry registry) { - registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**") - .addResourceLocations("classpath:/static/"); - } -} diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml deleted file mode 100644 index 385c11d5f1..0000000000 --- a/study/src/main/resources/application.yml +++ /dev/null @@ -1,12 +0,0 @@ -handlebars: - suffix: .html - -server: - tomcat: - accept-count: 1 - max-connections: 1 - threads: - max: 2 - compression: - enabled: true - min-response-size: 10 diff --git a/study/src/test/java/study/FileTest.java b/study/src/test/java/study/FileTest.java index a9ddd9b662..97ad7e94f9 100644 --- a/study/src/test/java/study/FileTest.java +++ b/study/src/test/java/study/FileTest.java @@ -1,30 +1,25 @@ package study; -import java.io.File; +import static org.assertj.core.api.Assertions.assertThat; + import java.io.IOException; import java.nio.file.Files; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - import java.nio.file.Path; -import java.util.Collections; import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; /** - * 웹서버는 사용자가 요청한 html 파일을 제공 할 수 있어야 한다. - * File 클래스를 사용해서 파일을 읽어오고, 사용자에게 전달한다. + * 웹서버는 사용자가 요청한 html 파일을 제공 할 수 있어야 한다. File 클래스를 사용해서 파일을 읽어오고, 사용자에게 전달한다. */ @DisplayName("File 클래스 학습 테스트") class FileTest { /** * resource 디렉터리 경로 찾기 - * - * File 객체를 생성하려면 파일의 경로를 알아야 한다. - * 자바 애플리케이션은 resource 디렉터리에 HTML, CSS 같은 정적 파일을 저장한다. - * resource 디렉터리의 경로는 어떻게 알아낼 수 있을까? + *

+ * File 객체를 생성하려면 파일의 경로를 알아야 한다. 자바 애플리케이션은 resource 디렉터리에 HTML, CSS 같은 정적 파일을 저장한다. resource 디렉터리의 경로는 어떻게 알아낼 수 + * 있을까? */ @Test void resource_디렉터리에_있는_파일의_경로를_찾는다() { @@ -38,9 +33,8 @@ class FileTest { /** * 파일 내용 읽기 - * - * 읽어온 파일의 내용을 I/O Stream을 사용해서 사용자에게 전달 해야 한다. - * File, Files 클래스를 사용하여 파일의 내용을 읽어보자. + *

+ * 읽어온 파일의 내용을 I/O Stream을 사용해서 사용자에게 전달 해야 한다. File, Files 클래스를 사용하여 파일의 내용을 읽어보자. */ @Test void 파일의_내용을_읽는다() throws IOException { diff --git a/study/src/test/java/study/IOStreamTest.java b/study/src/test/java/study/IOStreamTest.java index 6bb8b56edf..4cdbdf8082 100644 --- a/study/src/test/java/study/IOStreamTest.java +++ b/study/src/test/java/study/IOStreamTest.java @@ -1,45 +1,50 @@ package study; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import java.io.*; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.*; - /** - * 자바는 스트림(Stream)으로부터 I/O를 사용한다. - * 입출력(I/O)은 하나의 시스템에서 다른 시스템으로 데이터를 이동 시킬 때 사용한다. - * - * InputStream은 데이터를 읽고, OutputStream은 데이터를 쓴다. - * FilterStream은 InputStream이나 OutputStream에 연결될 수 있다. - * FilterStream은 읽거나 쓰는 데이터를 수정할 때 사용한다. (e.g. 암호화, 압축, 포맷 변환) - * - * Stream은 데이터를 바이트로 읽고 쓴다. - * 바이트가 아닌 텍스트(문자)를 읽고 쓰려면 Reader와 Writer 클래스를 연결한다. - * Reader, Writer는 다양한 문자 인코딩(e.g. UTF-8)을 처리할 수 있다. + * 자바는 스트림(Stream)으로부터 I/O를 사용한다. 입출력(I/O)은 하나의 시스템에서 다른 시스템으로 데이터를 이동 시킬 때 사용한다. + *

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

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

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

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

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

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

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

+ * 필터는 필터 스트림, reader, writer로 나뉜다. 필터는 바이트를 다른 데이터 형식으로 변환 할 때 사용한다. reader, writer는 UTF-8, ISO 8859-1 같은 형식으로 인코딩된 + * 텍스트를 처리하는 데 사용된다. */ @Nested class FilterStream_학습_테스트 { /** - * BufferedInputStream은 데이터 처리 속도를 높이기 위해 데이터를 버퍼에 저장한다. TODO: 아니면 어디에 저장하지? - * InputStream 객체를 생성하고 필터 생성자에 전달하면 필터에 연결된다. - * 버퍼 크기를 지정하지 않으면 버퍼의 기본 사이즈는 얼마일까? + * BufferedInputStream은 데이터 처리 속도를 높이기 위해 데이터를 버퍼에 저장한다. TODO: 아니면 어디에 저장하지? InputStream 객체를 생성하고 필터 생성자에 전달하면 + * 필터에 연결된다. 버퍼 크기를 지정하지 않으면 버퍼의 기본 사이즈는 얼마일까? */ @Test void 필터인_BufferedInputStream를_사용해보자() throws IOException { @@ -191,19 +189,15 @@ class FilterStream_학습_테스트 { } /** - * 자바의 기본 문자열은 UTF-16 유니코드 인코딩을 사용한다. - * 문자열이 아닌 바이트 단위로 처리하려니 불편하다. - * 그리고 바이트를 문자(char)로 처리하려면 인코딩을 신경 써야 한다. - * reader, writer를 사용하면 입출력 스트림을 바이트가 아닌 문자 단위로 데이터를 처리하게 된다. - * 그리고 InputStreamReader를 사용하면 지정된 인코딩에 따라 유니코드 문자로 변환할 수 있다. + * 자바의 기본 문자열은 UTF-16 유니코드 인코딩을 사용한다. 문자열이 아닌 바이트 단위로 처리하려니 불편하다. 그리고 바이트를 문자(char)로 처리하려면 인코딩을 신경 써야 한다. reader, + * writer를 사용하면 입출력 스트림을 바이트가 아닌 문자 단위로 데이터를 처리하게 된다. 그리고 InputStreamReader를 사용하면 지정된 인코딩에 따라 유니코드 문자로 변환할 수 있다. */ @Nested class InputStreamReader_학습_테스트 { /** - * InputStreamReader를 사용해서 바이트를 문자(char)로 읽어온다. - * 읽어온 문자(char)를 문자열(String)로 처리하자. - * 필터인 BufferedReader를 사용하면 readLine 메서드를 사용해서 문자열(String)을 한 줄 씩 읽어올 수 있다. + * InputStreamReader를 사용해서 바이트를 문자(char)로 읽어온다. 읽어온 문자(char)를 문자열(String)로 처리하자. 필터인 BufferedReader를 사용하면 + * readLine 메서드를 사용해서 문자열(String)을 한 줄 씩 읽어올 수 있다. */ @Test void BufferedReader를_사용하여_문자열을_읽어온다() throws IOException { From 1ff79ad4f4c6ceb57ed53faaece7b8a9b1556d7e Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 12:30:49 +0900 Subject: [PATCH 29/36] =?UTF-8?q?refactor:=203=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=ED=95=99=EC=8A=B5=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/cachecontrol/CacheWebConfig.java | 20 +++++++++++++ .../example/etag/EtagFilterConfiguration.java | 19 +++++++++++++ .../version/CacheBustingWebConfig.java | 28 +++++++++++++++++++ study/src/main/resources/application.yml | 13 +++++++++ 4 files changed, 80 insertions(+) create mode 100644 study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java create mode 100644 study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java create mode 100644 study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java create mode 100644 study/src/main/resources/application.yml diff --git a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java new file mode 100644 index 0000000000..f64fc5d435 --- /dev/null +++ b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java @@ -0,0 +1,20 @@ +package cache.com.example.cachecontrol; + +import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.mvc.WebContentInterceptor; + +@Configuration +public class CacheWebConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(final InterceptorRegistry registry) { + CacheControl cacheControl = CacheControl.noCache().cachePrivate(); + WebContentInterceptor webContentInterceptor = new WebContentInterceptor(); + webContentInterceptor.addCacheMapping(cacheControl, "/"); + + registry.addInterceptor(webContentInterceptor); + } +} diff --git a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java new file mode 100644 index 0000000000..75a9d51c21 --- /dev/null +++ b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java @@ -0,0 +1,19 @@ +package cache.com.example.etag; + +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.ShallowEtagHeaderFilter; + +@Configuration +public class EtagFilterConfiguration { + + @Bean + public FilterRegistrationBean shallowEtagHeaderFilter() { + FilterRegistrationBean filterFilterRegistrationBean = new FilterRegistrationBean<>( + new ShallowEtagHeaderFilter()); + filterFilterRegistrationBean.addUrlPatterns("/etag", "*.js"); + filterFilterRegistrationBean.setName("etagFilter"); + 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 new file mode 100644 index 0000000000..112f37ba9f --- /dev/null +++ b/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java @@ -0,0 +1,28 @@ +package cache.com.example.version; + +import java.time.Duration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class CacheBustingWebConfig implements WebMvcConfigurer { + + public static final String PREFIX_STATIC_RESOURCES = "/resources"; + + private final ResourceVersion version; + + @Autowired + public CacheBustingWebConfig(ResourceVersion version) { + this.version = version; + } + + @Override + public void addResourceHandlers(final ResourceHandlerRegistry registry) { + registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**") + .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic()) + .addResourceLocations("classpath:/static/"); + } +} diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml new file mode 100644 index 0000000000..8b74bdfd88 --- /dev/null +++ b/study/src/main/resources/application.yml @@ -0,0 +1,13 @@ +handlebars: + suffix: .html + +server: + tomcat: + accept-count: 1 + max-connections: 1 + threads: + min-spare: 2 + max: 2 + compression: + enabled: true + min-response-size: 10 From c21493ff3cac55e1d681ff1b5fe12a514cedfabb Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 12:32:44 +0900 Subject: [PATCH 30/36] =?UTF-8?q?refactor:=20=EB=B3=B4=EC=99=84=ED=95=B4?= =?UTF-8?q?=EC=95=BC=ED=95=98=EB=8A=94=20=ED=85=8C=EC=8A=A4=ED=8A=B8=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/request/RequestReaderTest.java | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java diff --git a/tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java b/tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java deleted file mode 100644 index e1afbd9b3c..0000000000 --- a/tomcat/src/test/java/org/apache/coyote/request/RequestReaderTest.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.apache.coyote.request; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; - -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.Test; - -class RequestReaderTest { - @Test // TODO: RequestReader 클래스의 readRequest 메서드를 테스트하는 코드를 작성하라. - void 요청을_읽는다() { - // given - String mockHttpRequest = "GET /index.html HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "User-Agent: Test\r\n" + - "\r\n" + - "account=gugu"; // HTTP 헤더 끝에 바디가 붙음 - - ByteArrayInputStream inputStream = new ByteArrayInputStream(mockHttpRequest.getBytes(StandardCharsets.UTF_8)); - - // when - HttpRequest httpRequest = RequestReader.readRequest(inputStream); - - // then - assertAll( - () -> assertThat(httpRequest.getPath()).isEqualTo("/index"), - () -> assertThat(httpRequest.getBody().get("account")).isEqualTo("gugu") - ); - } -} From d95d79d94dc5eb82e2b262104d8ec7214f5de181 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 14:01:29 +0900 Subject: [PATCH 31/36] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=97=90=20synchronized=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/test/java/thread/stage0/SynchronizationTest.java | 7 +++---- 1 file changed, 3 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..59afce5646 100644 --- a/study/src/test/java/thread/stage0/SynchronizationTest.java +++ b/study/src/test/java/thread/stage0/SynchronizationTest.java @@ -1,12 +1,11 @@ package thread.stage0; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; - -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; /** * 다중 스레드 환경에서 두 개 이상의 스레드가 변경 가능한(mutable) 공유 데이터를 동시에 업데이트하면 경쟁 조건(race condition)이 발생한다. @@ -41,7 +40,7 @@ private static final class SynchronizedMethods { private int sum = 0; - public void calculate() { + public synchronized void calculate() { setSum(getSum() + 1); } From d2692e0144d3b211fc0cb0c031656edd5cf823b2 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 14:02:05 +0900 Subject: [PATCH 32/36] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC=EC=9D=98=20=EC=8A=A4=EB=A0=88=EB=93=9C?= =?UTF-8?q?=ED=92=80=EA=B3=BC=20queue=20=EA=B0=AF=EC=88=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/java/thread/stage0/ThreadPoolsTest.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/study/src/test/java/thread/stage0/ThreadPoolsTest.java b/study/src/test/java/thread/stage0/ThreadPoolsTest.java index 238611ebfe..c3ecd5c80c 100644 --- a/study/src/test/java/thread/stage0/ThreadPoolsTest.java +++ b/study/src/test/java/thread/stage0/ThreadPoolsTest.java @@ -1,13 +1,12 @@ package thread.stage0; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.assertj.core.api.Assertions.assertThat; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; - -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * 스레드 풀은 무엇이고 어떻게 동작할까? @@ -31,8 +30,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 +45,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 adefc1bc795c4c265d93785f8ae477bf0a3bed0e Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 14:02:22 +0900 Subject: [PATCH 33/36] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=EC=97=90=20syncronized=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/test/java/thread/stage1/UserServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/study/src/test/java/thread/stage1/UserServlet.java b/study/src/test/java/thread/stage1/UserServlet.java index b180a84c32..a78e7b4ad4 100644 --- a/study/src/test/java/thread/stage1/UserServlet.java +++ b/study/src/test/java/thread/stage1/UserServlet.java @@ -11,7 +11,7 @@ public void service(final User user) { join(user); } - private void join(final User user) { + private synchronized void join(final User user) { if (!users.contains(user)) { users.add(user); } From 50578e5bab777c02c373d7ab0082235e5662721a Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 14:40:01 +0900 Subject: [PATCH 34/36] =?UTF-8?q?refactor:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=EC=9D=84=20post=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=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 --- .../coyote/controller/LoginController.java | 47 ++++++++++++++----- .../apache/coyote/request/HttpRequest.java | 4 ++ tomcat/src/main/resources/static/login.html | 2 +- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java index baa0631ab0..196bbc0605 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java @@ -18,18 +18,9 @@ public LoginController() { } @Override - protected void doGet(HttpRequest request, HttpResponse response) { - if (request.hasQueryParam()) { - login(request, response, sessionManager); - } - if (!request.hasQueryParam()) { - showLogin(request, response, sessionManager); - } - } - - private static void login(HttpRequest request, HttpResponse response, SessionManager sessionManager) { - String account = request.getQueryParam("account"); - String password = request.getQueryParam("password"); + protected void doPost(HttpRequest request, HttpResponse response) { + String account = request.getBody("account"); + String password = request.getBody("password"); Optional user = InMemoryUserRepository.findByAccount(account); if (user.isEmpty() || !user.get().checkPassword(password)) { @@ -45,7 +36,8 @@ private static void login(HttpRequest request, HttpResponse response, SessionMan } } - private static void showLogin(HttpRequest request, HttpResponse response, SessionManager sessionManager) { + @Override + protected void doGet(HttpRequest request, HttpResponse response) { if (request.hasSession() && sessionManager.isSessionExist(request.getSessionId())) { response.setStatusCode(StatusCode.FOUND); // response.addHeader(HeaderName.LOCATION, "/index.html"); @@ -55,4 +47,33 @@ private static void showLogin(HttpRequest request, HttpResponse response, Sessio response.setBody("/login.html"); } } +// +// private static void login(HttpRequest request, HttpResponse response, SessionManager sessionManager) { +// String account = request.getQueryParam("account"); +// String password = request.getQueryParam("password"); +// Optional user = InMemoryUserRepository.findByAccount(account); +// +// if (user.isEmpty() || !user.get().checkPassword(password)) { +// response.setStatusCode(StatusCode.UNAUTHORIZED); +// response.setBody("/401.html"); +// } +// if (user.isPresent() && user.get().checkPassword(password)) { +// response.setStatusCode(StatusCode.FOUND); +// response.setBody("/index.html"); +// +// String sessionId = sessionManager.generateSession(user.get()); +// response.addHeader(HeaderName.SET_COOKIE, sessionId); +// } +// } +// +// private static void showLogin(HttpRequest request, HttpResponse response, SessionManager sessionManager) { +// if (request.hasSession() && sessionManager.isSessionExist(request.getSessionId())) { +// response.setStatusCode(StatusCode.FOUND); // +// response.addHeader(HeaderName.LOCATION, "/index.html"); +// } +// if (!request.hasSession() || !sessionManager.isSessionExist(request.getSessionId())) { +// response.setStatusCode(StatusCode.OK); +// response.setBody("/login.html"); +// } +// } } diff --git a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java index d372935685..e0c25a843f 100644 --- a/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/request/HttpRequest.java @@ -61,4 +61,8 @@ public boolean hasSession() { public RequestBody getBody() { return body; } + + public String getBody(String parameter) { + return body.get(parameter); + } } diff --git a/tomcat/src/main/resources/static/login.html b/tomcat/src/main/resources/static/login.html index f4ed9de875..bc933357f2 100644 --- a/tomcat/src/main/resources/static/login.html +++ b/tomcat/src/main/resources/static/login.html @@ -20,7 +20,7 @@

로그인

-
+
From 848f767a3afbb8c96fe5eea320d3105ffa55b9ed Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 14:43:31 +0900 Subject: [PATCH 35/36] =?UTF-8?q?refactor:=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/controller/LoginController.java | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java index 196bbc0605..ca20d8d40c 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java @@ -47,33 +47,4 @@ protected void doGet(HttpRequest request, HttpResponse response) { response.setBody("/login.html"); } } -// -// private static void login(HttpRequest request, HttpResponse response, SessionManager sessionManager) { -// String account = request.getQueryParam("account"); -// String password = request.getQueryParam("password"); -// Optional user = InMemoryUserRepository.findByAccount(account); -// -// if (user.isEmpty() || !user.get().checkPassword(password)) { -// response.setStatusCode(StatusCode.UNAUTHORIZED); -// response.setBody("/401.html"); -// } -// if (user.isPresent() && user.get().checkPassword(password)) { -// response.setStatusCode(StatusCode.FOUND); -// response.setBody("/index.html"); -// -// String sessionId = sessionManager.generateSession(user.get()); -// response.addHeader(HeaderName.SET_COOKIE, sessionId); -// } -// } -// -// private static void showLogin(HttpRequest request, HttpResponse response, SessionManager sessionManager) { -// if (request.hasSession() && sessionManager.isSessionExist(request.getSessionId())) { -// response.setStatusCode(StatusCode.FOUND); // -// response.addHeader(HeaderName.LOCATION, "/index.html"); -// } -// if (!request.hasSession() || !sessionManager.isSessionExist(request.getSessionId())) { -// response.setStatusCode(StatusCode.OK); -// response.setBody("/login.html"); -// } -// } } From 5a4b7377bc81d5171c9ff64e671519276ce410c9 Mon Sep 17 00:00:00 2001 From: hyeonjilee Date: Fri, 13 Sep 2024 15:06:37 +0900 Subject: [PATCH 36/36] =?UTF-8?q?fix:=20=EC=84=B8=EC=85=98=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EB=94=94=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/controller/LoginController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java index ca20d8d40c..7e84cca85d 100644 --- a/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java +++ b/tomcat/src/main/java/org/apache/coyote/controller/LoginController.java @@ -32,7 +32,7 @@ protected void doPost(HttpRequest request, HttpResponse response) { response.setBody("/index.html"); String sessionId = sessionManager.generateSession(user.get()); - response.addHeader(HeaderName.SET_COOKIE, sessionId); + response.addHeader(HeaderName.SET_COOKIE, "JSESSIONID=" + sessionId); } }