From eb9459f3c06d448c189f104a40196a5dcf0bfac8 Mon Sep 17 00:00:00 2001 From: zangsu Date: Wed, 4 Sep 2024 00:36:01 +0900 Subject: [PATCH 01/28] =?UTF-8?q?=ED=95=99=EC=8A=B5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cache/com/example/GreetingController.java | 2 +- .../com/example/version/ResourceVersion.java | 2 +- study/src/test/java/study/FileTest.java | 66 +++++++++++++++++-- study/src/test/java/study/IOStreamTest.java | 66 +++++++++++++------ 4 files changed, 108 insertions(+), 28 deletions(-) diff --git a/study/src/main/java/cache/com/example/GreetingController.java b/study/src/main/java/cache/com/example/GreetingController.java index 978eefdc34..c0053cda42 100644 --- a/study/src/main/java/cache/com/example/GreetingController.java +++ b/study/src/main/java/cache/com/example/GreetingController.java @@ -5,7 +5,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; @Controller public class GreetingController { diff --git a/study/src/main/java/cache/com/example/version/ResourceVersion.java b/study/src/main/java/cache/com/example/version/ResourceVersion.java index 7049b3d82a..27a2f22813 100644 --- a/study/src/main/java/cache/com/example/version/ResourceVersion.java +++ b/study/src/main/java/cache/com/example/version/ResourceVersion.java @@ -2,7 +2,7 @@ import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/study/src/test/java/study/FileTest.java b/study/src/test/java/study/FileTest.java index e1b6cca042..6966a862ab 100644 --- a/study/src/test/java/study/FileTest.java +++ b/study/src/test/java/study/FileTest.java @@ -1,13 +1,19 @@ package study; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import java.io.File; +import java.net.URL; import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; /** * 웹서버는 사용자가 요청한 html 파일을 제공 할 수 있어야 한다. @@ -18,24 +24,72 @@ class FileTest { /** * resource 디렉터리 경로 찾기 - * + *

* File 객체를 생성하려면 파일의 경로를 알아야 한다. * 자바 애플리케이션은 resource 디렉터리에 HTML, CSS 같은 정적 파일을 저장한다. * resource 디렉터리의 경로는 어떻게 알아낼 수 있을까? */ @Test void resource_디렉터리에_있는_파일의_경로를_찾는다() { + //현재 프로젝트의 경로를 알아내는 방법은...? -> 해결 + // 현재 위치하고 있는 곳 (test / main ) 을 알아내는 방법은? + final String fileName = "nextstep.txt"; // todo - final String actual = ""; + /*List resoursesFiles = getResourceFile(); + final String actual = resoursesFiles.stream() + .flatMap(resoursesFile -> Arrays.stream(resoursesFile.listFiles())) + .filter(file -> file.getName().equals(fileName)) + .findFirst() + .orElseThrow() + .getName();*/ + + /*File resources = new File("/Users/mac/Desktop/zangsu/wooteco/Level4/java-http/study/src/test/resources"); + final String actual = Arrays.stream(resources.listFiles()) + .filter(file -> file.getName().equals(fileName)) + .findFirst() + .orElseThrow() + .getName();*/ + + // 세상에 몰리 대박 + final URL resoucrcesUrl = getClass().getClassLoader().getResource(fileName); + String actual = resoucrcesUrl.getFile(); assertThat(actual).endsWith(fileName); } + private List getResourceFile() { + File file = new File(".").getAbsoluteFile(); + + List results = new ArrayList<>(); + addResourcesFile(file, results); + Arrays.stream(file.listFiles()) + .filter(subFile -> subFile.getName().equals("resources")) + .forEach(subFile -> results.add(subFile)); + return results; + } + + private void addResourcesFile(File parent, List results) { + for(File file : parent.listFiles()) { + if (file.isFile() && file.getName().equals("resources")) { + results.add(file); + } else { + addResourcesFile(file, results); + } + } + } + + private File getCurrentProject() { + Path path = Paths.get(""); + File file = path.toAbsolutePath().toFile(); + System.out.println("file = " + file); + return file; + } + /** * 파일 내용 읽기 - * + *

* 읽어온 파일의 내용을 I/O Stream을 사용해서 사용자에게 전달 해야 한다. * File, Files 클래스를 사용하여 파일의 내용을 읽어보자. */ diff --git a/study/src/test/java/study/IOStreamTest.java b/study/src/test/java/study/IOStreamTest.java index 47a79356b6..c87e0b3891 100644 --- a/study/src/test/java/study/IOStreamTest.java +++ b/study/src/test/java/study/IOStreamTest.java @@ -1,22 +1,34 @@ package study; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.in; +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)을 처리할 수 있다. @@ -26,7 +38,7 @@ class IOStreamTest { /** * OutputStream 학습하기 - * + *

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

* write 메서드는 데이터를 바이트로 출력하기 때문에 비효율적이다. * write(byte[] data)write(byte b[], int off, int len) 메서드는 * 1바이트 이상을 한 번에 전송 할 수 있어 훨씬 효율적이다. @@ -48,12 +60,11 @@ class OutputStream_학습_테스트 { void OutputStream은_데이터를_바이트로_처리한다() throws IOException { final byte[] bytes = {110, 101, 120, 116, 115, 116, 101, 112}; final OutputStream outputStream = new ByteArrayOutputStream(bytes.length); - /** * todo * OutputStream 객체의 write 메서드를 사용해서 테스트를 통과시킨다 */ - + outputStream.write(bytes); final String actual = outputStream.toString(); assertThat(actual).isEqualTo("nextstep"); @@ -62,8 +73,9 @@ class OutputStream_학습_테스트 { /** * 효율적인 전송을 위해 스트림에서 버퍼링을 사용 할 수 있다. - * BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다. - * + * BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다. \\n + *

+ *

* 버퍼링을 사용하면 OutputStream을 사용할 때 flush를 사용하자. * flush() 메서드는 버퍼가 아직 가득 차지 않은 상황에서 강제로 버퍼의 내용을 전송한다. * Stream은 동기(synchronous)로 동작하기 때문에 버퍼가 찰 때까지 기다리면 @@ -78,6 +90,7 @@ class OutputStream_학습_테스트 { * flush를 사용해서 테스트를 통과시킨다. * ByteArrayOutputStream과 어떤 차이가 있을까? */ + outputStream.flush(); verify(outputStream, atLeastOnce()).flush(); outputStream.close(); @@ -96,6 +109,8 @@ class OutputStream_학습_테스트 { * try-with-resources를 사용한다. * java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다. */ + try (outputStream) { + } verify(outputStream, atLeastOnce()).close(); } @@ -103,12 +118,13 @@ class OutputStream_학습_테스트 { /** * InputStream 학습하기 - * + *
* 자바의 기본 입력 클래스는 java.io.InputStream이다. * InputStream은 다른 매체로부터 바이트로 데이터를 읽을 때 사용한다. * InputStream의 read() 메서드는 기반 메서드이다. * public abstract int read() throws IOException; - * + * + *
* InputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 읽기 위해 read() 메서드를 사용한다. */ @Nested @@ -128,7 +144,9 @@ class InputStream_학습_테스트 { * todo * inputStream에서 바이트로 반환한 값을 문자열로 어떻게 바꿀까? */ - final String actual = ""; + final OutputStream outputStream = new ByteArrayOutputStream(bytes.length); + inputStream.transferTo(outputStream); + final String actual = outputStream.toString(); assertThat(actual).isEqualTo("🤩"); assertThat(inputStream.read()).isEqualTo(-1); @@ -148,6 +166,9 @@ class InputStream_학습_테스트 { * try-with-resources를 사용한다. * java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다. */ + try (inputStream) { + + } verify(inputStream, atLeastOnce()).close(); } @@ -155,7 +176,7 @@ class InputStream_학습_테스트 { /** * FilterStream 학습하기 - * + *

* 필터는 필터 스트림, reader, writer로 나뉜다. * 필터는 바이트를 다른 데이터 형식으로 변환 할 때 사용한다. * reader, writer는 UTF-8, ISO 8859-1 같은 형식으로 인코딩된 텍스트를 처리하는 데 사용된다. @@ -169,12 +190,12 @@ class FilterStream_학습_테스트 { * 버퍼 크기를 지정하지 않으면 버퍼의 기본 사이즈는 얼마일까? */ @Test - void 필터인_BufferedInputStream를_사용해보자() { + void 필터인_BufferedInputStream를_사용해보자() throws IOException { final String text = "필터에 연결해보자."; final InputStream inputStream = new ByteArrayInputStream(text.getBytes()); - final InputStream bufferedInputStream = null; + final InputStream bufferedInputStream = new BufferedInputStream(inputStream); - final byte[] actual = new byte[0]; + final byte[] actual = bufferedInputStream.readAllBytes(); assertThat(bufferedInputStream).isInstanceOf(FilterInputStream.class); assertThat(actual).isEqualTo("필터에 연결해보자.".getBytes()); @@ -204,9 +225,14 @@ class InputStreamReader_학습_테스트 { "😋😛😝😜🤪🤨🧐🤓😎🥸🤩", ""); final InputStream inputStream = new ByteArrayInputStream(emoji.getBytes()); + final InputStreamReader inputStreamReader = new InputStreamReader(inputStream); + final BufferedReader bufferedReader = new BufferedReader(inputStreamReader); final StringBuilder actual = new StringBuilder(); + bufferedReader.lines() + .forEach(line -> actual.append(line).append("\r\n")); + assertThat(actual).hasToString(emoji); } } From caae46af8510526d013b227fc503c19331fe55f8 Mon Sep 17 00:00:00 2001 From: Jang Hyeok-su <76612738+zangsu@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:37:11 +0900 Subject: [PATCH 02/28] =?UTF-8?q?=EC=9D=B4=EC=8A=88=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/Feature Template | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Feature Template diff --git a/.github/ISSUE_TEMPLATE/Feature Template b/.github/ISSUE_TEMPLATE/Feature Template new file mode 100644 index 0000000000..2de2c831b2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature Template @@ -0,0 +1,23 @@ +--- +name: Feature Template +about: 기능 추가 이슈 템플릿 +title: "[FEAT] " +labels: feature +assignees: '' + +--- + +## 📌 어떤 기능인가요? +> 추가하려는 기능에 대해 간결하게 설명해주세요 + + +## 📜 작업 상세 내용 +- [ ] TODO +- [ ] TODO +- [ ] TODO + +## ⏳ 예상 소요 시간 +> 이슈를 완료하기까지 예상되는 소요 시간을 분 or 시간 or 일 단위로 작성해주세요. + + +## 🔍 참고할만한 자료(선택) From c00ca94dc92d0c360b2ea0ab835e1d3d78dd30cc Mon Sep 17 00:00:00 2001 From: zangsu Date: Wed, 4 Sep 2024 13:52:43 +0900 Subject: [PATCH 03/28] =?UTF-8?q?refactor=20:=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98=20=EC=A0=81=EC=9A=A9=20-=20=EC=A7=80=EC=97=AD=20?= =?UTF-8?q?=EB=B3=80=EC=88=98,=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0?= =?UTF-8?q?=EC=97=90=20`final`=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/Application.java | 2 +- .../techcourse/db/InMemoryUserRepository.java | 6 ++--- .../java/org/apache/catalina/Manager.java | 16 +++++------- .../apache/catalina/connector/Connector.java | 26 +++++++++---------- .../org/apache/catalina/startup/Tomcat.java | 4 +-- .../apache/coyote/http11/Http11Processor.java | 20 +++++++------- .../coyote/http11/Http11ProcessorTest.java | 11 ++++---- 7 files changed, 42 insertions(+), 43 deletions(-) diff --git a/tomcat/src/main/java/com/techcourse/Application.java b/tomcat/src/main/java/com/techcourse/Application.java index 6dc0e04e1d..f874a4efb5 100644 --- a/tomcat/src/main/java/com/techcourse/Application.java +++ b/tomcat/src/main/java/com/techcourse/Application.java @@ -5,7 +5,7 @@ public class Application { public static void main(String[] args) { - final var tomcat = new Tomcat(); + var tomcat = new Tomcat(); tomcat.start(); } } diff --git a/tomcat/src/main/java/com/techcourse/db/InMemoryUserRepository.java b/tomcat/src/main/java/com/techcourse/db/InMemoryUserRepository.java index d3fa57feeb..40b5104a69 100644 --- a/tomcat/src/main/java/com/techcourse/db/InMemoryUserRepository.java +++ b/tomcat/src/main/java/com/techcourse/db/InMemoryUserRepository.java @@ -1,17 +1,17 @@ package com.techcourse.db; -import com.techcourse.model.User; - import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import com.techcourse.model.User; + public class InMemoryUserRepository { private static final Map database = new ConcurrentHashMap<>(); static { - final User user = new User(1L, "gugu", "password", "hkkang@woowahan.com"); + User user = new User(1L, "gugu", "password", "hkkang@woowahan.com"); database.put(user.getAccount(), user); } diff --git a/tomcat/src/main/java/org/apache/catalina/Manager.java b/tomcat/src/main/java/org/apache/catalina/Manager.java index e69410f6a9..82b207fb05 100644 --- a/tomcat/src/main/java/org/apache/catalina/Manager.java +++ b/tomcat/src/main/java/org/apache/catalina/Manager.java @@ -1,9 +1,9 @@ package org.apache.catalina; -import jakarta.servlet.http.HttpSession; - import java.io.IOException; +import jakarta.servlet.http.HttpSession; + /** * A Manager manages the pool of Sessions that are associated with a * particular Container. Different Manager implementations may support @@ -36,14 +36,12 @@ public interface Manager { * specified session id (if any); otherwise return null. * * @param id The session id for the session to be returned - * - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - * @exception IOException if an input/output error occurs while - * processing this request - * * @return the request session or {@code null} if a session with the - * requested ID could not be found + * requested ID could not be found + * @throws IllegalStateException if a new session cannot be + * instantiated for any reason + * @throws IOException if an input/output error occurs while + * processing this request */ HttpSession findSession(String id) throws IOException; diff --git a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java index 3b2c4dda7c..2e2de79386 100644 --- a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java +++ b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java @@ -1,14 +1,14 @@ package org.apache.catalina.connector; -import org.apache.coyote.http11.Http11Processor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.IOException; import java.io.UncheckedIOException; import java.net.ServerSocket; import java.net.Socket; +import org.apache.coyote.http11.Http11Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class Connector implements Runnable { private static final Logger log = LoggerFactory.getLogger(Connector.class); @@ -23,15 +23,15 @@ public Connector() { this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT); } - public Connector(final int port, final int acceptCount) { + public Connector(int port, int acceptCount) { this.serverSocket = createServerSocket(port, acceptCount); this.stopped = false; } - private ServerSocket createServerSocket(final int port, final int acceptCount) { + private ServerSocket createServerSocket(int port, int acceptCount) { try { - final int checkedPort = checkPort(port); - final int checkedAcceptCount = checkAcceptCount(acceptCount); + int checkedPort = checkPort(port); + int checkedAcceptCount = checkAcceptCount(acceptCount); return new ServerSocket(checkedPort, checkedAcceptCount); } catch (IOException e) { throw new UncheckedIOException(e); @@ -62,7 +62,7 @@ private void connect() { } } - private void process(final Socket connection) { + private void process(Socket connection) { if (connection == null) { return; } @@ -79,9 +79,9 @@ public void stop() { } } - private int checkPort(final int port) { - final var MIN_PORT = 1; - final var MAX_PORT = 65535; + private int checkPort(int port) { + var MIN_PORT = 1; + var MAX_PORT = 65535; if (port < MIN_PORT || MAX_PORT < port) { return DEFAULT_PORT; @@ -89,7 +89,7 @@ private int checkPort(final int port) { return port; } - private int checkAcceptCount(final int acceptCount) { + private int checkAcceptCount(int acceptCount) { return Math.max(acceptCount, DEFAULT_ACCEPT_COUNT); } } diff --git a/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java b/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java index 205159e95b..61afa8df71 100644 --- a/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java +++ b/tomcat/src/main/java/org/apache/catalina/startup/Tomcat.java @@ -1,11 +1,11 @@ package org.apache.catalina.startup; +import java.io.IOException; + import org.apache.catalina.connector.Connector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; - public class Tomcat { private static final Logger log = LoggerFactory.getLogger(Tomcat.class); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index bb14184757..b93d9c687f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,12 +1,13 @@ package org.apache.coyote.http11; -import com.techcourse.exception.UncheckedServletException; +import java.io.IOException; +import java.net.Socket; + import org.apache.coyote.Processor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.net.Socket; +import com.techcourse.exception.UncheckedServletException; public class Http11Processor implements Runnable, Processor { @@ -14,7 +15,7 @@ public class Http11Processor implements Runnable, Processor { private final Socket connection; - public Http11Processor(final Socket connection) { + public Http11Processor(Socket connection) { this.connection = connection; } @@ -25,13 +26,12 @@ public void run() { } @Override - public void process(final Socket connection) { - try (final var inputStream = connection.getInputStream(); - final var outputStream = connection.getOutputStream()) { - - final var responseBody = "Hello world!"; + public void process(Socket connection) { + try (var inputStream = connection.getInputStream(); + var outputStream = connection.getOutputStream()) { + var responseBody = "Hello world!"; - final var response = String.join("\r\n", + var response = String.join("\r\n", "HTTP/1.1 200 OK ", "Content-Type: text/html;charset=utf-8 ", "Content-Length: " + responseBody.getBytes().length + " ", diff --git a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java index 2aba8c56e0..12a1df1479 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -1,14 +1,15 @@ package org.apache.coyote.http11; -import org.junit.jupiter.api.Test; -import support.StubSocket; +import static org.assertj.core.api.Assertions.assertThat; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Files; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; + +import support.StubSocket; class Http11ProcessorTest { @@ -35,7 +36,7 @@ void process() { @Test void index() throws IOException { // given - final String httpRequest= String.join("\r\n", + final String httpRequest = String.join("\r\n", "GET /index.html HTTP/1.1 ", "Host: localhost:8080 ", "Connection: keep-alive ", @@ -53,7 +54,7 @@ void index() throws IOException { var expected = "HTTP/1.1 200 OK \r\n" + "Content-Type: text/html;charset=utf-8 \r\n" + "Content-Length: 5564 \r\n" + - "\r\n"+ + "\r\n" + new String(Files.readAllBytes(new File(resource.getFile()).toPath())); assertThat(socket.output()).isEqualTo(expected); From e9002f836377610c4ac221264a3c87f7d8aca574 Mon Sep 17 00:00:00 2001 From: zangsu Date: Wed, 4 Sep 2024 15:32:29 +0900 Subject: [PATCH 04/28] =?UTF-8?q?test:=20Request=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/request/Request.java | 19 +++++++++ .../coyote/http11/request/RequestTest.java | 40 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/Request.java create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java new file mode 100644 index 0000000000..65c7055c0d --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java @@ -0,0 +1,19 @@ +package org.apache.coyote.http11.request; + +import java.io.InputStream; + +import org.apache.commons.lang3.NotImplementedException; + +public class Request { + + public Request(InputStream inputStream) { + } + + public Method getMethod() { + throw new NotImplementedException(); + } + + public String getTarget() { + throw new NotImplementedException(); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java new file mode 100644 index 0000000000..e96f917e21 --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java @@ -0,0 +1,40 @@ +package org.apache.coyote.http11.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class RequestTest { + + @Nested + @DisplayName("생성 테스트") + class ConstructorTest { + + @Test + @DisplayName("GET 요청 생성 테스트") + void getRequestConstructTest() throws IOException { + //given + String input = """ + GET /index.html HTTP/1.1 + Host: localhost:8080 + Connection: keep-alive + + """; + + //when + Request request = new Request(new ByteArrayInputStream(input.getBytes())); + + //then + assertAll( + () -> assertThat(request.getMethod()).isEqualTo(Method.GET), + () -> assertThat(request.getTarget()).isEqualTo("/index.html") + ); + } + } +} From 9d5dc56ac3ef3ba1fe38a0a494013c7c2730b011 Mon Sep 17 00:00:00 2001 From: zangsu Date: Wed, 4 Sep 2024 15:32:43 +0900 Subject: [PATCH 05/28] =?UTF-8?q?feat:=20Method=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/apache/coyote/http11/request/Method.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/Method.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/Method.java b/tomcat/src/main/java/org/apache/coyote/http11/request/Method.java new file mode 100644 index 0000000000..7321956414 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/Method.java @@ -0,0 +1,14 @@ +package org.apache.coyote.http11.request; + +import java.util.Arrays; + +public enum Method { + GET, POST, PUT, PATCH, DELETE; + + public Method findByName(String name) { + return Arrays.stream(values()) + .filter(method -> method.name().equals(name)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("잘못된 Http 메서드 입니다.")); + } +} From fed02f6f5f4308400e55c160d9495cad010f5bfb Mon Sep 17 00:00:00 2001 From: Gyeongho Yang Date: Thu, 5 Sep 2024 11:11:09 +0900 Subject: [PATCH 06/28] fix: remove implementation logback-classic on gradle (#501) --- study/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/study/build.gradle b/study/build.gradle index 5c69542f84..87a1f0313c 100644 --- a/study/build.gradle +++ b/study/build.gradle @@ -19,7 +19,6 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-webflux' - implementation 'ch.qos.logback:logback-classic:1.5.7' implementation 'org.apache.commons:commons-lang3:3.14.0' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1' From 7e9135698878932274ddc1f523ba817ed9c56c70 Mon Sep 17 00:00:00 2001 From: Gyeongho Yang Date: Thu, 5 Sep 2024 13:51:07 +0900 Subject: [PATCH 07/28] fix: add threads min-spare configuration on properties (#502) --- study/src/main/resources/application.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml index 4e8655a962..e3503a5fb9 100644 --- a/study/src/main/resources/application.yml +++ b/study/src/main/resources/application.yml @@ -6,4 +6,5 @@ server: accept-count: 1 max-connections: 1 threads: + min-spare: 2 max: 2 From d719ae3efa9b9956f102217d3ef7c0e3e8088fd3 Mon Sep 17 00:00:00 2001 From: zangsu Date: Thu, 5 Sep 2024 17:50:06 +0900 Subject: [PATCH 08/28] =?UTF-8?q?refactor:=20findByName=20=EC=9D=84=20stat?= =?UTF-8?q?ic=20=EC=9C=BC=EB=A1=9C=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/apache/coyote/http11/request/Method.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/Method.java b/tomcat/src/main/java/org/apache/coyote/http11/request/Method.java index 7321956414..04ca6a3c38 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/Method.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/Method.java @@ -5,7 +5,7 @@ public enum Method { GET, POST, PUT, PATCH, DELETE; - public Method findByName(String name) { + public static Method findByName(String name) { return Arrays.stream(values()) .filter(method -> method.name().equals(name)) .findFirst() From ef54ac688a64a54ac9108b24155a5d769184570d Mon Sep 17 00:00:00 2001 From: zangsu Date: Thu, 5 Sep 2024 21:56:54 +0900 Subject: [PATCH 09/28] =?UTF-8?q?feat:=20=EC=9A=94=EC=B2=AD=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20Request=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=ED=8C=8C?= =?UTF-8?q?=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/request/Request.java | 17 +++++++++++------ .../coyote/http11/request/RequestLine.java | 13 +++++++++++++ .../coyote/http11/request/RequestTest.java | 7 ++++++- 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java index 65c7055c0d..99dec443db 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java @@ -1,19 +1,24 @@ package org.apache.coyote.http11.request; -import java.io.InputStream; - -import org.apache.commons.lang3.NotImplementedException; +import java.util.List; public class Request { - public Request(InputStream inputStream) { + private final RequestLine requestLine; + + private Request(RequestLine requestLine) { + this.requestLine = requestLine; + } + + public static Request parseFrom(List request) { + return new Request(RequestLine.parseFrom(request.getFirst())); } public Method getMethod() { - throw new NotImplementedException(); + return requestLine.method(); } public String getTarget() { - throw new NotImplementedException(); + return requestLine.target(); } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java new file mode 100644 index 0000000000..3bd18e25a5 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java @@ -0,0 +1,13 @@ +package org.apache.coyote.http11.request; + +public record RequestLine ( + Method method, + String target, + String httpVersion +) { + + public static RequestLine parseFrom(String requestLineText) { + String[] token = requestLineText.split(" "); + return new RequestLine(Method.findByName(token[0]), token[1], token[2]); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java index e96f917e21..91cd174cfe 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java @@ -3,8 +3,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -28,7 +31,9 @@ void getRequestConstructTest() throws IOException { """; //when - Request request = new Request(new ByteArrayInputStream(input.getBytes())); + InputStream requestStream = new ByteArrayInputStream(input.getBytes()); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(requestStream)); + Request request = Request.parseFrom(bufferedReader.lines().toList()); //then assertAll( From cd7625420196011016d5800e2382deb64d72c6ef Mon Sep 17 00:00:00 2001 From: zangsu Date: Thu, 5 Sep 2024 22:07:40 +0900 Subject: [PATCH 10/28] =?UTF-8?q?refactor:=20=EC=9A=94=EC=B2=AD=EC=97=90?= =?UTF-8?q?=20=EB=8C=80=ED=95=9C=20=EC=9D=91=EB=8B=B5=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index b93d9c687f..f0892c5770 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,9 +1,13 @@ package org.apache.coyote.http11; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.net.Socket; import org.apache.coyote.Processor; +import org.apache.coyote.http11.request.Method; +import org.apache.coyote.http11.request.Request; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,20 +32,38 @@ public void run() { @Override public void process(Socket connection) { try (var inputStream = connection.getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream); var outputStream = connection.getOutputStream()) { - var responseBody = "Hello world!"; - var response = String.join("\r\n", - "HTTP/1.1 200 OK ", - "Content-Type: text/html;charset=utf-8 ", - "Content-Length: " + responseBody.getBytes().length + " ", - "", - responseBody); + BufferedReader requestBufferedReader = new BufferedReader(inputStreamReader); + Request request = Request.parseFrom(requestBufferedReader.lines().toList()); + String response = getResponseString(request); outputStream.write(response.getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { log.error(e.getMessage(), e); } } + + private String getResponseString(Request request) { + if (request.getMethod() == Method.GET) { + String content = getContent(request); + + return String.join("\r\n", + "HTTP/1.1 200 OK ", + "Content-Type: text/html;charset=utf-8 ", + "Content-Length: " + content.getBytes().length + " ", + "", + content); + } + return null; + } + + private String getContent(Request request) { + if (request.getTarget().equals("/")) { + return "Hello world!"; + } + return null; + } } From bc3c24104c19121247192760dd8673dff446e05e Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 00:34:34 +0900 Subject: [PATCH 11/28] =?UTF-8?q?refactor:=20=EB=94=94=EB=B2=84=EA=B9=85?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=B4=20toString=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/apache/coyote/http11/request/Request.java | 7 +++++++ .../org/apache/coyote/http11/request/RequestLine.java | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java index 99dec443db..49ad327191 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java @@ -21,4 +21,11 @@ public Method getMethod() { public String getTarget() { return requestLine.target(); } + + @Override + public String toString() { + return "Request{" + + "requestLine=" + requestLine + + '}'; + } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java index 3bd18e25a5..04fd330939 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/RequestLine.java @@ -10,4 +10,13 @@ public static RequestLine parseFrom(String requestLineText) { String[] token = requestLineText.split(" "); return new RequestLine(Method.findByName(token[0]), token[1], token[2]); } + + @Override + public String toString() { + return "RequestLine{" + + "method=" + method + + ", target='" + target + '\'' + + ", httpVersion='" + httpVersion + '\'' + + '}'; + } } From f830fd7b8e81710730d47987612c261e7dbb4c4a Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 00:47:16 +0900 Subject: [PATCH 12/28] =?UTF-8?q?refactor:=20=EC=9E=85=EB=A0=A5=EC=9D=84?= =?UTF-8?q?=20=EC=9D=BD=EB=8A=94=EB=8D=B0=20BufferedReader.lines()=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 --- .../apache/coyote/http11/Http11Processor.java | 29 +++++++++++++++---- .../coyote/http11/request/RequestTest.java | 2 ++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index f0892c5770..c7c358df73 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,9 +1,15 @@ package org.apache.coyote.http11; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; +import java.net.URL; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.apache.coyote.Processor; import org.apache.coyote.http11.request.Method; @@ -33,12 +39,12 @@ public void run() { public void process(Socket connection) { try (var inputStream = connection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); + BufferedReader requestBufferedReader = new BufferedReader(inputStreamReader); var outputStream = connection.getOutputStream()) { - BufferedReader requestBufferedReader = new BufferedReader(inputStreamReader); - Request request = Request.parseFrom(requestBufferedReader.lines().toList()); - + Request request = Request.parseFrom(getPlainRequest(requestBufferedReader)); String response = getResponseString(request); + outputStream.write(response.getBytes()); outputStream.flush(); } catch (IOException | UncheckedServletException e) { @@ -46,7 +52,16 @@ public void process(Socket connection) { } } - private String getResponseString(Request request) { + private List getPlainRequest(BufferedReader requestBufferedReader) throws IOException { + List plainRequest = new ArrayList<>(); + while(requestBufferedReader.ready()) { + String line = requestBufferedReader.readLine(); + plainRequest.add(line); + } + return Collections.unmodifiableList(plainRequest); + } + + private String getResponseString(Request request) throws IOException { if (request.getMethod() == Method.GET) { String content = getContent(request); @@ -60,10 +75,12 @@ private String getResponseString(Request request) { return null; } - private String getContent(Request request) { + private String getContent(Request request) throws IOException { if (request.getTarget().equals("/")) { return "Hello world!"; } - return null; + String name = "static" + request.getTarget(); + URL resource = getClass().getClassLoader().getResource(name); + return new String(Files.readAllBytes(new File(resource.getPath()).toPath())); } } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java index 91cd174cfe..009f03be72 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/request/RequestTest.java @@ -33,6 +33,8 @@ void getRequestConstructTest() throws IOException { //when InputStream requestStream = new ByteArrayInputStream(input.getBytes()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(requestStream)); + + Request request = Request.parseFrom(bufferedReader.lines().toList()); //then From d19e5ff3a9ab60029005eb7de93d916fad0573f8 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 01:19:15 +0900 Subject: [PATCH 13/28] =?UTF-8?q?feat:=20=EC=9D=91=EB=8B=B5=ED=95=A0=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=EC=9D=84=20Content=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=A1=9C=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/response/Content.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/response/Content.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/Content.java b/tomcat/src/main/java/org/apache/coyote/http11/response/Content.java new file mode 100644 index 0000000000..908f9acce7 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/Content.java @@ -0,0 +1,37 @@ +package org.apache.coyote.http11.response; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; + +public class Content { + private final String contentType; + private final String content; + + public Content(String resourceName) throws IOException { + this.contentType = determineContentType(resourceName); + String path = "static" + resourceName; + URL resource = getClass().getClassLoader().getResource(path); + this.content = new String(Files.readAllBytes(new File(resource.getPath()).toPath())); + } + + private String determineContentType(String resourceName) { + String extension = resourceName.split("\\.")[1]; + if (extension.equals("html")) { + return "text/html"; + } + if (extension.equals("css")) { + return "text/css"; + } + return "text/plain"; + } + + public String getContentType() { + return contentType; + } + + public String getContent() { + return content; + } +} From fd7e4096c03414d55d3d14c3292563288b9db8eb Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 01:19:29 +0900 Subject: [PATCH 14/28] =?UTF-8?q?feat:=20css=20=ED=8C=8C=EC=9D=BC=EB=8F=84?= =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 23 +++++++------- .../coyote/http11/Http11ProcessorTest.java | 30 +++++++++++++++++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index c7c358df73..ff63f59184 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -1,12 +1,9 @@ package org.apache.coyote.http11; import java.io.BufferedReader; -import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; -import java.net.URL; -import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -14,6 +11,7 @@ import org.apache.coyote.Processor; import org.apache.coyote.http11.request.Method; import org.apache.coyote.http11.request.Request; +import org.apache.coyote.http11.response.Content; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,6 +41,7 @@ public void process(Socket connection) { var outputStream = connection.getOutputStream()) { Request request = Request.parseFrom(getPlainRequest(requestBufferedReader)); + log.info("request : {}", request); String response = getResponseString(request); outputStream.write(response.getBytes()); @@ -54,7 +53,7 @@ public void process(Socket connection) { private List getPlainRequest(BufferedReader requestBufferedReader) throws IOException { List plainRequest = new ArrayList<>(); - while(requestBufferedReader.ready()) { + while (requestBufferedReader.ready()) { String line = requestBufferedReader.readLine(); plainRequest.add(line); } @@ -63,24 +62,22 @@ private List getPlainRequest(BufferedReader requestBufferedReader) throw private String getResponseString(Request request) throws IOException { if (request.getMethod() == Method.GET) { - String content = getContent(request); + Content content = getContent(request); return String.join("\r\n", "HTTP/1.1 200 OK ", - "Content-Type: text/html;charset=utf-8 ", - "Content-Length: " + content.getBytes().length + " ", + String.format("Content-Type: %s;charset=utf-8 ", content.getContentType()), + "Content-Length: " + content.getContent().getBytes().length + " ", "", - content); + content.getContent()); } return null; } - private String getContent(Request request) throws IOException { + private Content getContent(Request request) throws IOException { if (request.getTarget().equals("/")) { - return "Hello world!"; + return new Content("index.html"); } - String name = "static" + request.getTarget(); - URL resource = getClass().getClassLoader().getResource(name); - return new String(Files.readAllBytes(new File(resource.getPath()).toPath())); + return new Content(request.getTarget()); } } diff --git a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java index 12a1df1479..a3404db146 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -7,6 +7,7 @@ import java.net.URL; import java.nio.file.Files; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import support.StubSocket; @@ -14,6 +15,7 @@ class Http11ProcessorTest { @Test + @Disabled void process() { // given final var socket = new StubSocket(); @@ -59,4 +61,32 @@ void index() throws IOException { assertThat(socket.output()).isEqualTo(expected); } + + @Test + void css() throws IOException { + // given + final String httpRequest = String.join("\r\n", + "GET /css/styles.css HTTP/1.1 ", + "Host: localhost:8080 ", + "Connection: keep-alive ", + "", + ""); + + final var socket = new StubSocket(httpRequest); + final Http11Processor processor = new Http11Processor(socket); + + // when + processor.process(socket); + + // then + final URL resource = getClass().getClassLoader().getResource("static/css/styles.css"); + String contentBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); + var expected = "HTTP/1.1 200 OK \r\n" + + "Content-Type: text/css;charset=utf-8 \r\n" + + String.format("Content-Length: %d \r\n",contentBody.getBytes().length) + + "\r\n" + + contentBody; + + assertThat(socket.output()).isEqualTo(expected); + } } From 62539e6d9b34f122d1816278c2932dcd5097af5e Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 01:25:36 +0900 Subject: [PATCH 15/28] =?UTF-8?q?refactor:=20http=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EC=9D=84=20=EC=9D=91=EB=8B=B5=EA=B3=BC=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EC=9D=B4=20=EB=8F=99=EC=9D=BC=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/apache/coyote/http11/Http11Processor.java | 2 +- .../main/java/org/apache/coyote/http11/request/Request.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index ff63f59184..fc1084cb61 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -65,7 +65,7 @@ private String getResponseString(Request request) throws IOException { Content content = getContent(request); return String.join("\r\n", - "HTTP/1.1 200 OK ", + String.format("%s 200 OK ", request.getHttpVersion()), String.format("Content-Type: %s;charset=utf-8 ", content.getContentType()), "Content-Length: " + content.getContent().getBytes().length + " ", "", diff --git a/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java index 49ad327191..7c7021e36f 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/request/Request.java @@ -22,6 +22,10 @@ public String getTarget() { return requestLine.target(); } + public String getHttpVersion() { + return requestLine.httpVersion(); + } + @Override public String toString() { return "Request{" + From 49c47612ba5668f7c016318102600363359acd35 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 13:38:59 +0900 Subject: [PATCH 16/28] =?UTF-8?q?feat:=20templates=20=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=A0=95=EC=A0=81=ED=8C=8C=EC=9D=BC=EC=9D=84=20=EC=9D=BD?= =?UTF-8?q?=EC=96=B4=EC=98=A4=EA=B8=B0=20=EC=9C=84=ED=95=9C=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/study/build.gradle b/study/build.gradle index 87a1f0313c..da27dc9653 100644 --- a/study/build.gradle +++ b/study/build.gradle @@ -23,6 +23,8 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.assertj:assertj-core:3.26.0' testImplementation 'org.mockito:mockito-core:5.12.0' From 3e389a41a9e8d467a0f228a91a4602eedce6a8d8 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 13:39:49 +0900 Subject: [PATCH 17/28] =?UTF-8?q?feat:=20=ED=9C=B4=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8B=B1=20=EC=BA=90=EC=8B=9C=20=EC=A0=9C=EA=B1=B0=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=EC=85=89=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CacheControllerInterceptor.java | 17 +++++++++++++++++ .../example/cachecontrol/CacheWebConfig.java | 1 + 2 files changed, 18 insertions(+) create mode 100644 study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java diff --git a/study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java b/study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java new file mode 100644 index 0000000000..71e82d99ff --- /dev/null +++ b/study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java @@ -0,0 +1,17 @@ +package cache.com.example.cachecontrol; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +public class CacheControllerInterceptor implements HandlerInterceptor { + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView + ) throws Exception { + response.addHeader("Cache-Control", "no-cache, private"); + HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); + } +} diff --git a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java index 305b1f1e1e..1fa17612d0 100644 --- a/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java +++ b/study/src/main/java/cache/com/example/cachecontrol/CacheWebConfig.java @@ -9,5 +9,6 @@ public class CacheWebConfig implements WebMvcConfigurer { @Override public void addInterceptors(final InterceptorRegistry registry) { + registry.addInterceptor(new CacheControllerInterceptor()); } } From 2932a9fb7ea6369ceaf7ddf5b22a640deb8012dd Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 14:04:21 +0900 Subject: [PATCH 18/28] =?UTF-8?q?feat:=20Http=20=EC=95=95=EC=B6=95=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/main/resources/application.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/study/src/main/resources/application.yml b/study/src/main/resources/application.yml index e3503a5fb9..8b74bdfd88 100644 --- a/study/src/main/resources/application.yml +++ b/study/src/main/resources/application.yml @@ -8,3 +8,6 @@ server: threads: min-spare: 2 max: 2 + compression: + enabled: true + min-response-size: 10 From 134679297427bd87862b8be207da5b94ffaaefd9 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 14:11:20 +0900 Subject: [PATCH 19/28] =?UTF-8?q?feat:=20etag=20=EA=B2=BD=EB=A1=9C?= =?UTF-8?q?=EC=97=90=20ETag=20=EC=BA=90=EC=8B=B1=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/etag/EtagFilterConfiguration.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java index 41ef7a3d9a..68c1232eac 100644 --- a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java +++ b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java @@ -1,12 +1,17 @@ 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() { -// return null; -// } + @Bean + public FilterRegistrationBean shallowEtagHeaderFilter() { + FilterRegistrationBean filterFilterRegistrationBean = + new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); + filterFilterRegistrationBean.addUrlPatterns("/etag"); + return filterFilterRegistrationBean; + } } From 17595c749cdfe20e12f734fc9a1c599dd7020d10 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 14:30:16 +0900 Subject: [PATCH 20/28] =?UTF-8?q?feat:=20=EC=A0=95=EC=A0=81=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=97=90=20=EB=B2=84=EC=A0=80=EB=8B=9D,=20eTag=20?= =?UTF-8?q?=EC=BA=90=EC=8B=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/cachecontrol/CacheControllerInterceptor.java | 4 +++- .../cache/com/example/etag/EtagFilterConfiguration.java | 2 +- .../cache/com/example/version/CacheBustingWebConfig.java | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java b/study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java index 71e82d99ff..360df770b6 100644 --- a/study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java +++ b/study/src/main/java/cache/com/example/cachecontrol/CacheControllerInterceptor.java @@ -11,7 +11,9 @@ public class CacheControllerInterceptor implements HandlerInterceptor { public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView ) throws Exception { - response.addHeader("Cache-Control", "no-cache, private"); + if(!response.containsHeader("Cache-Control")) { + response.addHeader("Cache-Control", "no-cache, private"); + } HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } } diff --git a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java index 68c1232eac..1b3940f1dd 100644 --- a/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java +++ b/study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.java @@ -11,7 +11,7 @@ public class EtagFilterConfiguration { public FilterRegistrationBean shallowEtagHeaderFilter() { FilterRegistrationBean filterFilterRegistrationBean = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); - filterFilterRegistrationBean.addUrlPatterns("/etag"); + filterFilterRegistrationBean.addUrlPatterns("/etag", "/resources/*"); return filterFilterRegistrationBean; } } diff --git a/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java b/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java index 6da6d2c795..8cf8162a46 100644 --- a/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java +++ b/study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java @@ -1,7 +1,10 @@ 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; @@ -20,6 +23,7 @@ public CacheBustingWebConfig(ResourceVersion version) { @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**") - .addResourceLocations("classpath:/static/"); + .addResourceLocations("classpath:/static/") + .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic()); } } From 8895b00090d45c8c8353196d3613127a5206c658 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 14:33:36 +0900 Subject: [PATCH 21/28] =?UTF-8?q?feat:=20=ED=8C=8C=EC=9D=BC=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=ED=95=99=EC=8A=B5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- study/src/test/java/study/FileTest.java | 54 +++---------------------- 1 file changed, 5 insertions(+), 49 deletions(-) diff --git a/study/src/test/java/study/FileTest.java b/study/src/test/java/study/FileTest.java index 6966a862ab..c7f2608670 100644 --- a/study/src/test/java/study/FileTest.java +++ b/study/src/test/java/study/FileTest.java @@ -3,7 +3,9 @@ import static org.assertj.core.api.Assertions.assertThat; import java.io.File; +import java.io.IOException; import java.net.URL; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -37,56 +39,12 @@ class FileTest { final String fileName = "nextstep.txt"; // todo - /*List resoursesFiles = getResourceFile(); - final String actual = resoursesFiles.stream() - .flatMap(resoursesFile -> Arrays.stream(resoursesFile.listFiles())) - .filter(file -> file.getName().equals(fileName)) - .findFirst() - .orElseThrow() - .getName();*/ - - /*File resources = new File("/Users/mac/Desktop/zangsu/wooteco/Level4/java-http/study/src/test/resources"); - final String actual = Arrays.stream(resources.listFiles()) - .filter(file -> file.getName().equals(fileName)) - .findFirst() - .orElseThrow() - .getName();*/ - - // 세상에 몰리 대박 final URL resoucrcesUrl = getClass().getClassLoader().getResource(fileName); String actual = resoucrcesUrl.getFile(); assertThat(actual).endsWith(fileName); } - private List getResourceFile() { - File file = new File(".").getAbsoluteFile(); - - List results = new ArrayList<>(); - addResourcesFile(file, results); - Arrays.stream(file.listFiles()) - .filter(subFile -> subFile.getName().equals("resources")) - .forEach(subFile -> results.add(subFile)); - return results; - } - - private void addResourcesFile(File parent, List results) { - for(File file : parent.listFiles()) { - if (file.isFile() && file.getName().equals("resources")) { - results.add(file); - } else { - addResourcesFile(file, results); - } - } - } - - private File getCurrentProject() { - Path path = Paths.get(""); - File file = path.toAbsolutePath().toFile(); - System.out.println("file = " + file); - return file; - } - /** * 파일 내용 읽기 *

@@ -94,14 +52,12 @@ private File getCurrentProject() { * File, Files 클래스를 사용하여 파일의 내용을 읽어보자. */ @Test - void 파일의_내용을_읽는다() { + void 파일의_내용을_읽는다() throws IOException { final String fileName = "nextstep.txt"; // todo - final Path path = null; - - // todo - final List actual = Collections.emptyList(); + final URL resoucrcesUrl = getClass().getClassLoader().getResource(fileName); + final List actual = Files.readAllLines(Paths.get(resoucrcesUrl.getPath())); assertThat(actual).containsOnly("nextstep"); } From 2bdba9a4cc9512994b913891bfdb2696db4242e3 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 15:07:11 +0900 Subject: [PATCH 22/28] =?UTF-8?q?refactor:=20RequestHandler=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 42 ++++++++----------- .../apache/coyote/http11/RequestHandler.java | 10 +++++ .../http11/exception/NoHandlerException.java | 7 ++++ .../http11/handler/StaticResourceHandler.java | 36 ++++++++++++++++ .../coyote/http11/response/Content.java | 4 ++ 5 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index fc1084cb61..ba67cfe0c9 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -9,9 +9,9 @@ import java.util.List; import org.apache.coyote.Processor; -import org.apache.coyote.http11.request.Method; +import org.apache.coyote.http11.exception.NoHandlerException; +import org.apache.coyote.http11.handler.StaticResourceHandler; import org.apache.coyote.http11.request.Request; -import org.apache.coyote.http11.response.Content; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,11 +20,14 @@ public class Http11Processor implements Runnable, Processor { private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); - + private final List requestHandlers; private final Socket connection; public Http11Processor(Socket connection) { this.connection = connection; + this.requestHandlers = List.of( + new StaticResourceHandler() + ); } @Override @@ -42,7 +45,7 @@ public void process(Socket connection) { Request request = Request.parseFrom(getPlainRequest(requestBufferedReader)); log.info("request : {}", request); - String response = getResponseString(request); + String response = getResponse(request); outputStream.write(response.getBytes()); outputStream.flush(); @@ -51,6 +54,16 @@ public void process(Socket connection) { } } + private String getResponse(Request request) throws IOException { + for (RequestHandler requestHandler : requestHandlers) { + String response = requestHandler.handle(request); + if (response != null) { + return response; + } + } + throw new NoHandlerException("핸들러가 존재하지 않습니다. request : " + request); + } + private List getPlainRequest(BufferedReader requestBufferedReader) throws IOException { List plainRequest = new ArrayList<>(); while (requestBufferedReader.ready()) { @@ -59,25 +72,4 @@ private List getPlainRequest(BufferedReader requestBufferedReader) throw } return Collections.unmodifiableList(plainRequest); } - - private String getResponseString(Request request) throws IOException { - if (request.getMethod() == Method.GET) { - Content content = getContent(request); - - return String.join("\r\n", - String.format("%s 200 OK ", request.getHttpVersion()), - String.format("Content-Type: %s;charset=utf-8 ", content.getContentType()), - "Content-Length: " + content.getContent().getBytes().length + " ", - "", - content.getContent()); - } - return null; - } - - private Content getContent(Request request) throws IOException { - if (request.getTarget().equals("/")) { - return new Content("index.html"); - } - return new Content(request.getTarget()); - } } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java new file mode 100644 index 0000000000..9492e6aee1 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/RequestHandler.java @@ -0,0 +1,10 @@ +package org.apache.coyote.http11; + +import java.io.IOException; + +import org.apache.coyote.http11.request.Request; + +@FunctionalInterface +public interface RequestHandler { + String handle(Request request) throws IOException; +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java b/tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java new file mode 100644 index 0000000000..a8f36e5d4e --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/exception/NoHandlerException.java @@ -0,0 +1,7 @@ +package org.apache.coyote.http11.exception; + +public class NoHandlerException extends RuntimeException { + public NoHandlerException(String message) { + super(message); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java new file mode 100644 index 0000000000..c38def68c1 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java @@ -0,0 +1,36 @@ +package org.apache.coyote.http11.handler; + +import java.io.IOException; +import java.nio.file.NoSuchFileException; + +import org.apache.coyote.http11.RequestHandler; +import org.apache.coyote.http11.request.Method; +import org.apache.coyote.http11.request.Request; +import org.apache.coyote.http11.response.Content; + +public class StaticResourceHandler implements RequestHandler { + + @Override + public String handle(Request request) throws IOException { + if (request.getMethod() != Method.GET) { + return null; + } + + try { + Content content = getContent(request); + return String.join("\r\n", + String.format("%s 200 OK ", request.getHttpVersion()), + String.format("Content-Type: %s;charset=utf-8 ", content.getContentType()), + "Content-Length: " + content.getContent().getBytes().length + " ", + "", + content.getContent()); + } catch (NoSuchFileException e) { + return null; + } + } + + private Content getContent(Request request) throws IOException { + String target = request.getTarget().equals("/") ? "index.html" : request.getTarget(); + return new Content(target); + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/Content.java b/tomcat/src/main/java/org/apache/coyote/http11/response/Content.java index 908f9acce7..f206725f05 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/response/Content.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/Content.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.URL; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; public class Content { private final String contentType; @@ -13,6 +14,9 @@ public Content(String resourceName) throws IOException { this.contentType = determineContentType(resourceName); String path = "static" + resourceName; URL resource = getClass().getClassLoader().getResource(path); + if (resource == null) { + throw new NoSuchFileException("파일 " + resourceName + "이 존재하지 않습니다."); + } this.content = new String(Files.readAllBytes(new File(resource.getPath()).toPath())); } From 84882ed875f65fb5dd24bc84eae4b8ebe897d278 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 16:09:22 +0900 Subject: [PATCH 23/28] =?UTF-8?q?refactor:=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=B1=85=EC=9E=84=EC=9D=84=20Response=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http11/handler/StaticResourceHandler.java | 8 ++------ .../apache/coyote/http11/response/Response.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/response/Response.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java index c38def68c1..56fda64094 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/StaticResourceHandler.java @@ -7,6 +7,7 @@ import org.apache.coyote.http11.request.Method; import org.apache.coyote.http11.request.Request; import org.apache.coyote.http11.response.Content; +import org.apache.coyote.http11.response.Response; public class StaticResourceHandler implements RequestHandler { @@ -18,12 +19,7 @@ public String handle(Request request) throws IOException { try { Content content = getContent(request); - return String.join("\r\n", - String.format("%s 200 OK ", request.getHttpVersion()), - String.format("Content-Type: %s;charset=utf-8 ", content.getContentType()), - "Content-Length: " + content.getContent().getBytes().length + " ", - "", - content.getContent()); + return Response.writeResponse(request, content.getContentType(), content.getContent()); } catch (NoSuchFileException e) { return null; } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/response/Response.java b/tomcat/src/main/java/org/apache/coyote/http11/response/Response.java new file mode 100644 index 0000000000..311c156f24 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/response/Response.java @@ -0,0 +1,14 @@ +package org.apache.coyote.http11.response; + +import org.apache.coyote.http11.request.Request; + +public class Response { + public static String writeResponse(Request request, String contentType, String content) { + return String.join("\r\n", + String.format("%s 200 OK ", request.getHttpVersion()), + String.format("Content-Type: %s;charset=utf-8 ",contentType), + "Content-Length: " + content.getBytes().length + " ", + "", + content); + } +} From f4e8d60b141a49409f02be1fccc2e9d679b1ebe3 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 16:09:44 +0900 Subject: [PATCH 24/28] =?UTF-8?q?refactor:=20Json=20=EC=A7=81=EB=A0=AC?= =?UTF-8?q?=ED=99=94=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tomcat/build.gradle | 3 +++ .../http11/learningTest/ObjectMapperTest.java | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tomcat/src/test/java/org/apache/coyote/http11/learningTest/ObjectMapperTest.java diff --git a/tomcat/build.gradle b/tomcat/build.gradle index 21063b298f..ba598c228d 100644 --- a/tomcat/build.gradle +++ b/tomcat/build.gradle @@ -18,6 +18,9 @@ dependencies { implementation 'ch.qos.logback:logback-classic:1.5.7' implementation 'org.apache.commons:commons-lang3:3.14.0' + //objectMapper + implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.3' + testImplementation 'org.assertj:assertj-core:3.26.0' testImplementation 'org.mockito:mockito-core:5.12.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' diff --git a/tomcat/src/test/java/org/apache/coyote/http11/learningTest/ObjectMapperTest.java b/tomcat/src/test/java/org/apache/coyote/http11/learningTest/ObjectMapperTest.java new file mode 100644 index 0000000000..341af4ddec --- /dev/null +++ b/tomcat/src/test/java/org/apache/coyote/http11/learningTest/ObjectMapperTest.java @@ -0,0 +1,22 @@ +package org.apache.coyote.http11.learningTest; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + +public class ObjectMapperTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + @DisplayName("Object -> Json 직렬화 테스트") + void serializeTest() throws JsonProcessingException { + User user = InMemoryUserRepository.findByAccount("gugu").get(); + + System.out.println(objectMapper.writeValueAsString(user)); + } +} From 30bf46345b0c93319acae09677f84bed620ec8c9 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 16:15:53 +0900 Subject: [PATCH 25/28] =?UTF-8?q?refactor:=20api=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EC=9D=84=20=EC=B2=98=EB=A6=AC=ED=95=A0=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20Handler=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apache/coyote/http11/Http11Processor.java | 2 + .../coyote/http11/handler/MethodHandler.java | 40 +++++++++++++++++++ .../coyote/http11/Http11ProcessorTest.java | 35 +++++++++++++++- 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java index ba67cfe0c9..8424340b4e 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java @@ -10,6 +10,7 @@ import org.apache.coyote.Processor; import org.apache.coyote.http11.exception.NoHandlerException; +import org.apache.coyote.http11.handler.MethodHandler; import org.apache.coyote.http11.handler.StaticResourceHandler; import org.apache.coyote.http11.request.Request; import org.slf4j.Logger; @@ -26,6 +27,7 @@ public class Http11Processor implements Runnable, Processor { public Http11Processor(Socket connection) { this.connection = connection; this.requestHandlers = List.of( + new MethodHandler(), new StaticResourceHandler() ); } diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java new file mode 100644 index 0000000000..5ebec14c93 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java @@ -0,0 +1,40 @@ +package org.apache.coyote.http11.handler; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.coyote.http11.RequestHandler; +import org.apache.coyote.http11.request.Request; +import org.apache.coyote.http11.response.Response; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + +public class MethodHandler implements RequestHandler { + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public String handle(Request request) throws IOException { + String[] targetToken = request.getTarget().split("\\?"); + Map queryParams = new HashMap<>(); + String[] queryParamTokens = targetToken[1].split("&"); + for (String queryParam : queryParamTokens) { + String[] split = queryParam.split("="); + queryParams.put(split[0], split[1]); + } + return Response.writeResponse(request, "application/json", handleMethod(targetToken[0], queryParams)); + } + + private String handleMethod(String endPoint, Map queryParams) throws JsonProcessingException { + if (!endPoint.equals("/login")) { + return null; + } + String account = queryParams.get("account"); + User user = InMemoryUserRepository.findByAccount(account) + .orElseThrow(() -> new IllegalArgumentException(account + " 이름의 유저가 없습니다.")); + return objectMapper.writeValueAsString(user); + } +} diff --git a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java index a3404db146..02e44f4a83 100644 --- a/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java +++ b/tomcat/src/test/java/org/apache/coyote/http11/Http11ProcessorTest.java @@ -10,6 +10,10 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.techcourse.db.InMemoryUserRepository; +import com.techcourse.model.User; + import support.StubSocket; class Http11ProcessorTest { @@ -83,7 +87,36 @@ void css() throws IOException { String contentBody = new String(Files.readAllBytes(new File(resource.getFile()).toPath())); var expected = "HTTP/1.1 200 OK \r\n" + "Content-Type: text/css;charset=utf-8 \r\n" + - String.format("Content-Length: %d \r\n",contentBody.getBytes().length) + + String.format("Content-Length: %d \r\n", contentBody.getBytes().length) + + "\r\n" + + contentBody; + + assertThat(socket.output()).isEqualTo(expected); + } + + @Test + void login() throws IOException { + // given + final String httpRequest = String.join("\r\n", + "GET /login?account=gugu&password=password HTTP/1.1 ", + "Host: localhost:8080 ", + "Connection: keep-alive ", + "", + ""); + + final var socket = new StubSocket(httpRequest); + final Http11Processor processor = new Http11Processor(socket); + final ObjectMapper objectMapper = new ObjectMapper(); + + // when + processor.process(socket); + + // then + User user = InMemoryUserRepository.findByAccount("gugu").get(); + String contentBody = objectMapper.writeValueAsString(user); + var expected = "HTTP/1.1 200 OK \r\n" + + "Content-Type: application/json;charset=utf-8 \r\n" + + String.format("Content-Length: %d \r\n", contentBody.getBytes().length) + "\r\n" + contentBody; From f9e544ee780ea1ecf5bc81956badc9599561ff75 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 16:37:34 +0900 Subject: [PATCH 26/28] =?UTF-8?q?refactor:=20api=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EC=9D=84=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coyote/http11/handler/MethodHandler.java | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java index 5ebec14c93..ff52fa75ff 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java @@ -16,23 +16,43 @@ public class MethodHandler implements RequestHandler { private final ObjectMapper objectMapper = new ObjectMapper(); + private static class MethodRequest { + private final String endPoint; + private final Map queryParams; + + private MethodRequest(String url) { + String[] targetToken = url.split("\\?"); + this.endPoint = targetToken[0]; + + Map queryParams = new HashMap<>(); + String[] queryParamTokens = targetToken[1].split("&"); + for (String queryParam : queryParamTokens) { + String[] split = queryParam.split("="); + queryParams.put(split[0], split[1]); + } + this.queryParams = Map.copyOf(queryParams); + } + + public String getParam(String key) { + return queryParams.get(key); + } + + public String getEndPoint() { + return this.endPoint; + } + } + @Override public String handle(Request request) throws IOException { - String[] targetToken = request.getTarget().split("\\?"); - Map queryParams = new HashMap<>(); - String[] queryParamTokens = targetToken[1].split("&"); - for (String queryParam : queryParamTokens) { - String[] split = queryParam.split("="); - queryParams.put(split[0], split[1]); - } - return Response.writeResponse(request, "application/json", handleMethod(targetToken[0], queryParams)); + MethodRequest methodRequest = new MethodRequest(request.getTarget()); + return Response.writeResponse(request, "application/json", handleMethod(methodRequest)); } - private String handleMethod(String endPoint, Map queryParams) throws JsonProcessingException { - if (!endPoint.equals("/login")) { + private String handleMethod(MethodRequest methodRequest) throws JsonProcessingException { + if (!methodRequest.getEndPoint().equals("/login")) { return null; } - String account = queryParams.get("account"); + String account = methodRequest.getParam("account"); User user = InMemoryUserRepository.findByAccount(account) .orElseThrow(() -> new IllegalArgumentException(account + " 이름의 유저가 없습니다.")); return objectMapper.writeValueAsString(user); From 64559fac4dac6f72cd132bab2fe0ace524237ba2 Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 17:02:01 +0900 Subject: [PATCH 27/28] =?UTF-8?q?refactor:=20=EC=B1=85=EC=9E=84=EC=97=90?= =?UTF-8?q?=20=EB=94=B0=EB=9D=BC=20=ED=81=B4=EB=9E=98=EC=8A=A4=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 --- .../coyote/http11/handler/MethodHandler.java | 28 --------------- .../coyote/http11/handler/MethodRequest.java | 25 ++++++++++++++ .../http11/handler/QueryParameters.java | 34 +++++++++++++++++++ 3 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java create mode 100644 tomcat/src/main/java/org/apache/coyote/http11/handler/QueryParameters.java diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java index ff52fa75ff..8cf18b8065 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodHandler.java @@ -1,8 +1,6 @@ package org.apache.coyote.http11.handler; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import org.apache.coyote.http11.RequestHandler; import org.apache.coyote.http11.request.Request; @@ -16,32 +14,6 @@ public class MethodHandler implements RequestHandler { private final ObjectMapper objectMapper = new ObjectMapper(); - private static class MethodRequest { - private final String endPoint; - private final Map queryParams; - - private MethodRequest(String url) { - String[] targetToken = url.split("\\?"); - this.endPoint = targetToken[0]; - - Map queryParams = new HashMap<>(); - String[] queryParamTokens = targetToken[1].split("&"); - for (String queryParam : queryParamTokens) { - String[] split = queryParam.split("="); - queryParams.put(split[0], split[1]); - } - this.queryParams = Map.copyOf(queryParams); - } - - public String getParam(String key) { - return queryParams.get(key); - } - - public String getEndPoint() { - return this.endPoint; - } - } - @Override public String handle(Request request) throws IOException { MethodRequest methodRequest = new MethodRequest(request.getTarget()); diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java new file mode 100644 index 0000000000..56264a5957 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java @@ -0,0 +1,25 @@ +package org.apache.coyote.http11.handler; + +public class MethodRequest { + private final String endPoint; + private final QueryParameters queryParams; + + public MethodRequest(String url) { + String[] targetToken = url.split("\\?"); + this.endPoint = targetToken[0]; + + if (targetToken.length == 1) { + this.queryParams = QueryParameters.empty(); + } else { + this.queryParams = QueryParameters.parseFrom(targetToken[1]); + } + } + + public String getParam(String key) { + return queryParams.getParam(key); + } + + public String getEndPoint() { + return this.endPoint; + } +} diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/QueryParameters.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/QueryParameters.java new file mode 100644 index 0000000000..a91a8a31b8 --- /dev/null +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/QueryParameters.java @@ -0,0 +1,34 @@ +package org.apache.coyote.http11.handler; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +public class QueryParameters { + private final Map queryParams; + + private QueryParameters(Map queryParams) { + this.queryParams = Map.copyOf(queryParams); + } + + public static QueryParameters empty() { + return new QueryParameters(Collections.emptyMap()); + } + + public static QueryParameters parseFrom(String queryStrings) { + Map queryParams = new HashMap<>(); + String[] queryParamTokens = queryStrings.split("&"); + for (String queryParam : queryParamTokens) { + String[] split = queryParam.split("="); + queryParams.put(split[0], split[1]); + } + return new QueryParameters(queryParams); + } + + public String getParam(String key) { + return Optional.ofNullable(queryParams.get(key)) + .orElseThrow(() -> new NoSuchElementException(key + " 에 해당하는 값이 존재하지 않습니다.")); + } +} From f1eb2bfb322ebb08e8fb2c8433d807b25518fd3a Mon Sep 17 00:00:00 2001 From: zangsu Date: Fri, 6 Sep 2024 17:08:14 +0900 Subject: [PATCH 28/28] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=EC=B2=98?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=84=A4=EC=9D=B4=EB=B0=8D=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 --- ...eryParameters.java => MethodQueryParameters.java} | 12 ++++++------ .../apache/coyote/http11/handler/MethodRequest.java | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) rename tomcat/src/main/java/org/apache/coyote/http11/handler/{QueryParameters.java => MethodQueryParameters.java} (70%) diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/QueryParameters.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodQueryParameters.java similarity index 70% rename from tomcat/src/main/java/org/apache/coyote/http11/handler/QueryParameters.java rename to tomcat/src/main/java/org/apache/coyote/http11/handler/MethodQueryParameters.java index a91a8a31b8..61bc14b1b9 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/QueryParameters.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodQueryParameters.java @@ -6,25 +6,25 @@ import java.util.NoSuchElementException; import java.util.Optional; -public class QueryParameters { +public class MethodQueryParameters { private final Map queryParams; - private QueryParameters(Map queryParams) { + private MethodQueryParameters(Map queryParams) { this.queryParams = Map.copyOf(queryParams); } - public static QueryParameters empty() { - return new QueryParameters(Collections.emptyMap()); + public static MethodQueryParameters empty() { + return new MethodQueryParameters(Collections.emptyMap()); } - public static QueryParameters parseFrom(String queryStrings) { + public static MethodQueryParameters parseFrom(String queryStrings) { Map queryParams = new HashMap<>(); String[] queryParamTokens = queryStrings.split("&"); for (String queryParam : queryParamTokens) { String[] split = queryParam.split("="); queryParams.put(split[0], split[1]); } - return new QueryParameters(queryParams); + return new MethodQueryParameters(queryParams); } public String getParam(String key) { diff --git a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java index 56264a5957..e18caf0cc6 100644 --- a/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java +++ b/tomcat/src/main/java/org/apache/coyote/http11/handler/MethodRequest.java @@ -2,16 +2,16 @@ public class MethodRequest { private final String endPoint; - private final QueryParameters queryParams; + private final MethodQueryParameters queryParams; public MethodRequest(String url) { String[] targetToken = url.split("\\?"); this.endPoint = targetToken[0]; if (targetToken.length == 1) { - this.queryParams = QueryParameters.empty(); + this.queryParams = MethodQueryParameters.empty(); } else { - this.queryParams = QueryParameters.parseFrom(targetToken[1]); + this.queryParams = MethodQueryParameters.parseFrom(targetToken[1]); } }