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단계] 땡칠(박성철) 미션 제출합니다. #471

Merged
merged 16 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
23 changes: 23 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/handler/HelloController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package nextstep.jwp.handler;

import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpResponse;
import org.apache.coyote.http11.TargetPath;
import org.apache.coyote.http11.controller.Controller;
import org.apache.coyote.http11.header.ContentType;

public class HelloController implements Controller {

private static final TargetPath SUPPORTED_PATH = new TargetPath("/");

@Override
public boolean supports(HttpRequest httpRequest) {
return httpRequest.getTarget().getPath().equals(SUPPORTED_PATH) && httpRequest.getMethod().isGet();
}

@Override
public void handle(HttpRequest httpRequest, HttpResponse httpResponse) {
httpResponse.setContentType(new ContentType("text/html"));
httpResponse.setBody("Hello world!");
}
}
78 changes: 78 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/handler/LoginController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package nextstep.jwp.handler;

import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpResponse;
import org.apache.coyote.http11.TargetPath;
import org.apache.coyote.http11.body.FormData;
import org.apache.coyote.http11.controller.FileController;
import org.apache.coyote.http11.controller.GetAndPostController;
import org.apache.coyote.http11.header.Cookies;
import org.apache.coyote.http11.session.Session;
import org.apache.coyote.http11.session.SessionManager;

import java.util.Optional;

public class LoginController extends GetAndPostController {

private static final String SESSION_KEY = "JSESSIONID";
private static final String SESSION_USER_KEY = "user";

private static final String UNAUTHORIZED_LOCATION = "/401";
private static final String MAIN_LOCATION = "/index";

private static final TargetPath SUPPORTED_PATH = new TargetPath("/login").autoComplete();

private final FileController fileHandler = new FileController();

@Override
public boolean supports(HttpRequest httpRequest) {
if (httpRequest.getMethod().isGet() || httpRequest.getMethod().isPost()) {
return httpRequest.getTarget().getPath().autoComplete().equals(SUPPORTED_PATH);
}
return false;
}

@Override
protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) {
boolean isSignedIn = httpRequest.getSession(SESSION_KEY)
.map(session -> session.hasAttribute(SESSION_USER_KEY))
.isPresent();
if (isSignedIn) {
httpResponse.redirectTo(MAIN_LOCATION);
}
fileHandler.handle(httpRequest, httpResponse);
}

@Override
protected void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) {
FormData formData = FormData.of(httpRequest.getBody());
String account = formData.get("account");
String password = formData.get("password");

Optional<User> found = InMemoryUserRepository.findByAccount(account);
if (found.isPresent()) {
User user = found.get();
signIn(httpResponse, user, password);
return;
}
httpResponse.redirectTo(UNAUTHORIZED_LOCATION);
}

private void signIn(final HttpResponse httpResponse, final User user, final String password) {
if (user.checkPassword(password)) {
Session session = new Session();
session.addAttribute(SESSION_USER_KEY, user);
SessionManager.add(session);

Cookies cookies = new Cookies();
cookies.add(SESSION_KEY, session.getId());

httpResponse.redirectTo(MAIN_LOCATION);
httpResponse.setCookies(cookies);
return;
}
httpResponse.redirectTo(UNAUTHORIZED_LOCATION);
}
}
69 changes: 0 additions & 69 deletions tomcat/src/main/java/nextstep/jwp/handler/LoginHandler.java

This file was deleted.

43 changes: 43 additions & 0 deletions tomcat/src/main/java/nextstep/jwp/handler/RegisterController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package nextstep.jwp.handler;

import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpResponse;
import org.apache.coyote.http11.TargetPath;
import org.apache.coyote.http11.body.FormData;
import org.apache.coyote.http11.controller.FileController;
import org.apache.coyote.http11.controller.GetAndPostController;

