Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
bada3ab
feat(Http11Processor): 요청 데이터를 HttpRequest 객체로 변경하는 메서드 작성
jminkkk Sep 4, 2024
c4a1553
feat(Http11Processor): 요청URL과 일치하는 정적 파일을 반환
jminkkk Sep 4, 2024
c18f016
feat(Http11Processor): root url로 요청일 경우 특정 문자열 반환
jminkkk Sep 4, 2024
f1faac6
feat(Http11Processor): html이 아닌 다른 형식의 파일 지원
jminkkk Sep 4, 2024
46e7647
refactor(HttpRequestParser): HttpRequest를 처리하는 객체 분리
jminkkk Sep 4, 2024
e759369
feat(RequestHandler): 요청을 처리하는 핸들러 분리
jminkkk Sep 4, 2024
fe4966a
feat(RequestHandler): login 엔드포인트 접속 시 로직 처리
jminkkk Sep 4, 2024
eec7b5e
fix(RequestHandler): query null인 경우 정적 파일 렌더링하도록
jminkkk Sep 4, 2024
5585ca3
feat(RequestHandler): 로그인 성공 시 리다이렉트
jminkkk Sep 4, 2024
7611c00
refactor(HttpResponseGenerator): response 생성 객체 분리
jminkkk Sep 4, 2024
1413445
fix: remove implementation logback-classic on gradle (#501)
geoje Sep 5, 2024
a622aa8
fix: add threads min-spare configuration on properties (#502)
geoje Sep 5, 2024
113c1f2
feat(HttpHeader): Header 객체 분리
jminkkk Sep 5, 2024
4b09d6c
feat(HttpReqeust): Request 객체 구현
jminkkk Sep 5, 2024
1cc268b
feat(HttpRequestParser): Get이 아닌 다른 method여도 Request 객체 파싱
jminkkk Sep 5, 2024
f03ad13
feat(RequestHandler): queryString이 없는 path일 경우 검증 후 로직
jminkkk Sep 5, 2024
25e2e2d
feat(RequestHandler): 회원가입 post 요청 로직 구현
jminkkk Sep 5, 2024
8dd16d8
feat(HttpCookie): Cookie 객체 구현
jminkkk Sep 5, 2024
e9a913f
fix(RequestHandler): 회원가입 시 비밀번호, 이메일 파싱 로직 수정
jminkkk Sep 5, 2024
f3ae893
feat(index.html): login 적용 후 코드 활성화
jminkkk Sep 5, 2024
66716c9
feat(RequestHandler): login 을 post method로 변경
jminkkk Sep 5, 2024
df2f62f
fix(RequestHandler): Set-Cookie 응답에 추가하는 로직 수정
jminkkk Sep 5, 2024
ebfb27e
feat(Session): Session, Manger 구현체 생성
jminkkk Sep 6, 2024
72a7a76
feat(SessionManager): 싱글톤 적용
jminkkk Sep 6, 2024
dfef52c
feat(RequestHandler): 이미 로그인 되어있는지 세션으로 검증 및 리다이렉트
jminkkk Sep 6, 2024
e36802d
chore: 타임리프 의존성 추가
jminkkk Sep 6, 2024
76ab97b
feat(CacheWebConfig): 휴리스틱 캐싱 제거
jminkkk Sep 6, 2024
2567872
feat(CacheWebConfig): HTTP Compression 설정
jminkkk Sep 6, 2024
1ca0846
feat(EtagFilterConfiguration): ETag/If-None-Match 적용
jminkkk Sep 6, 2024
8a983ca
feat(HttpRequest): Cookie 파싱 로직 변경, Session 파싱 제거
jminkkk Sep 6, 2024
42efdd6
refactor(HttpCookie): 파일 위치 변경
jminkkk Sep 6, 2024
0268d07
refactor(/request): request 관련 객체 위치 이동
jminkkk Sep 6, 2024
a2dfedd
refactor(/response): response 관련 객체 위치 이동
jminkkk Sep 6, 2024
6a23a53
refactor(HttpMethod): http method 상수로 추출
jminkkk Sep 6, 2024
0e7ed00
refactor(handler): handler 분리
jminkkk Sep 6, 2024
586ac33
refactor(handler): 요청을 처리하는 최상위 Handler 추상 클래스 생성
jminkkk Sep 6, 2024
7ec70c7
refactor(HttpHeader): toString 구현
jminkkk Sep 6, 2024
7dc68a1
refactor(RequestHandler): 불필요한 예외 전파 제거
jminkkk Sep 6, 2024
0e8346a
refactor(mapping): 패키지 구조 변경
jminkkk Sep 6, 2024
eec0659
feat(EtagFilterConfiguration): etag 추가
jminkkk Sep 6, 2024
953dea1
refactor(CacheBustingWebConfig): busting 추가
jminkkk Sep 6, 2024
96f9b69
test(Http11ProcessorTest): content-length 수정
jminkkk Sep 6, 2024
809d0fe
refactor(RequestHandlerAdapter): Adapter로 이름 변경
jminkkk Sep 6, 2024
60fd852
refactor(/http): 패키지 구조 개선, http 관련 객체 위치 이동
jminkkk Sep 9, 2024
cbd6b19
refactor(Http11Processor): sout문 제거
jminkkk Sep 9, 2024
cd3776b
refactor(HttpRequestParser): 중복 정의된 조건문 제거
jminkkk Sep 9, 2024
a2c3b1f
refactor: 클래스 시작 줄에 개행 추가
jminkkk Sep 9, 2024
ef92ee3
test(SessionManager): 기본 메서드에 대해 테스트 작성
jminkkk Sep 9, 2024
36dbef5
refactor(/catalina/session): session 관련 객체들 위치 이동
jminkkk Sep 9, 2024
e92d191
refactor(Session): 세션에 속성을 추가하는 메서드의 인자 이름 명확하게
jminkkk Sep 9, 2024
9108869
test(SessionTest): 속성값 조회 테스트
jminkkk Sep 9, 2024
ab376fd
refactor(ResourceHandlerMapping): concat 메서드를 체이닝처럼 개행
jminkkk Sep 9, 2024
fdb5ce9
refactor(UrlHandlerMapping): IllegalCallerException 던지지 않고 404 페이지 반환
jminkkk Sep 9, 2024
03e7a20
refactor(StaticResourceHandler): Handler 상속 및 파일 위치 변경
jminkkk Sep 9, 2024
312cff6
test(StaticResourceHandler): 정적 리소스 처리 테스트 작성
jminkkk Sep 9, 2024
1cfca7f
refactor(LoginHandler): Get 요청 처리 로직 개선
jminkkk Sep 9, 2024
c14cc75
refactor(LoginHandler): 인증되었는지 로직 개선 및 테스트 작성
jminkkk Sep 9, 2024
62b2b3f
refactor(RootEndPointHandler): 루트 엔드포인트 요청을 처리하는 핸들러 분리
jminkkk Sep 9, 2024
8ae6cac
test(RegisterHandlerTest): 회원가입 테스트 작성
jminkkk Sep 9, 2024
6027f47
refactor(HandlerMapping): 요청에 대한 핸들러를 반환하도록 역할 부여 및 테스트 작성
jminkkk Sep 9, 2024
0f88784
feat(SessionManager): 특정 아이디인 세션이 존재하는지 반환하는 메서드 추가
jminkkk Sep 9, 2024
7ed734e
refactor(HttpCookie): 필드와 인자가 다른 생성자를 정팩메로 변경
jminkkk Sep 9, 2024
f5efceb
test(HttpCookie): 테스트 작성 및 필드를 private하게 변경
jminkkk Sep 9, 2024
6b297db
refactor(HttpRequestReader): 객체 책임에 맡게 이름 변경
jminkkk Sep 9, 2024
7e936f4
refactor(StandardHttpHeader): HTTP 일반적인 헤더를 나타내는 이넘 생성
jminkkk Sep 9, 2024
7c4a23c
refactor(/header): header 관련 객체 패키지로 이동
jminkkk Sep 9, 2024
e347bdf
refactor(StaticResourceHandler): 확장자가 없는 경우 /static 경로에 있는 html 리소스를 반환
jminkkk Sep 10, 2024
8e1dcff
refactor(NotFoundHandler): NotFoundException에 대한 핸들러 분리
jminkkk Sep 10, 2024
5b2f99f
refactor(UnAuthorizationHandler): UnAuthorization 에 대한 핸들러 분리
jminkkk Sep 10, 2024
bf65e8e
refactor(/test): 변경된 응답 메시지를 규격에 맞게 상태 값 형식 변경
jminkkk Sep 10, 2024
9b91b4b
refactor(InternalServerErrorHandler): 최상위 Exception 에 대한 핸들러 분리
jminkkk Sep 10, 2024
1261359
refactor(HandlerMapping): 에러에 대한 핸들링 처리
jminkkk Sep 10, 2024
12c64e4
refactor(Http11Processor): 핸들링 도중 에러 발생 시 처리
jminkkk Sep 10, 2024
4557a29
refactor(HttpResponseGenerator): 500 변경
jminkkk Sep 10, 2024
c5384c1
refactor(StaticResourceHandler): 정적 파일 조회 로직 변경
jminkkk Sep 10, 2024
51103bf
refactor(Http11ProcessorTest): 각 http request에 따른 통합 테스트 추가
jminkkk Sep 10, 2024
94cc5e9
test(HttpRequest): HttpRequest 객체 테스트 작성
jminkkk Sep 10, 2024
6199da2
refactor(HttpRequest): application/x-www-form-urlencoded 형식의 요청인 경우 바…
jminkkk Sep 10, 2024
7829350
test(HttpRequestReader): HttpRequestReader 테스트 작성
jminkkk Sep 10, 2024
b90b9aa
test(HttpResponseGenerator): host 고
jminkkk Sep 10, 2024
aff79b0
refacotr(HttpRequest): 특정 헤더인지 StandardHttpHeader 에게 물어보도록 변경
jminkkk Sep 10, 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
2 changes: 1 addition & 1 deletion study/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ 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'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.assertj:assertj-core:3.26.0'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package cache.com.example.cachecontrol;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.WebContentInterceptor;

@Configuration
public class CacheWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(final InterceptorRegistry registry) {
CacheControl cacheControl = CacheControl.noCache().cachePrivate();

WebContentInterceptor webContentInterceptor = new WebContentInterceptor();
webContentInterceptor.addCacheMapping(cacheControl, "/**");

registry.addInterceptor(webContentInterceptor);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
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;

import cache.com.example.version.CacheBustingWebConfig;

@Configuration
public class EtagFilterConfiguration {

// @Bean
// public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
// return null;
// }
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
FilterRegistrationBean<ShallowEtagHeaderFilter> filter = new FilterRegistrationBean<>();
filter.setFilter(new ShallowEtagHeaderFilter());
filter.addUrlPatterns("/etag", CacheBustingWebConfig.PREFIX_STATIC_RESOURCES + "/*");
return filter;
}
}
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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());
}
}
4 changes: 4 additions & 0 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ handlebars:
suffix: .html

