Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[톰캣 구현하기 1, 2단계] 하디(전동혁) 미션 제출합니다. #323

Merged
merged 50 commits into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
0d6a25a
test: IOStreamTest 테스트 작성
jundonghyuk Sep 3, 2023
09fde36
test: FileTest 테스트 작성
jundonghyuk Sep 3, 2023
da5c247
refactor: Path 수정
jundonghyuk Sep 3, 2023
78a9e6a
feat: Util성 Http enum 구현
jundonghyuk Sep 3, 2023
5d0ca81
feat: HttpRequest, HttpResponse 구현
jundonghyuk Sep 3, 2023
f928ff5
feat: Handler 구현
jundonghyuk Sep 3, 2023
885d383
feat: HandlerMapping, HandlerMatcher 구현
jundonghyuk Sep 3, 2023
59cf38e
feat: HttpProcessor 구현
jundonghyuk Sep 3, 2023
a355de6
feat: HttpHeader enum 구현
jundonghyuk Sep 3, 2023
15b6125
feat: HttpHeader, HttpStatus 이넘 값 추가
jundonghyuk Sep 3, 2023
279ea71
feat: Redirect 와 에러 페이지 추가
jundonghyuk Sep 3, 2023
b56a924
refactor: 문자열 수정
jundonghyuk Sep 3, 2023
326ef0d
feat: 로그인 post로 변경
jundonghyuk Sep 4, 2023
fc13eab
feat: request에 바디 추가
jundonghyuk Sep 4, 2023
8406320
feat: 회원가입 기능 구현
jundonghyuk Sep 4, 2023
07e2909
refactor: HandlerMapping 변경
jundonghyuk Sep 4, 2023
c9a5c30
refactor: 세션 추가
jundonghyuk Sep 4, 2023
0eccc60
feat: ExceptionHandler 추가
jundonghyuk Sep 4, 2023
c59d682
refactor: 세션 추가 및 ExceptionHandler 적용
jundonghyuk Sep 4, 2023
a197987
refactor: statusText 대문자로 변경
jundonghyuk Sep 4, 2023
9347f5e
refactor: 출력문 제거
jundonghyuk Sep 4, 2023
949b20c
fix: key type 불일치 버그 수정
jundonghyuk Sep 4, 2023
2740586
refactor: null 방어
jundonghyuk Sep 4, 2023
60292e6
refactor: 기본 생성자 제거
jundonghyuk Sep 4, 2023
7cd5a6c
refactor: 생성자 변경
jundonghyuk Sep 4, 2023
b84534b
refactor: 정적파일 내려주는 중복 핸들러 제거
jundonghyuk Sep 7, 2023
bcdf51d
refactor: Enum final 추가 및 변경
jundonghyuk Sep 7, 2023
36b1f89
refactor: Body 클래스 분리
jundonghyuk Sep 7, 2023
d95af1a
refactor: Header 클래스 분리
jundonghyuk Sep 7, 2023
62155dc
refactor: StartLine 클래스 분리
jundonghyuk Sep 7, 2023
3cd5c91
refactor: 세션 및 쿠키 분리
jundonghyuk Sep 7, 2023
08ff2c4
refactor: RequestTarget 분리(EndPoint)
jundonghyuk Sep 7, 2023
4bd59e3
refactor: Query 파싱 클래스 추가
jundonghyuk Sep 7, 2023
c8abcb1
refactor: StatusLine 클래스 분리
jundonghyuk Sep 7, 2023
400ffdc
refactor: ExceptionHandler 수정
jundonghyuk Sep 7, 2023
4e966be
refactor: Static한 파일을 내려주는 핸들러 통합
jundonghyuk Sep 7, 2023
7df6cbc
feat: InputStream으로 부터 읽는 클래스 구현
jundonghyuk Sep 7, 2023
049fdb2
refactor: HttpRequest 클래스 책임 분리
jundonghyuk Sep 7, 2023
e8350bf
refactor: HttpResponse 클래스 책임 분리
jundonghyuk Sep 7, 2023
a1f1b28
feat: HttpResponse를 형식에 맞게 출력해주는 클래스 구현
jundonghyuk Sep 7, 2023
021cb21
refactor: HelloHandler 변경
jundonghyuk Sep 7, 2023
069e3cc
refactor: LoginHandler 변경
jundonghyuk Sep 7, 2023
35ad188
refactor: RegisterHandler 변경
jundonghyuk Sep 7, 2023
83d6a4d
refactor: HandlerMapping 변경
jundonghyuk Sep 7, 2023
3ca560a
refactor: Processor 단순화
jundonghyuk Sep 7, 2023
8df57c2
refactor: 환경에 맞는 줄바꿈으로 변경
jundonghyuk Sep 7, 2023
7360a8d
refactor: 테스트 코드 컨텐트 타입 수정
jundonghyuk Sep 7, 2023
f1f3c4d
refactor: stacktrace 제거
jundonghyuk Sep 7, 2023
af23de1
refactor: header value가 없을 시 continue
jundonghyuk Sep 7, 2023
4a3a635
refactor: 불필요한 클래스 삭제
jundonghyuk Sep 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions study/src/test/java/study/FileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.nio.file.Paths;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -18,7 +20,7 @@ class FileTest {

/**
* resource 디렉터리 경로 찾기
*
* <p>
* File 객체를 생성하려면 파일의 경로를 알아야 한다.
* 자바 애플리케이션은 resource 디렉터리에 HTML, CSS 같은 정적 파일을 저장한다.
* resource 디렉터리의 경로는 어떻게 알아낼 수 있을까?
Expand All @@ -28,26 +30,27 @@ class FileTest {
final String fileName = "nextstep.txt";

// todo
final String actual = "";
String path = getClass().getClassLoader().getResource(fileName).getPath();
String actual = path;

assertThat(actual).endsWith(fileName);
}

/**
* 파일 내용 읽기
*
* <p>
* 읽어온 파일의 내용을 I/O Stream을 사용해서 사용자에게 전달 해야 한다.
* File, Files 클래스를 사용하여 파일의 내용을 읽어보자.
*/
@Test
void 파일의_내용을_읽는다() {
void 파일의_내용을_읽는다() throws IOException {
final String fileName = "nextstep.txt";

// todo
final Path path = null;
final Path path = Paths.get("src/test/resources" + "/" + fileName);

// todo
final List<String> actual = Collections.emptyList();
final List<String> actual = Files.readAllLines(path);

assertThat(actual).containsOnly("nextstep");
}
Expand Down
57 changes: 43 additions & 14 deletions study/src/test/java/study/IOStreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@
import org.junit.jupiter.api.Test;

import java.io.*;
import java.nio.charset.StandardCharsets;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;

/**
* 자바는 스트림(Stream)으로부터 I/O를 사용한다.
* 입출력(I/O)은 하나의 시스템에서 다른 시스템으로 데이터를 이동 시킬 때 사용한다.
*
* <p>
jundonghyuk marked this conversation as resolved.
Show resolved Hide resolved
* InputStream은 데이터를 읽고, OutputStream은 데이터를 쓴다.
* FilterStream은 InputStream이나 OutputStream에 연결될 수 있다.
* FilterStream은 읽거나 쓰는 데이터를 수정할 때 사용한다. (e.g. 암호화, 압축, 포맷 변환)
*
* <p>
* Stream은 데이터를 바이트로 읽고 쓴다.
* 바이트가 아닌 텍스트(문자)를 읽고 쓰려면 Reader와 Writer 클래스를 연결한다.
* Reader, Writer는 다양한 문자 인코딩(e.g. UTF-8)을 처리할 수 있다.
Expand All @@ -26,7 +27,7 @@ class IOStreamTest {

/**
* OutputStream 학습하기
*
* <p>
* 자바의 기본 출력 클래스는 java.io.OutputStream이다.
* OutputStream의 write(int b) 메서드는 기반 메서드이다.
* <code>public abstract void write(int b) throws IOException;</code>
Expand All @@ -39,7 +40,7 @@ class OutputStream_학습_테스트 {
* OutputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 쓰기 위해 write(int b) 메서드를 사용한다.
* 예를 들어, FilterOutputStream은 파일로 데이터를 쓸 때,
* 또는 DataOutputStream은 자바의 primitive type data를 다른 매체로 데이터를 쓸 때 사용한다.
*
* <p>
* write 메서드는 데이터를 바이트로 출력하기 때문에 비효율적이다.
* <code>write(byte[] data)</code>와 <code>write(byte b[], int off, int len)</code> 메서드는
* 1바이트 이상을 한 번에 전송 할 수 있어 훨씬 효율적이다.
Expand All @@ -54,6 +55,8 @@ class OutputStream_학습_테스트 {
* OutputStream 객체의 write 메서드를 사용해서 테스트를 통과시킨다
*/

outputStream.write(bytes);

final String actual = outputStream.toString();

assertThat(actual).isEqualTo("nextstep");
Expand All @@ -63,7 +66,7 @@ class OutputStream_학습_테스트 {
/**
* 효율적인 전송을 위해 스트림에서 버퍼링을 사용 할 수 있다.
* BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다.
*
* <p>
* 버퍼링을 사용하면 OutputStream을 사용할 때 flush를 사용하자.
* flush() 메서드는 버퍼가 아직 가득 차지 않은 상황에서 강제로 버퍼의 내용을 전송한다.
* Stream은 동기(synchronous)로 동작하기 때문에 버퍼가 찰 때까지 기다리면
Expand All @@ -78,6 +81,7 @@ class OutputStream_학습_테스트 {
* flush를 사용해서 테스트를 통과시킨다.
* ByteArrayOutputStream과 어떤 차이가 있을까?
*/
outputStream.flush();

verify(outputStream, atLeastOnce()).flush();
outputStream.close();
Expand All @@ -96,19 +100,20 @@ class OutputStream_학습_테스트 {
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
outputStream.close();

verify(outputStream, atLeastOnce()).close();
}
}

/**
* InputStream 학습하기
*
* <p>
* 자바의 기본 입력 클래스는 java.io.InputStream이다.
* InputStream은 다른 매체로부터 바이트로 데이터를 읽을 때 사용한다.
* InputStream의 read() 메서드는 기반 메서드이다.
* <code>public abstract int read() throws IOException;</code>
*
* <p>
* InputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 읽기 위해 read() 메서드를 사용한다.
*/
@Nested
Expand All @@ -128,7 +133,16 @@ class InputStream_학습_테스트 {
* todo
* inputStream에서 바이트로 반환한 값을 문자열로 어떻게 바꿀까?
*/
final String actual = "";
String actual = "";
StringBuilder stringBuilder = new StringBuilder();
try (Reader reader = new BufferedReader(new InputStreamReader
(inputStream, StandardCharsets.UTF_8))) {
int c = 0;
while ((c = reader.read()) != -1) {
stringBuilder.append((char) c);
}
}
actual = stringBuilder.toString();

assertThat(actual).isEqualTo("🤩");
assertThat(inputStream.read()).isEqualTo(-1);
Expand All @@ -141,21 +155,27 @@ class InputStream_학습_테스트 {
*/
@Test
void InputStream은_사용하고_나서_close_처리를_해준다() throws IOException {
final InputStream inputStream = mock(InputStream.class);
InputStream inputStream = mock(InputStream.class);

/**
* todo
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
try (InputStreamReader inputStreamReader = new InputStreamReader(inputStream);) {

} catch (Exception e) {

} finally {

}
verify(inputStream, atLeastOnce()).close();
}
}

/**
* FilterStream 학습하기
*
* <p>
* 필터는 필터 스트림, reader, writer로 나뉜다.
* 필터는 바이트를 다른 데이터 형식으로 변환 할 때 사용한다.
* reader, writer는 UTF-8, ISO 8859-1 같은 형식으로 인코딩된 텍스트를 처리하는 데 사용된다.
Expand All @@ -169,12 +189,12 @@ class FilterStream_학습_테스트 {
* 버퍼 크기를 지정하지 않으면 버퍼의 기본 사이즈는 얼마일까?
*/
@Test
void 필터인_BufferedInputStream를_사용해보자() {
void 필터인_BufferedInputStream를_사용해보자() throws IOException {
final String text = "필터에 연결해보자.";
final InputStream inputStream = new ByteArrayInputStream(text.getBytes());
final InputStream bufferedInputStream = null;
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

final byte[] actual = new byte[0];
final byte[] actual = bufferedInputStream.readAllBytes();

assertThat(bufferedInputStream).isInstanceOf(FilterInputStream.class);
assertThat(actual).isEqualTo("필터에 연결해보자.".getBytes());
Expand Down Expand Up @@ -203,9 +223,18 @@ class InputStreamReader_학습_테스트 {
"😇🙂🙃😉😌😍🥰😘😗😙😚",
"😋😛😝😜🤪🤨🧐🤓😎🥸🤩",
"");
final InputStream inputStream = new ByteArrayInputStream(emoji.getBytes());

final StringBuilder actual = new StringBuilder();
final InputStream inputStream = new ByteArrayInputStream(emoji.getBytes());

try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String temp;
while ((temp = br.readLine()) != null) {
actual.append(temp + "\r\n");
}
} catch (Exception e) {

}

assertThat(actual).hasToString(emoji);
}
Expand Down
20 changes: 9 additions & 11 deletions tomcat/src/main/java/org/apache/catalina/Manager.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.apache.catalina;

import jakarta.servlet.http.HttpSession;
import org.apache.coyote.http11.Session;

import java.io.IOException;

Expand Down Expand Up @@ -29,28 +29,26 @@ public interface Manager {
*
* @param session Session to be added
*/
void add(HttpSession session);
void add(Session session);

/**
* Return the active Session, associated with this Manager, with the
* specified session id (if any); otherwise return <code>null</code>.
*
* @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;
Session findSession(String id) throws IOException;

/**
* Remove this Session from the active Sessions for this Manager.
*
* @param session Session to be removed
*/
void remove(HttpSession session);
void remove(Session session);
}
9 changes: 9 additions & 0 deletions tomcat/src/main/java/org/apache/coyote/handler/Handler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.apache.coyote.handler;

import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

public interface Handler {

HttpResponse handle(HttpRequest httpRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.apache.coyote.handler.dynamichandler;

import org.apache.coyote.handler.Handler;
import org.apache.coyote.http11.ContentType;
import org.apache.coyote.http11.Header;
import org.apache.coyote.http11.HttpHeader;
import org.apache.coyote.http11.Body;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;
import org.apache.coyote.http11.response.HttpStatus;
import org.apache.coyote.http11.response.StatusLine;

import java.util.LinkedHashMap;
import java.util.Map;

public class HelloHandler implements Handler {

@Override
public HttpResponse handle(HttpRequest httpRequest) {
StatusLine statusLine = new StatusLine(httpRequest.httpVersion(), HttpStatus.OK);

Body body = new Body("Hello world!");

Map<String, String> headers = new LinkedHashMap<>();
headers.put(HttpHeader.CONTENT_TYPE.value(), ContentType.TEXT_HTML.value());
headers.put(HttpHeader.CONTENT_LENGTH.value(), String.valueOf(body.message().getBytes().length));
Header header = new Header(headers);

return new HttpResponse(statusLine, header, body);
}
}
Loading