public class RegisterController extends GetAndPostController {

private static final String MAIN_LOCATION = "/index";
private static final TargetPath SUPPORTED_PATH = new TargetPath("/register").autoComplete();

private final FileController fileHandler = new FileController();

@Override
public boolean supports(HttpRequest httpRequest) {
if (httpRequest.getMethod().isGet() || httpRequest.getMethod().isPost()) {
return httpRequest.getTarget().getPath().autoComplete().equals(SUPPORTED_PATH);
}
return false;
}

@Override
protected void doGet(final HttpRequest httpRequest, final HttpResponse httpResponse) {
fileHandler.handle(httpRequest, httpResponse);
}

@Override
protected void doPost(final HttpRequest httpRequest, final HttpResponse httpResponse) {
FormData formData = FormData.of(httpRequest.getBody());

String account = formData.get("account");
String password = formData.get("password");
String email = formData.get("email");

InMemoryUserRepository.save(new User(account, password, email));
httpResponse.redirectTo(MAIN_LOCATION);
}
}
29 changes: 0 additions & 29 deletions tomcat/src/main/java/nextstep/jwp/handler/RegisterHandler.java

This file was deleted.

26 changes: 17 additions & 9 deletions tomcat/src/main/java/org/apache/catalina/connector/Connector.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
package org.apache.catalina.connector;

import java.net.SocketException;
import org.apache.coyote.http11.Http11Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.coyote.http11.Http11Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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_ACCEPT_COUNT = 100; // 모든 쓰레드가 사용중일 때 들어오는 연결에 대한 대기열의 길이
private static final int MAX_THREADS = 250; // 동시에 연결 후 처리 가능한 요청의 최대 개수
// 최대 ThradPool의 크기는 250, 모든 Thread가 사용 중인(Busy) 상태이면 100명까지 대기 상태로 만들려면 어떻게 할까?
// acceptCount를 100으로 한다
// 처리중인 연결이 250개 이므로 나머지는 OS 큐에서 대기하게 된다.
private static final int SOCKET_TIMEOUT_SECONDS = 10;
Comment on lines +19 to 24
Copy link
Author

Choose a reason for hiding this comment

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

정확한지는 잘 모르겠는데 제가 이해한대로 우선 적어보았습니다.
히이로는 최대 ThradPool의 크기는 250, 모든 Thread가 사용 중인(Busy) 상태이면 100명까지 대기 상태로 만들려면 어떻게 할까?
라는 요구사항을 어떻게 반영해야한다고 생각하시나요?

Choose a reason for hiding this comment

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

네 저도 정확하게 땡칠과 같은 방식으로 이해하고 있습니다. 모든 쓰레드가 사용중일 떄 100개의 connection 요청들을 queueing하기 위해서 acceptCount로 ServerSocket을 생성할 때 OS에 저장되는 connection들에 대한 queue size를 100으로 설정해줍니다.

ThreadPool 생성 시 corePoolSize와 maximumPoolSize는 250으로 동일하게 설정했으니 시작부터 250개의 쓰레드가 생성되어 동작하면서 요청들을 처리하게 될 것 같습니다.

혹시 어떤 부분이 궁금하셨던건지 더 자세하게 따로 말씀해주시면 같이 고민해봐도 좋을 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

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

답변해주신 내용이 바로 궁금한 부분이었습니다.
Accept Count가 OS가 queueing 할 크기(백로그 크기)를 결정하는 부분이라고 이해했어요!


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

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

public Connector(final int port, final int acceptCount) {
public Connector(final int port, final int acceptCount, final int maxThreads) {
this.pool = Executors.newFixedThreadPool(maxThreads);
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
}
Expand Down Expand Up @@ -60,6 +67,7 @@ private void connect() {
try {
process(serverSocket.accept());
} catch (IOException e) {
pool.shutdown();
log.error(e.getMessage(), e);
}
}
Expand All @@ -70,7 +78,7 @@ private void process(final Socket connection) throws SocketException {
}
connection.setSoTimeout(SOCKET_TIMEOUT_SECONDS * 1000);
var processor = new Http11Processor(connection);
new Thread(processor).start();
pool.execute(processor);
}

public void stop() {
Expand Down
Loading