server:
compression:
enabled: true
min-response-size: 10
tomcat:
accept-count: 1
max-connections: 1
threads:
min-spare: 2
max: 2
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
package org.apache.catalina;

import jakarta.servlet.http.HttpSession;
package org.apache.catalina.session;

import java.io.IOException;

Expand Down Expand Up @@ -29,7 +27,7 @@ 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
Expand All @@ -45,12 +43,12 @@ public interface Manager {
* @return the request session or {@code null} if a session with the
* requested ID could not be found
*/
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);
}
35 changes: 35 additions & 0 deletions tomcat/src/main/java/org/apache/catalina/session/Session.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.apache.catalina.session;

import java.util.HashMap;
import java.util.Map;

public class Session {

private final String id;
private final Map<String, Object> values = new HashMap<>();

public Session(final String id) {
this.id = id;
}

public String getId() {
return id;
}

public Object getAttribute(final String name) {
return values.entrySet()
.stream()
.filter(entry -> entry.getKey().equals(name))
.map(Map.Entry::getValue)
.findFirst()
.orElse(null);
}

public Map<String, Object> getValues() {
return values;
}

public void setAttribute(String name, Object value) {
values.put(name, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.apache.catalina.session;

import java.util.HashMap;
import java.util.Map;

public class SessionManager implements Manager {
private static final Map<String, Session> SESSIONS = new HashMap<>();
private static final SessionManager INSTANCE = new SessionManager();

private SessionManager() {}

public static SessionManager getInstance() {
return INSTANCE;
}

public boolean existsById(final String id) {
return SESSIONS.containsKey(id);
}

@Override
public void add(Session session) {
SESSIONS.put(session.getId(), session);
}

@Override
public Session findSession(final String id) {
return SESSIONS.get(id);
}

@Override
public void remove(Session session) {
SESSIONS.remove(session.getId());
}
}

59 changes: 59 additions & 0 deletions tomcat/src/main/java/org/apache/coyote/HandlerMapping.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.apache.coyote;

import org.apache.coyote.handler.Handler;
import org.apache.coyote.handler.LoginHandler;
import org.apache.coyote.handler.RegisterHandler;
import org.apache.coyote.handler.RootEndPointHandler;
import org.apache.coyote.handler.StaticResourceHandler;
import org.apache.coyote.handler.exception.InternalServerErrorHandler;
import org.apache.coyote.handler.exception.NotFoundHandler;
import org.apache.coyote.handler.exception.UnAuthorizationHandler;
import org.apache.http.request.HttpRequest;


public class HandlerMapping {

private static final HandlerMapping INSTANCE = new HandlerMapping();
private static final String PATH_DELIMITER = "/";

private HandlerMapping() {
}

public static HandlerMapping getInstance() {
return INSTANCE;
}

public Handler getHandler(final HttpRequest httpRequest) {
return getHandlerByEndPoint(httpRequest);
}

private Handler getHandlerByEndPoint(final HttpRequest httpRequest) {
final String path = httpRequest.getPath();

if (path.equals(PATH_DELIMITER)) {
return RootEndPointHandler.getInstance();
}

if (path.contains("login")) {
return LoginHandler.getInstance();
}

if (path.contains("register")) {
return RegisterHandler.getInstance();
}

return StaticResourceHandler.getInstance();
}

public Handler getHandlerByException(final Exception exception) {
if (exception instanceof NotFoundException) {
return NotFoundHandler.getInstance();
}

if (exception instanceof UnauthorizedException) {
return UnAuthorizationHandler.getInstance();
}

return InternalServerErrorHandler.getInstance();
}
}
7 changes: 7 additions & 0 deletions tomcat/src/main/java/org/apache/coyote/NotFoundException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.apache.coyote;

public class NotFoundException extends RuntimeException {
public NotFoundException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.apache.coyote;

public class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String message) {
super(message);
}
}
8 changes: 8 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,8 @@
package org.apache.coyote.handler;

import org.apache.http.request.HttpRequest;

public abstract class Handler {
// TODO: 반환타입 HttpResponse로 변경
public abstract String handle(HttpRequest httpRequest);
}
74 changes: 74 additions & 0 deletions tomcat/src/main/java/org/apache/coyote/handler/LoginHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.apache.coyote.handler;

import java.util.Optional;
import java.util.UUID;

import org.apache.catalina.session.SessionManager;
import org.apache.http.HttpCookie;
import org.apache.http.HttpMethod;
import org.apache.catalina.session.Session;
import org.apache.http.header.StandardHttpHeader;
import org.apache.http.request.HttpRequest;
import org.apache.http.response.HttpResponseGenerator;

import com.techcourse.db.InMemoryUserRepository;
import com.techcourse.model.User;

public class LoginHandler extends Handler {

private static final LoginHandler INSTANCE = new LoginHandler();
private final SessionManager sessionManager = SessionManager.getInstance();

private LoginHandler() {
}

public static LoginHandler getInstance() {
return INSTANCE;
}

@Override
public String handle(final HttpRequest httpRequest) {
if (httpRequest.isSameMethod(HttpMethod.GET)) {
return processLoginGetRequest(httpRequest);
}

if (httpRequest.isSameMethod(HttpMethod.POST)) {
return processLoginPostRequest(httpRequest);
}

return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/404.html", "HTTP/1.1", null, null));

}

private String processLoginGetRequest(final HttpRequest httpRequest) {
HttpCookie httpCookie = httpRequest.getHttpCookie();
if (httpCookie == null || ! sessionManager.existsById(httpCookie.getValue("JSESSIONID"))) {
return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/login.html", "HTTP/1.1", null, null));
}

return HttpResponseGenerator.getFoundResponse("/index.html");
}

private String processLoginPostRequest(final HttpRequest httpRequest) {
final String account = httpRequest.getFormBody("account");
final String password = httpRequest.getFormBody("password");

final Optional<User> userOptional = InMemoryUserRepository.findByAccount(account);
if (userOptional.isEmpty() || !userOptional.get().checkPassword(password)) {
return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/401.html", "HTTP/1.1", null, null));
}

final Session session = new Session(UUID.randomUUID().toString());
session.setAttribute("user", userOptional.get());
sessionManager.add(session);
return addCookie(
HttpResponseGenerator.getFoundResponse("/index.html"),
HttpCookie.of("JSESSIONID=" + session.getId()));
}

private String addCookie(final String response, final HttpCookie cookie) {
return response
.concat("\n")
.concat(StandardHttpHeader.SET_COOKIE.getValue() + ": " + cookie.toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.apache.coyote.handler;

import org.apache.http.HttpMethod;
import org.apache.http.request.HttpRequest;
import org.apache.http.response.HttpResponseGenerator;

import com.techcourse.db.InMemoryUserRepository;
import com.techcourse.model.User;

public class RegisterHandler extends Handler {

private static final RegisterHandler INSTANCE = new RegisterHandler();

private RegisterHandler() {
}

public static RegisterHandler getInstance() {
return INSTANCE;
}
Comment on lines +17 to +19

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인스턴스를 재활용한 것 👍


public String handle(final HttpRequest httpRequest) {
if (httpRequest.isSameMethod(HttpMethod.GET)) {
return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/register.html", "HTTP/1.1", null, null));
}

if (httpRequest.isSameMethod(HttpMethod.POST)) {
return processRegisterPostRequest(httpRequest);
}

return StaticResourceHandler.getInstance().handle(new HttpRequest("GET", "/401.html", "HTTP/1.1", null, null));
}

private String processRegisterPostRequest(final HttpRequest httpRequest) {
String[] body = httpRequest.getBody().split("&");
String account = body[0].split("=")[1];
String email = body[1].split("=")[1];
String password = body[2].split("=")[1];
InMemoryUserRepository.save(new User(account, password, email));
return HttpResponseGenerator.getFoundResponse("/index.html");
}
}
Loading