Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
fed02f6
fix: remove implementation logback-classic on gradle (#501)
geoje Sep 5, 2024
7e91356
fix: add threads min-spare configuration on properties (#502)
geoje Sep 5, 2024
44661a3
feat: index.html 응답 구현
le2sky Sep 3, 2024
d11ca3b
refactor: 응답값과 contentType 자료구조로 포장
le2sky Sep 3, 2024
7a15bf7
feat: css, javascript 파일 지원
le2sky Sep 3, 2024
436a244
feat: login.html 응답 구현
le2sky Sep 4, 2024
bd9e29a
docs: todo list 작성
le2sky Sep 4, 2024
6d95afc
refactor: query parameter 책임 분리
le2sky Sep 5, 2024
172d7c5
refactor: process 메서드 가독성 개선
le2sky Sep 5, 2024
3a92560
fix: javascript contentType 변경
le2sky Sep 5, 2024
314b36a
test: 누락된 쿼리 파라미터 테스트 추가
le2sky Sep 5, 2024
8107ba5
refactor: header 책임 분리
le2sky Sep 5, 2024
8c99626
refactor: 패키지 이동
le2sky Sep 5, 2024
281d9d3
fix: header pair 구분자 변경
le2sky Sep 5, 2024
ccecee0
refactor: 정적 파일 핸들링 책임 분리
le2sky Sep 5, 2024
2506893
refactor: login 책임 분리
le2sky Sep 5, 2024
c0b8dfc
refactor: handler 추상화
le2sky Sep 5, 2024
8780caf
refactor: 추상화된 핸들러 사용하도록 변경
le2sky Sep 5, 2024
b7acd82
fix: */* 타입 처리하도록 변경
le2sky Sep 5, 2024
f852512
fix: hello handler hello.html 반환하도록 변경
le2sky Sep 5, 2024
704823c
refactor: 불필요한 로그 제거
le2sky Sep 5, 2024
3b55376
chore: import 최적화
le2sky Sep 5, 2024
23b3098
refactor: response 내부로 메시지 생성 책임 위임
le2sky Sep 5, 2024
e36a27b
feat: 로그인 redirection 처리
le2sky Sep 5, 2024
a43ebae
refactor: 메서드 이름 변경
le2sky Sep 5, 2024
6cc0cc5
refactor: /login get post 분리
le2sky Sep 5, 2024
45c7fd7
feat: register 페이지 조회 기능 구현
le2sky Sep 5, 2024
9a84cde
feat: not found 핸들러 구현
le2sky Sep 5, 2024
2614f38
refactor: content-type 분리
le2sky Sep 5, 2024
0a33eda
refactor: forward 결과 포장
le2sky Sep 5, 2024
f3f408c
feat: 회원가입 기능 구현
le2sky Sep 6, 2024
236a94b
refactor: http header 상수화
le2sky Sep 6, 2024
421ddb6
feat: header 추가 메서드 구현
le2sky Sep 6, 2024
e24a8ef
fix: null 검증 제거
le2sky Sep 6, 2024
7eb2844
chore: import문 최적화
le2sky Sep 6, 2024
cce15be
refactor: forward 내부에서 status, header 다룰 수 있도록 변경
le2sky Sep 6, 2024
5668186
feat: cookie 클래스 구현
le2sky Sep 6, 2024
fc664f5
refactor: 패키지 구조 변경
le2sky Sep 6, 2024
c3be469
feat: session 구현
le2sky Sep 6, 2024
48bec18
feat: 로그인 세션 적용
le2sky Sep 6, 2024
da8a395
style: enum 개행 제거
le2sky Sep 6, 2024
b11b42a
refactor: 불필요한 throws 제거
le2sky Sep 6, 2024
2e0f82d
chore: 학습 테스트 흔적 제거
le2sky Sep 6, 2024
5837dfd
chore: p 태그 제거
le2sky Sep 6, 2024
d3b1cda
refactor: content-type 내부로 content-type 결정 책임 이동
le2sky Sep 8, 2024
8bead94
refactor: header.empty 정적 팩터리 메서드로 변경
le2sky Sep 8, 2024
8e83204
refactor: http version 상수화
le2sky Sep 8, 2024
1f1e5f3
refactor: http request body를 char[]로 변경
le2sky Sep 8, 2024
3aab4c8
fix: from 메서드에서 case 무시하지 않도록 변경
le2sky Sep 8, 2024
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
1 change: 0 additions & 1 deletion study/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
1 change: 1 addition & 0 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ server:
accept-count: 1
max-connections: 1
threads:
min-spare: 2
max: 2
18 changes: 13 additions & 5 deletions study/src/test/java/study/IOStreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.io.*;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

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

/**
* 자바는 스트림(Stream)으로부터 I/O를 사용한다.
Expand Down Expand Up @@ -39,7 +47,7 @@ class OutputStream_학습_테스트 {
* OutputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 쓰기 위해 write(int b) 메서드를 사용한다.
* 예를 들어, FilterOutputStream은 파일로 데이터를 쓸 때,
* 또는 DataOutputStream은 자바의 primitive type data를 다른 매체로 데이터를 쓸 때 사용한다.
*
*
* write 메서드는 데이터를 바이트로 출력하기 때문에 비효율적이다.
* <code>write(byte[] data)</code>와 <code>write(byte b[], int off, int len)</code> 메서드는
* 1바이트 이상을 한 번에 전송 할 수 있어 훨씬 효율적이다.
Expand All @@ -63,7 +71,7 @@ class OutputStream_학습_테스트 {
/**
* 효율적인 전송을 위해 스트림에서 버퍼링을 사용 할 수 있다.
* BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다.
*
*
* 버퍼링을 사용하면 OutputStream을 사용할 때 flush를 사용하자.
* flush() 메서드는 버퍼가 아직 가득 차지 않은 상황에서 강제로 버퍼의 내용을 전송한다.
* Stream은 동기(synchronous)로 동작하기 때문에 버퍼가 찰 때까지 기다리면
Expand Down Expand Up @@ -108,7 +116,7 @@ class OutputStream_학습_테스트 {
* InputStream은 다른 매체로부터 바이트로 데이터를 읽을 때 사용한다.
* InputStream의 read() 메서드는 기반 메서드이다.
* <code>public abstract int read() throws IOException;</code>
*
*
* InputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 읽기 위해 read() 메서드를 사용한다.
*/
@Nested
Expand Down
1 change: 1 addition & 0 deletions tomcat/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {
testImplementation 'org.mockito:mockito-core:5.12.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
}

test {
Expand Down
25 changes: 25 additions & 0 deletions tomcat/src/main/java/com/techcourse/handler/GetLoginHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.techcourse.handler;

import org.apache.catalina.Manager;
import org.apache.coyote.http11.AbstractHandler;
import org.apache.coyote.http11.ForwardResult;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpStatus;

import java.net.URI;

public class GetLoginHandler extends AbstractHandler {

@Override
public boolean canHandle(HttpRequest httpRequest) {
URI uri = httpRequest.getUri();
String path = uri.getPath();

return "/login".equals(path) && httpRequest.getMethod().isGet();
}

@Override
protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
return new ForwardResult("login.html", HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.techcourse.handler;

import org.apache.catalina.Manager;
import org.apache.coyote.http11.AbstractHandler;
import org.apache.coyote.http11.ForwardResult;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpStatus;

import java.net.URI;

public class GetRegisterHandler extends AbstractHandler {

@Override
public boolean canHandle(HttpRequest httpRequest) {
URI uri = httpRequest.getUri();
String path = uri.getPath();

return "/register".equals(path) && httpRequest.getMethod().isGet();
}

@Override
protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
return new ForwardResult("register.html", HttpStatus.OK);
}
}
25 changes: 25 additions & 0 deletions tomcat/src/main/java/com/techcourse/handler/HelloHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.techcourse.handler;

import org.apache.catalina.Manager;
import org.apache.coyote.http11.AbstractHandler;
import org.apache.coyote.http11.ForwardResult;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpStatus;

import java.net.URI;

public class HelloHandler extends AbstractHandler {

@Override
public boolean canHandle(HttpRequest httpRequest) {
URI uri = httpRequest.getUri();
String path = uri.getPath();

return "/".equals(path);
}

@Override
protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
return new ForwardResult("hello.html", HttpStatus.OK);
}
}
20 changes: 20 additions & 0 deletions tomcat/src/main/java/com/techcourse/handler/NotFoundHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.techcourse.handler;

import org.apache.catalina.Manager;
import org.apache.coyote.http11.AbstractHandler;
import org.apache.coyote.http11.ForwardResult;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpStatus;

public class NotFoundHandler extends AbstractHandler {

@Override
public boolean canHandle(HttpRequest httpRequest) {
return true;
}

@Override
protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
return new ForwardResult("404.html", HttpStatus.NOT_FOUND);
}
}
61 changes: 61 additions & 0 deletions tomcat/src/main/java/com/techcourse/handler/PostLoginHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.techcourse.handler;

import com.techcourse.db.InMemoryUserRepository;
import com.techcourse.model.User;
import jakarta.servlet.http.HttpSession;
import org.apache.catalina.Manager;
import org.apache.coyote.http11.AbstractHandler;
import org.apache.coyote.http11.ForwardResult;
import org.apache.coyote.http11.Header;
import org.apache.coyote.http11.HttpHeaderKey;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpStatus;
import org.apache.coyote.http11.QueryParameter;

import java.net.URI;

public class PostLoginHandler extends AbstractHandler {

@Override
public boolean canHandle(HttpRequest httpRequest) {
URI uri = httpRequest.getUri();
String path = uri.getPath();

return "/login".equals(path) && httpRequest.getMethod().isPost();
}

@Override
protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
if (httpRequest.hasNotApplicationXW3FormUrlEncodedBody()) {
throw new RuntimeException();
}

QueryParameter queryParameter = new QueryParameter(httpRequest.body());
Header header = Header.empty();
String redirectionPath = "401.html";

if (isLoggedIn(queryParameter)) {
HttpSession session = findSessionOrCreate(sessionManager, createCookie(httpRequest));
session.setAttribute("user", getUser(queryParameter));
header.append(HttpHeaderKey.SET_COOKIE, getSessionKey() + "=" + session.getId());
redirectionPath = "index.html";
}

header.append(HttpHeaderKey.LOCATION, redirectionPath);
return new ForwardResult(HttpStatus.FOUND, header);
}

private boolean isLoggedIn(QueryParameter queryParameter) {
String password = queryParameter.get("password").orElse("");

return queryParameter.get("account")
.flatMap(InMemoryUserRepository::findByAccount)
.map(it -> it.checkPassword(password))
.orElse(false);
}

private User getUser(QueryParameter queryParameter) {
String account = queryParameter.get("account").orElseThrow();
return InMemoryUserRepository.findByAccount(account).orElseThrow();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.techcourse.handler;

import com.techcourse.db.InMemoryUserRepository;
import com.techcourse.model.User;
import org.apache.catalina.Manager;
import org.apache.coyote.http11.AbstractHandler;
import org.apache.coyote.http11.ForwardResult;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpStatus;
import org.apache.coyote.http11.QueryParameter;

import java.net.URI;

public class PostRegisterHandler extends AbstractHandler {

@Override
public boolean canHandle(HttpRequest httpRequest) {
URI uri = httpRequest.getUri();
String path = uri.getPath();

return "/register".equals(path) && httpRequest.getMethod().isPost();
}

@Override
protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
if (httpRequest.hasNotApplicationXW3FormUrlEncodedBody()) {
throw new RuntimeException();
}

registerNewUser(httpRequest);

return new ForwardResult("index.html", HttpStatus.OK);
}

private void registerNewUser(HttpRequest httpRequest) {
QueryParameter body = new QueryParameter(httpRequest.body());
String account = body.get("account").orElseThrow();
String password = body.get("password").orElseThrow();
String email = body.get("email").orElseThrow();

InMemoryUserRepository.save(new User(account, password, email));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.apache.catalina.connector;

import org.apache.catalina.Manager;
import org.apache.coyote.http11.Http11Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -17,15 +18,18 @@ public class Connector implements Runnable {
private static final int DEFAULT_ACCEPT_COUNT = 100;

private final ServerSocket serverSocket;
private final Manager sessionManager;

private boolean stopped;

public Connector() {
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT);
public Connector(Manager sessionManager) {
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, sessionManager);
}

public Connector(final int port, final int acceptCount) {
public Connector(final int port, final int acceptCount, final Manager sessionManager) {
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
this.sessionManager = sessionManager;
}

private ServerSocket createServerSocket(final int port, final int acceptCount) {
Expand Down Expand Up @@ -66,7 +70,7 @@ private void process(final Socket connection) {
if (connection == null) {
return;
}
var processor = new Http11Processor(connection);
var processor = new Http11Processor(connection, sessionManager);
new Thread(processor).start();
}

Expand Down
Loading