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

[톰캣 구현하기 - 3, 4단계] 라온(문채원) 미션 제출합니다. #433

Merged
merged 32 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f54bffd
refactor: request에 HttpHeaders 적용
mcodnjs Sep 4, 2023
f8d24eb
refactor: 패키지 구조 변경
mcodnjs Sep 4, 2023
fe717dd
refactor: HttpHeaders 내부에 HttpCookie 추가
mcodnjs Sep 4, 2023
293f988
refactor: RequestHandler 및 Controller 객체 생성
mcodnjs Sep 4, 2023
fbbd644
test: Http 활용하기 테스트 구현
mcodnjs Sep 5, 2023
2bb6e1f
refactor: Controller 핸들링 구조 변경
mcodnjs Sep 5, 2023
9aec72c
refactor: Controller 메서드별 로직 추가
mcodnjs Sep 5, 2023
f0bf5bb
refactor: Processor 내부의 handleRequest 메서드 삭제
mcodnjs Sep 5, 2023
f5fd662
refactor: ResourceReader 구현
mcodnjs Sep 6, 2023
9687137
refactor: ResourceContentTypeResolver 구현
mcodnjs Sep 6, 2023
e16df12
refactor: MediaType 구현
mcodnjs Sep 7, 2023
32a7681
refactor: MediaType value 수정
mcodnjs Sep 7, 2023
407db0a
refactor: 리소스 핸들링하는 메소드 분리
mcodnjs Sep 7, 2023
33e7826
refactor: 패키지 구조 분리
mcodnjs Sep 8, 2023
317e434
test: thread test 진행
mcodnjs Sep 9, 2023
99a5154
feat: step4 - executors로 thread pool 적용
mcodnjs Sep 9, 2023
e66ea7f
feat: step4 - 동시성 컬렉션 사용
mcodnjs Sep 9, 2023
7f2ed15
refactor: 세션 패키지 분리
mcodnjs Sep 9, 2023
ab7dfee
refactor: HttpController의 추상메서드를 구체메서드로 변경
mcodnjs Sep 9, 2023
d6b199c
refactor: session 패키지 위치 변경
mcodnjs Sep 9, 2023
9d1f8ff
test: coyote 패키지 테스트 구현
mcodnjs Sep 9, 2023
8237e9e
test: Controller 테스트 구현
mcodnjs Sep 9, 2023
cbd7b69
refactor: SessionManager 싱글톤 구현
mcodnjs Sep 9, 2023
9d6802e
refactor: todo 주석 제거
mcodnjs Sep 9, 2023
a0efa42
refactor: RequestMapping 주입 수정
mcodnjs Sep 9, 2023
ef23b65
refactor: content type 헤더 제거
mcodnjs Sep 11, 2023
a5493f7
refactor: exception handling 로직 수정
mcodnjs Sep 11, 2023
dea46b0
refactor: ResourceContentTypeResolver static 메서드로 수정
mcodnjs Sep 11, 2023
4a96971
refactor: getResourceContentType 로직 수정
mcodnjs Sep 11, 2023
1e6d57c
refactor: url encoded 메서드 분리
mcodnjs Sep 11, 2023
8039dde
refactor: null 반환 Optional 처리
mcodnjs Sep 11, 2023
f6e401c
refactor: Controller의 handle 메서드 수정
mcodnjs Sep 11, 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
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) {
final WebContentInterceptor interceptor = new WebContentInterceptor();
final CacheControl cacheControl = CacheControl
.noCache()
.cachePrivate();
interceptor.addCacheMapping(cacheControl, "/**");
registry.addInterceptor(interceptor);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
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 static cache.com.example.version.CacheBustingWebConfig.PREFIX_STATIC_RESOURCES;

@Configuration
public class EtagFilterConfiguration {

// @Bean
// public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
// return null;
// }
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {

FilterRegistrationBean<ShallowEtagHeaderFilter> filterFilterRegistrationBean
= new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
filterFilterRegistrationBean.addUrlPatterns("/etag", PREFIX_STATIC_RESOURCES + "/*");
return filterFilterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

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;

import java.time.Duration;

@Configuration
public class CacheBustingWebConfig implements 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());
}
}
3 changes: 3 additions & 0 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ handlebars:
suffix: .html

