-
Notifications
You must be signed in to change notification settings - Fork 309
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
[톰캣 구현하기 - 3, 4단계] 에단(김석호) 미션 제출합니다. #422
Merged
Merged
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
5f53414
feat: CacheControl 인터셉터 추가
cookienc 818588c
feat: 압축 설정 추가
cookienc b205cc0
feat: Etag 설정 추가
cookienc e42bd2a
feat: Version 및 캐싱 기능 구현
cookienc 815ecb5
test: 쓰레드 stage0 학습 테스트 진행
cookienc 35d7e57
test: 쓰레드 stage1 학습 테스트 진행
cookienc c714b06
test: 쓰레드 stage2 학습 테스트 진행
cookienc 4fd6b34
refactor: 패키지 변경
cookienc 7c08deb
refactor: HttpHeaders 의 key 를 enummap으로 변경
cookienc 8618726
refactor: 정적파일의 확장자를 contenttype으로 관리
cookienc 0b1b0e6
refactor: 상수의 접근 제한자를 private으로 변경
cookienc 2d9e91c
refactor: HomePageMapping 에서 경로 상수화
cookienc 8a1647e
refactor: 페이지 이름을 관리하는 Path 추가
cookienc 10bb2f2
refactor: requestLine 빈 줄 제거
cookienc 2f774c9
refactor: QueryString 으로 리팩토링
cookienc f7d6fc2
refactor: keySet()을 entrySet()으로 변경
cookienc da45451
feat: Controller 추가
cookienc 23216a7
refactor: AbstractController 로 리팩토링
cookienc 4180472
refactor: 필요없는 파일 제거
cookienc 0e0cb5b
refactor: Mapping 을 Controller 로 이름 변경
cookienc 83a2309
refactor: Login 관련 컨트롤러를 하나로 합침
cookienc 3beba19
refactor: Register 관련 파일을 하나로 합침
cookienc 708cad5
refactor: 패키지 변경
cookienc 6d188b4
refactor: example 패키지 CacheBustingWebConfig의 상수의 접근제한자 변경
cookienc 937e0f7
refactor: 의존성 끊기 위한 패키지 분리 및 인스턴스 변수 추가
cookienc 4a2e985
refactor: FrontController 를 FrontHandler 로 리팩토링
cookienc cabedba
refactor: HttpResponseBuilder 제거
cookienc cbc9455
refactor: 사용하지 않는 메서드 제거
cookienc 954862a
test: 테스트를 HttpRequest, HttpResponse 로 리팩토링
cookienc 694cca8
test: StubSockect 으로 serialize 코드 옮김
cookienc 0ecf383
refactor: 로그인 테스트 하기 쉬운 구조로 변경
cookienc 1994cc3
test: E2E 테스트 작성
cookienc f3cfa28
test: Processor 테스트 분리
cookienc c91cd6d
fix: 자원 공유 문제 해결
cookienc 8ff9c92
refactor: LoginController 메서드 분리
cookienc 86b6d32
feat: Default Max Thread Size 적용
cookienc 207e696
refactor: SessionManager에 ConcurrentHashMap 적용
cookienc 73966b1
refactor: code smell 제거
cookienc ed006cb
refactor: 필요없는 static 제거
cookienc 93513c9
refactor: 메서드명 변경
cookienc f3c9cb7
refactor: HttpResponse serialize 수정
cookienc 5f735eb
refactor: 분기문을 stream 으로 정리
cookienc e2b96bb
test: 잘못된 테스트 수정
cookienc File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
study/src/main/java/cache/com/example/cachecontrol/CacheInterceptor.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,21 @@ | ||
package cache.com.example.cachecontrol; | ||
|
||
import com.google.common.net.HttpHeaders; | ||
import org.springframework.http.CacheControl; | ||
import org.springframework.web.servlet.HandlerInterceptor; | ||
import org.springframework.web.servlet.ModelAndView; | ||
|
||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
public class CacheInterceptor implements HandlerInterceptor { | ||
|
||
@Override | ||
public void postHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler, final ModelAndView modelAndView) throws Exception { | ||
final String cacheControlValue = CacheControl.noCache() | ||
.cachePrivate() | ||
.getHeaderValue(); | ||
|
||
response.addHeader(HttpHeaders.CACHE_CONTROL, cacheControlValue); | ||
} | ||
} |
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
15 changes: 11 additions & 4 deletions
15
study/src/main/java/cache/com/example/etag/EtagFilterConfiguration.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,12 +1,19 @@ | ||
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> shallowEtagHeaderFilter() { | ||
// return null; | ||
// } | ||
@Bean | ||
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() { | ||
final FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilterFilterRegistrationBean | ||
= new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); | ||
shallowEtagHeaderFilterFilterRegistrationBean.addUrlPatterns("/etag", "/resources/*"); | ||
shallowEtagHeaderFilterFilterRegistrationBean.setName("etagFilter"); | ||
return shallowEtagHeaderFilterFilterRegistrationBean; | ||
} | ||
} |
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
package nextstep; | ||
|
||
import nextstep.jwp.controller.FrontHandler; | ||
import org.apache.catalina.startup.Tomcat; | ||
import org.apache.coyote.http.session.SessionManager; | ||
|
||
public class Application { | ||
|
||
public static void main(String[] args) { | ||
final var tomcat = new Tomcat(); | ||
public static void main(final String[] args) { | ||
final var tomcat = new Tomcat(new FrontHandler(new SessionManager())); | ||
tomcat.start(); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
tomcat/src/main/java/nextstep/jwp/controller/FrontHandler.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,37 @@ | ||
package nextstep.jwp.controller; | ||
|
||
import org.apache.coyote.controller.Controller; | ||
import org.apache.coyote.controller.RequestHandler; | ||
import org.apache.coyote.http.LoginManager; | ||
import org.apache.coyote.http.request.HttpRequest; | ||
import org.apache.coyote.http.response.HttpResponse; | ||
|
||
import java.io.IOException; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import static nextstep.jwp.controller.Path.NOT_FOUND; | ||
|
||
public class FrontHandler implements RequestHandler { | ||
|
||
private final Set<Controller> requestControllers = new HashSet<>(); | ||
|
||
public FrontHandler(final LoginManager loginManager) { | ||
requestControllers.add(new HomePageController()); | ||
requestControllers.add(new StaticFileController()); | ||
requestControllers.add(new LoginController(loginManager)); | ||
requestControllers.add(new RegisterController()); | ||
} | ||
|
||
@Override | ||
public void handle(final HttpRequest request, final HttpResponse response) throws IOException { | ||
for (final Controller controller : requestControllers) { | ||
if (controller.supports(request)) { | ||
controller.service(request, response); | ||
return; | ||
} | ||
} | ||
|
||
response.mapToRedirect(NOT_FOUND.getValue()); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
tomcat/src/main/java/nextstep/jwp/controller/HomePageController.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,33 @@ | ||
package nextstep.jwp.controller; | ||
|
||
import org.apache.coyote.http.common.ContentType; | ||
import org.apache.coyote.http.common.HttpBody; | ||
import org.apache.coyote.http.request.HttpRequest; | ||
import org.apache.coyote.http.response.HttpResponse; | ||
import org.apache.coyote.http.response.StatusCode; | ||
import org.apache.coyote.http.response.StatusLine; | ||
|
||
import static org.apache.coyote.http.common.HttpHeader.CONTENT_TYPE; | ||
|
||
public class HomePageController extends RequestController { | ||
|
||
private static final String HOME_MESSAGE = "Hello world!"; | ||
private static final String TARGET_URI = "/"; | ||
|
||
@Override | ||
public boolean supports(final HttpRequest httpRequest) { | ||
return TARGET_URI.equals(httpRequest.getRequestUri().getRequestUri()); | ||
} | ||
|
||
@Override | ||
protected void doPost(final HttpRequest request, final HttpResponse response) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
protected void doGet(final HttpRequest request, final HttpResponse response) { | ||
response.changeStatusLine(StatusLine.from(StatusCode.OK)); | ||
response.addHeader(CONTENT_TYPE, ContentType.HTML.getValue()); | ||
response.changeBody(new HttpBody(HOME_MESSAGE)); | ||
} | ||
} |
171 changes: 171 additions & 0 deletions
171
tomcat/src/main/java/nextstep/jwp/controller/LoginController.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,171 @@ | ||
package nextstep.jwp.controller; | ||
|
||
import nextstep.jwp.db.InMemoryUserRepository; | ||
import nextstep.jwp.model.User; | ||
import org.apache.coyote.http.LoginManager; | ||
import org.apache.coyote.http.common.ContentType; | ||
import org.apache.coyote.http.common.HttpBody; | ||
import org.apache.coyote.http.common.HttpHeader; | ||
import org.apache.coyote.http.request.HttpCookie; | ||
import org.apache.coyote.http.request.HttpRequest; | ||
import org.apache.coyote.http.request.QueryString; | ||
import org.apache.coyote.http.response.HttpResponse; | ||
import org.apache.coyote.http.response.StatusCode; | ||
import org.apache.coyote.http.response.StatusLine; | ||
import org.apache.coyote.http.session.Session; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.util.Map; | ||
import java.util.UUID; | ||
|
||
import static nextstep.jwp.controller.Path.LOGIN; | ||
import static nextstep.jwp.controller.Path.MAIN; | ||
import static nextstep.jwp.controller.Path.UNAUTHORIZED; | ||
import static org.apache.coyote.http.common.HttpHeader.CONTENT_TYPE; | ||
import static org.apache.coyote.http.common.HttpHeader.COOKIE; | ||
|
||
public class LoginController extends RequestController { | ||
|
||
private static final String TARGET_URI = "login"; | ||
private static final Logger log = LoggerFactory.getLogger(LoginController.class); | ||
private static final String CREDENTIALS = "account"; | ||
private static final String PASSWORD = "password"; | ||
|
||
private final LoginManager loginManager; | ||
|
||
public LoginController(final LoginManager loginManager) { | ||
this.loginManager = loginManager; | ||
} | ||
|
||
@Override | ||
public boolean supports(final HttpRequest httpRequest) { | ||
return httpRequest.containsRequestUri(TARGET_URI); | ||
} | ||
|
||
@Override | ||
protected void doPost(final HttpRequest request, final HttpResponse response) { | ||
try { | ||
final User user = getValidateUser(request); | ||
|
||
log.info("로그인 성공! user = {}", user); | ||
final UUID uuid = createSessionToUser(user); | ||
|
||
setCookieAndRedirectToMain(response, uuid); | ||
} catch (final IllegalArgumentException e) { | ||
log.warn("login error = {}", e.getMessage()); | ||
redirectToUnAuthorized(response); | ||
} | ||
} | ||
|
||
private User getValidateUser(final HttpRequest request) { | ||
final Map<String, String> bodyParams = request.getParsedBody(); | ||
final String account = bodyParams.get(CREDENTIALS); | ||
final String password = bodyParams.get(PASSWORD); | ||
|
||
final User user = InMemoryUserRepository.findByAccount(account) | ||
.orElseThrow(() -> new IllegalArgumentException("잘못된 계정입니다. 다시 입력해주세요.")); | ||
|
||
if (!user.checkPassword(password)) { | ||
throw new IllegalArgumentException("잘못된 비밀번호입니다. 다시 입력해주세요."); | ||
} | ||
|
||
return user; | ||
} | ||
|
||
private UUID createSessionToUser(final User user) { | ||
final UUID uuid = UUID.randomUUID(); | ||
|
||
final Map<String, String> sessionData = Map.of(CREDENTIALS, user.getAccount()); | ||
final Session session = new Session(uuid.toString()); | ||
for (final Map.Entry<String, String> entry : sessionData.entrySet()) { | ||
session.add(entry.getKey(), entry.getValue()); | ||
} | ||
|
||
loginManager.add(session); | ||
|
||
return uuid; | ||
} | ||
|
||
private static void setCookieAndRedirectToMain(final HttpResponse response, final UUID uuid) { | ||
response.changeStatusLine(StatusLine.from(StatusCode.FOUND)); | ||
response.addHeader(HttpHeader.LOCATION, MAIN.getValue()); | ||
response.addHeader(HttpHeader.SET_COOKIE, "JSESSIONID=" + uuid); | ||
response.changeBody(HttpBody.empty()); | ||
} | ||
|
||
@Override | ||
protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { | ||
if (isAlreadyLogined(request)) { | ||
redirectToMain(response); | ||
return; | ||
} | ||
|
||
if (wantToLogin(request)) { | ||
doLoginProcess(request, response); | ||
return; | ||
} | ||
|
||
redirectToLoginPage(response); | ||
} | ||
|
||
private boolean isAlreadyLogined(final HttpRequest request) { | ||
if (!request.containsHeader(COOKIE)) { | ||
return false; | ||
} | ||
|
||
final HttpCookie cookies = HttpCookie.from(request.getHeader(COOKIE)); | ||
|
||
return checkLogin(cookies.get("JSESSIONID")); | ||
} | ||
|
||
private void redirectToMain(final HttpResponse response) { | ||
response.mapToRedirect(MAIN.getValue()); | ||
} | ||
|
||
private boolean wantToLogin(final HttpRequest request) { | ||
return request.hasQueryString(); | ||
} | ||
|
||
private void doLoginProcess(final HttpRequest request, final HttpResponse response) { | ||
final QueryString queryString = request.getQueryString(); | ||
|
||
final String account = queryString.get(CREDENTIALS); | ||
final String password = queryString.get(PASSWORD); | ||
|
||
try { | ||
validateUserCredentials(account, password); | ||
log.info("로그인 성공! account = {}", account); | ||
} catch (final IllegalArgumentException e) { | ||
log.warn("login error = {}", e.getMessage()); | ||
redirectToUnAuthorized(response); | ||
return; | ||
} | ||
|
||
redirectToMain(response); | ||
} | ||
|
||
private void redirectToUnAuthorized(final HttpResponse response) { | ||
response.mapToRedirect(UNAUTHORIZED.getValue()); | ||
} | ||
|
||
private void validateUserCredentials(final String account, final String password) { | ||
final User user = InMemoryUserRepository.findByAccount(account) | ||
.orElseThrow(() -> new IllegalArgumentException("잘못된 계정입니다. 다시 입력해주세요.")); | ||
|
||
if (!user.checkPassword(password)) { | ||
throw new IllegalArgumentException("잘못된 비밀번호입니다. 다시 입력해주세요."); | ||
} | ||
} | ||
|
||
private boolean checkLogin(final String jSessionId) { | ||
return loginManager.isAlreadyLogined(jSessionId); | ||
} | ||
|
||
private void redirectToLoginPage(final HttpResponse response) throws IOException { | ||
response.changeStatusLine(StatusLine.from(StatusCode.OK)); | ||
response.addHeader(CONTENT_TYPE, ContentType.HTML.getValue()); | ||
response.changeBody(HttpBody.file(LOGIN.getValue())); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
statusLine은 정적팩토리메서드로 HttpBody는 생성자로 생성하고 있는데 혹시 기준이 있나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
특별한 로직 같은게 있으면 정팩메를 씁니다! StatusLine에 있는 from 메서드는 Protocol이 기본으로 들어가 있어서 로직으로 봤습니다.