-
Notifications
You must be signed in to change notification settings - Fork 311
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[톰캣 구현하기 - 3단계] 안나(김민겸) 미션 제출합니다. (#652)
* fix: remove implementation logback-classic on gradle (#501) * fix: add threads min-spare configuration on properties (#502) * [톰캣 구현하기 1, 2단계] 안나 (김민겸) 미션 제출합니다. (#571) * test: 학습 테스트 진행 * feat: `/index.html`에 접근했을 때 static/index.html 파일이 보여지도록 구현 * feat: 자원에 따라 다른 Conent-Type으로 응답을 보내도록 수정 * fix: remove implementation logback-classic on gradle (#501) * fix: 공백 처리 때문에 index.html이 불러와지지 않는 현상 해결 * feat: 로그인 요청 시 쿼리 파라미터를 파싱하는 기능 구현 * fix: add threads min-spare configuration on properties (#502) * feat: 로그인에 성공하거나 실패한 경우 다른 페이지로 리다이렉트하는 * feat: POST 요청으로 회원 가입 시 요청 본문에서 정보를 가져와 사용자 저장하는 기능 구현 * feat: 로그인 시 POST 요청을 보내도록 수정 * feat: 로그인 시 세션 아이디를 쿠키에 등록하는 기능 구현 * feat: 쿠키에 JSESSIONID가 없을 때 Set-Cookie를 발급하는 기능 구현 * feat: 이미 로그인한 회원의 경우 로그인 페이지에 접근 불가하도록 구현 * refactor: 쿠키가 없을 때 일반 페이지에 접근하면 세션 아이디를 주지 않음 * feat: HTTP 활용 학습 테스트 진행 * refactor: 뭉친 코드를 클래스 분리하여 리팩토링 * fix: JSESSIONID를 추가하지 않아 로그인되지 않는 문제 해결 * fix: 세션 아이디가 달라서 로그인 시 로그인 페이지가 접속되는 현상 해결 * refactor: 기존 코드 주석 제거 * style: 주석 제거 및 컨벤션 맞추기 * refactor: 미구현된 파일 제거 * refactor: 필터를 사용하여 ETag를 지정하는 것으로 변경 * refactor: 인터셉터에서 CacheControl을 적용할 수 있도록 수정 * refactor: Content-Length 헤더 이름을 상수화 * refactor: 정적 파일을 한 번에 처리하도록 리팩토링 * fix: Json 파일을 보내는 경우를 고려하여 MediaType 수정 * refactor: 로그인 시 쿠키 세션을 꺼내오는 코드 가독성 개선 * refactor: 요청한 사용자 정보가 없는 경우 401 페이지를 보여주도록 수정 * refactor: 쿠키의 키값을 상수화하여 리팩토링 --------- Co-authored-by: Gyeongho Yang <[email protected]> * refactor: Method, Body, Path 를 VO로 분리 * refactor: HttpResponse와 하위 요소들을 VO로 분리 * refactor: HttpResponse를 활용해 응답을 보내는 코드 리팩토링 * refactor: Content-Type을 객체로 생성하여 생성 로직 위임 * refactor: 응답 본문을 반환하는 부분을 객체로 대체 * refactor: 생성자와 요청 HTTP 생성 용 정적 팩토리 메서드 분리 * refactor: initialLine을 requestLine으로 변수명 변경 * refactor: 서블릿 컨테이너를 사용해서 요청을 처리하도록 수정 * refactor: 동적 요청에 대해 분기하는 HandlerMapping 구현 * refactor: Servlet이 적절한 컨트롤러를 꺼내어 처리하도록 구현 * refactor: HttpResponse 빈 객체 생성 후 값을 대입할 수 있도록 수정 * refactor: 응답을 출력하는 역할을 하는 클래스 분리 * feat: 로그인을 담당하는 컨트롤러 구현 * feat: 회원 저장을 담당하는 Controller 구현 * feat: 정적 파일 처리를 담당하는 Controller 구현 * refactor: 분기 처리를 구현 컨트롤러에게 위임하여 로직 개선 * refactor: Body에서 속성을 파싱할 수 있도록 Properties 클래스 분리 * fix: 로그인 페이지가 출력되지 않는 버그 해결 * fix: 세션 정보가 조회되지 않는 현상 해결 * fix: 실패하는 테스트 케이스 수정 * feat: Executors로 Thread Pool 적용 * refactor: 기존의 Controller로 명명한 클래스 이름을 Servlet으로 수정 * test: 로그인 및 회원가입 서블릿 테스트 구현 * refactor: 필요한 설정 값을 상수화하도록 수정 * style: 클래스 상단 개행 컨벤션 맞춤 * refactor: 정적 파일 처리 시 . 을 붙여 확장자 판별 * refactor: 모든 헤더 키를 상수화 * refactor: 정적 메서드의 이름을 직관적으로 변경 * refactor: HTTP 파싱을 위한 Delimter 를 전부 상수화 * refactor: 세션 값을 추출하는 메서드를 분리 * refactor: RequestLine과 ResponseLine으로 객체를 추상화 * refactor: 헤더 키를 상수화하여 생성하도록 수정 * fix: 인덱스 페이지가 연결되지 않는 현상 해결 * refactor: GET, POST 이외의 메소드 요청이 온다면 405를 반환 * refactor: 프로퍼티를 HttpRequest에서 바로 꺼내오도록 설정 * refactor: 로그인이 실패한 경우 401 페이지를 응답 * refactor: RequestLine에서 한번에 처리하도록 수정 * refactor: 이미 존재하는 유저가 아니라면 저장하도록 수정 * fix: 불일치 메서드명 수정 * fix: 요청과 응답이 동작하지 않는 문제 해결 * refactor: ContentLength가 0 이하인 경우 예외처리 * refactor: 정적 메서드의 이름을 수정 * fix: 패스워드가 조회되지 않는 문제 해결 * fix: 루트경로 입력시 Hello, World가 보여지도록 수정 * test: 실패하는 테스트 케이스 수정 * fix: 잘못 올라간 파일 수정 --------- Co-authored-by: Gyeongho Yang <[email protected]>
- Loading branch information
1 parent
37b1313
commit 147fc92
Showing
36 changed files
with
936 additions
and
345 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 30 additions & 45 deletions
75
tomcat/src/main/java/org/apache/coyote/http11/Http11Processor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,47 @@ | ||
package org.apache.coyote.http11; | ||
|
||
|
||
import com.techcourse.db.InMemoryUserRepository; | ||
import com.techcourse.exception.UncheckedServletException; | ||
import com.techcourse.model.User; | ||
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.HttpRequest; | ||
import org.apache.coyote.http11.request.RequestHandler; | ||
import org.apache.coyote.http11.session.SessionManager; | ||
import org.apache.coyote.http11.response.HttpResponse; | ||
import org.apache.coyote.http11.response.ResponsePrinter; | ||
import org.apache.coyote.http11.servlet.ServletContainer; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.io.OutputStream; | ||
import java.net.Socket; | ||
import java.net.URL; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
public class Http11Processor implements Runnable, Processor { | ||
private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); | ||
|
||
private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); | ||
|
||
private final Socket connection; | ||
private static final Map<String, String> httpRequestHeader = new HashMap<>(); | ||
private static final String sessionId = "JSESSIONID=sessionId"; | ||
private final Socket connection; | ||
|
||
public Http11Processor(final Socket connection) { | ||
this.connection = connection; | ||
} | ||
public Http11Processor(final Socket connection) { | ||
this.connection = connection; | ||
} | ||
|
||
@Override | ||
public void run() { | ||
log.info("connect host: {}, port: {}", connection.getInetAddress(), connection.getPort()); | ||
process(connection); | ||
} | ||
@Override | ||
public void run() { | ||
log.info("connect host: {}, port: {}", connection.getInetAddress(), connection.getPort()); | ||
process(connection); | ||
} | ||
|
||
@Override | ||
public void process(final Socket connection) { | ||
try (final var inputStream = connection.getInputStream(); | ||
final var outputStream = connection.getOutputStream()) { | ||
@Override | ||
public void process(final Socket connection) { | ||
try (final var inputStream = connection.getInputStream(); | ||
final var outputStream = connection.getOutputStream()) { | ||
|
||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); | ||
HttpRequest httpRequest = new HttpRequest(reader); | ||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); | ||
HttpRequest request = new HttpRequest(reader); | ||
HttpResponse response = new HttpResponse(); | ||
|
||
RequestHandler requestHandler = new RequestHandler(httpRequest, outputStream); | ||
requestHandler.handleRequest(); | ||
new ServletContainer().invoke(request, response); | ||
|
||
} catch (IOException e) { | ||
log.error(e.getMessage(), e); | ||
} | ||
} | ||
new ResponsePrinter(outputStream).print(response); | ||
} catch (IOException e) { | ||
log.error(e.getMessage(), e); | ||
} | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
tomcat/src/main/java/org/apache/coyote/http11/common/Body.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.apache.coyote.http11.common; | ||
|
||
import static org.apache.coyote.http11.common.HttpDelimiter.*; | ||
import static org.apache.coyote.http11.common.HeaderKey.*; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.util.Arrays; | ||
|
||
public record Body(String value) { | ||
public static Body parseRequestBody(Headers headers, BufferedReader reader) throws IOException { | ||
return new Body(parseBody(headers, reader)); | ||
} | ||
|
||
private static String parseBody(Headers headers, BufferedReader reader) throws IOException { | ||
String contentLength = headers.getValue(CONTENT_LENGTH); | ||
if (contentLength == null) { | ||
return null; | ||
} | ||
|
||
int length = Integer.parseInt(contentLength); | ||
if (length > 0) { | ||
char[] body = new char[length]; | ||
reader.read(body, 0, length); | ||
return new String(body); | ||
} else if (length < 0) { | ||
throw new IOException("Invalid Content-Length: " + length); | ||
} | ||
return null; | ||
} | ||
|
||
public int getContentLength() { | ||
return this.value.getBytes().length; | ||
} | ||
|
||
public Properties parseProperty() { | ||
Properties properties = new Properties(); | ||
Arrays.asList(value.split(BODY_PROPERTY_DELIMITER.getValue())) | ||
.forEach(properties::add); | ||
return properties; | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
tomcat/src/main/java/org/apache/coyote/http11/common/ContentType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package org.apache.coyote.http11.common; | ||
|
||
public enum ContentType { | ||
APPLICATION_JSON("application/json"), | ||
TEXT_CSS("text/css"), | ||
TEXT_HTML("text/html"), | ||
TEXT_JAVASCRIPT("text/javascript"), | ||
; | ||
|
||
private final String value; | ||
|
||
ContentType(String value) { | ||
this.value = value; | ||
} | ||
|
||
public static ContentType fromPath(String path) { | ||
if (path.endsWith(".css")) { | ||
return ContentType.TEXT_CSS; | ||
} | ||
if (path.endsWith(".js")) { | ||
return ContentType.APPLICATION_JSON; | ||
} | ||
if (path.endsWith(".html")) { | ||
return ContentType.TEXT_HTML; | ||
} | ||
return ContentType.APPLICATION_JSON; | ||
} | ||
|
||
public String getValue() { | ||
return value; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
tomcat/src/main/java/org/apache/coyote/http11/common/HeaderKey.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.apache.coyote.http11.common; | ||
|
||
public enum HeaderKey { | ||
CONTENT_LENGTH("Content-Length"), | ||
CONTENT_TYPE("Content-Type"), | ||
COOKIE("Cookie"), | ||
SET_COOKIE("Set-Cookie"), | ||
LOCATION("Location") | ||
; | ||
|
||
private final String value; | ||
|
||
HeaderKey(String value) { | ||
this.value = value; | ||
} | ||
|
||
public String getValue() { | ||
return value; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
tomcat/src/main/java/org/apache/coyote/http11/common/Headers.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.apache.coyote.http11.common; | ||
|
||
import static org.apache.coyote.http11.common.HttpDelimiter.*; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public record Headers(Map<String, String> headers) { | ||
public Headers() { | ||
this(new HashMap<>()); | ||
} | ||
|
||
public static Headers parseRequestHeader(BufferedReader reader) throws IOException { | ||
HashMap<String, String> headers = new HashMap<>(); | ||
String line; | ||
while ((line = reader.readLine()) != null && !line.isEmpty()) { | ||
String[] header = line.split(HEADER_KEY_VALUE_DELIMITER.getValue()); | ||
headers.put(header[0].trim(), header[1].trim()); | ||
} | ||
return new Headers(headers); | ||
} | ||
|
||
public void add(HeaderKey key, String value) { | ||
headers.put(key.getValue(), value); | ||
} | ||
|
||
public String getValue(HeaderKey headerKey) { | ||
return headers.get(headerKey.getValue()); | ||
} | ||
|
||
public String generatePlainText() { | ||
StringBuilder sb = new StringBuilder(); | ||
headers().forEach((key, value) -> { | ||
sb.append(String.format("%s: %s \r\n", key, value)); | ||
}); | ||
return sb.toString(); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
tomcat/src/main/java/org/apache/coyote/http11/common/HttpDelimiter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.apache.coyote.http11.common; | ||
|
||
public enum HttpDelimiter { | ||
REQUEST_LINE_DELIMITER(" "), | ||
BODY_PROPERTY_DELIMITER("&"), | ||
BODY_KEY_VALUE_DELIMITER("="), | ||
SESSION_DELIMITER("; "), | ||
HEADER_KEY_VALUE_DELIMITER(":") | ||
; | ||
|
||
private final String value; | ||
|
||
HttpDelimiter(String value) { | ||
this.value = value; | ||
} | ||
|
||
public String getValue() { | ||
return value; | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
tomcat/src/main/java/org/apache/coyote/http11/common/Properties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package org.apache.coyote.http11.common; | ||
|
||
import static org.apache.coyote.http11.common.HttpDelimiter.*; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class Properties { | ||
private static final int KEY_INDEX_OF_PROPERTY = 0; | ||
private static final int VALUE_INDEX_OF_PROPERTY = 1; | ||
|
||
private final Map<String, String> properties; | ||
|
||
public Properties() { | ||
this.properties = new HashMap<>(); | ||
} | ||
|
||
public void add(String rawProperty) { | ||
String key = rawProperty.split(BODY_KEY_VALUE_DELIMITER.getValue())[KEY_INDEX_OF_PROPERTY]; | ||
String value = rawProperty.split(BODY_KEY_VALUE_DELIMITER.getValue())[VALUE_INDEX_OF_PROPERTY]; | ||
this.properties.put(key, value); | ||
} | ||
|
||
public String get(String key) { | ||
return properties.get(key); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
tomcat/src/main/java/org/apache/coyote/http11/common/VersionOfProtocol.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.apache.coyote.http11.common; | ||
|
||
import static org.apache.coyote.http11.common.HttpDelimiter.*; | ||
|
||
import java.util.Objects; | ||
|
||
public record VersionOfProtocol(String value) { | ||
private static final int INDEX_OF_VERSION_OF_PROTOCOL = 2; | ||
|
||
public static VersionOfProtocol parseReqeustToVersionOfProtocol(String requestLine) { | ||
return new VersionOfProtocol(requestLine.split(REQUEST_LINE_DELIMITER.getValue())[INDEX_OF_VERSION_OF_PROTOCOL]); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
VersionOfProtocol that = (VersionOfProtocol)o; | ||
return Objects.equals(value, that.value); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hashCode(value); | ||
} | ||
} |
Oops, something went wrong.