server:
compression:
enabled: true
min-response-size: 10
tomcat:
accept-count: 1
max-connections: 1
Expand Down
2 changes: 1 addition & 1 deletion study/src/test/java/thread/stage0/SynchronizationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private static final class SynchronizedMethods {

private int sum = 0;

public void calculate() {
public synchronized void calculate() {
setSum(getSum() + 1);
}

Expand Down
6 changes: 3 additions & 3 deletions study/src/test/java/thread/stage0/ThreadPoolsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void testNewFixedThreadPool() {
executor.submit(logWithSleep("hello fixed thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedQueueSize = 0;
final int expectedPoolSize = 2;
final int expectedQueueSize = 1;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size());
Expand All @@ -46,7 +46,7 @@ void testNewCachedThreadPool() {
executor.submit(logWithSleep("hello cached thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedPoolSize = 3;
final int expectedQueueSize = 0;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
Expand Down
1 change: 1 addition & 0 deletions tomcat/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ dependencies {
testImplementation "org.assertj:assertj-core:3.24.2"
testImplementation "org.mockito:mockito-core:5.4.0"
testImplementation "org.junit.jupiter:junit-jupiter-api:5.7.2"
testImplementation "org.junit.jupiter:junit-jupiter-params:5.7.2"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.7.2"
}
68 changes: 68 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/controller/LoginController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package nextstep.jwp.controller;

import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.catalina.controller.HttpController;
import org.apache.catalina.session.Session;
import org.apache.catalina.session.SessionManager;
import org.apache.coyote.http11.common.HttpCookie;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

import java.io.IOException;
import java.util.*;

import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION;
import static org.apache.coyote.http11.common.HttpHeaderType.SET_COOKIE;
import static org.apache.coyote.http11.response.HttpStatusCode.FOUND;

public class LoginController extends HttpController {

@Override
public boolean canHandle(final HttpRequest httpRequest) {
final Set<String> requestType = Set.of("/login");
return requestType.contains(httpRequest.getTarget());
}

@Override
protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException {
final HttpCookie httpCookie = httpRequest.getCookie();
String sessionId = httpCookie.getCookie("JSESSIONID");
if (sessionId != null && SessionManager.getInstance().findSession(sessionId) != null) { // already login user
httpResponse.addHeader(LOCATION, "/index.html");
httpResponse.setStatusCode(FOUND);
} else { // not login user
handleResource("/login.html", httpRequest, httpResponse);
}
}

@Override
protected void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) {
final HttpCookie httpCookie = httpRequest.getCookie();
String sessionId = httpCookie.getCookie("JSESSIONID");

final Optional<User> user = InMemoryUserRepository.findByAccount(httpRequest.getBody().get("account"));
if (user.isEmpty() || !user.get().checkPassword(httpRequest.getBody().get("password"))) {
// invalid user
httpResponse.addHeader(LOCATION, "/401.html");
httpResponse.setStatusCode(FOUND);
return;
}

if (sessionId != null) { // if already have session
httpResponse.addHeader(LOCATION, "/index.html");
httpResponse.setStatusCode(FOUND);
return;
}

// if no session
final Session session = new Session(String.valueOf(UUID.randomUUID()));
session.setAttribute("user", user);
SessionManager.getInstance().add(session);
sessionId = session.getId();

httpResponse.addHeader(LOCATION, "/index.html");
httpResponse.addHeader(SET_COOKIE, "JSESSIONID=" + sessionId);
httpResponse.setStatusCode(FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package nextstep.jwp.controller;

import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.catalina.controller.HttpController;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

import java.io.IOException;
import java.util.Set;

import static org.apache.coyote.http11.common.HttpHeaderType.LOCATION;
import static org.apache.coyote.http11.response.HttpStatusCode.FOUND;

public class RegisterController extends HttpController {

@Override
public boolean canHandle(final HttpRequest httpRequest) {
final Set<String> requestType = Set.of("/register");
return requestType.contains(httpRequest.getTarget());
}

@Override
public void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) throws IOException {
handleResource("/register.html", httpRequest, httpResponse);
}

@Override
public void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) {
final User newUser = new User(
httpRequest.getBody().get("account"),
httpRequest.getBody().get("password"),
httpRequest.getBody().get("email")
);
InMemoryUserRepository.save(newUser);
httpResponse.addHeader(LOCATION, "/index.html");
httpResponse.setStatusCode(FOUND);
}
}
27 changes: 27 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/controller/RootController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package nextstep.jwp.controller;

import org.apache.catalina.controller.HttpController;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

import java.util.*;

import static org.apache.coyote.http11.common.HttpHeaderType.CONTENT_TYPE;
import static org.apache.coyote.http11.common.MediaType.TEXT_HTML;
import static org.apache.coyote.http11.response.HttpStatusCode.OK;

public class RootController extends HttpController {

@Override
public boolean canHandle(final HttpRequest httpRequest) {
final Set<String> requestType = Set.of("/");
return requestType.contains(httpRequest.getTarget());
}

@Override
protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) {
httpResponse.addHeader(CONTENT_TYPE, TEXT_HTML.stringifyWithUtf());
httpResponse.setStatusCode(OK);
httpResponse.setBody("Hello world!");
}
}
14 changes: 14 additions & 0 deletions tomcat/src/main/java/org/apache/catalina/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.apache.catalina;

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

import java.io.IOException;

public interface Controller {

void init();
void destory();
void service(HttpRequest request, HttpResponse response) throws IOException;

}
3 changes: 2 additions & 1 deletion tomcat/src/main/java/org/apache/catalina/Manager.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package org.apache.catalina;

import org.apache.catalina.session.Session;

import java.io.IOException;
import nextstep.jwp.model.Session;

/**
* A <b>Manager</b> manages the pool of Sessions that are associated with a
Expand Down
15 changes: 11 additions & 4 deletions tomcat/src/main/java/org/apache/catalina/connector/Connector.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.apache.catalina.connector;

import org.apache.coyote.RequestMapping;
import org.apache.coyote.http11.Http11Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -8,26 +9,32 @@
import java.io.UncheckedIOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Connector implements Runnable {

private static final Logger log = LoggerFactory.getLogger(Connector.class);

private static final int DEFAULT_PORT = 8080;
private static final int DEFAULT_ACCEPT_COUNT = 100;
private static final int DEFAULT_MAX_THREADS = 250;

private final ServerSocket serverSocket;
private final ExecutorService executor;
private boolean stopped;

public Connector() {
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT);
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_MAX_THREADS);
}

public Connector(final int port, final int acceptCount) {
public Connector(final int port, final int acceptCount, final int maxThreads) {
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
this.executor = Executors.newFixedThreadPool(maxThreads);
}


private ServerSocket createServerSocket(final int port, final int acceptCount) {
try {
final int checkedPort = checkPort(port);
Expand Down Expand Up @@ -66,8 +73,8 @@ private void process(final Socket connection) {
if (connection == null) {
return;
}
var processor = new Http11Processor(connection);
new Thread(processor).start();
var processor = new Http11Processor(connection, new RequestMapping());
executor.submit(processor);
}

public void stop() {
Expand Down
Loading