Skip to content

Commit

Permalink
[톰캣 구현하기 3, 4단계] 루쿠(백경환) 미션 제출합니다. (#488)
Browse files Browse the repository at this point in the history
* train : 학습 테스트 학습

* feat : GET /index.html 응답하기 +  CSS 지원하기

* feat : QueryString 파싱

* feat : HTTP Status Code 302 구현

* feat : reqeustHeader 파싱 기능 추가 + POST 방식으로 회원가입 기능 추가

* feat : 로그인 페이지도 버튼을 눌렀을 때 GET 방식에서 POST 방식으로 전송하도록 변경

* feat : 세션, 쿠키, 세션매니저 클래스 구현

* feat : HttpResponse 클래스 구현

* feat : 로그인시 쿠키 설정, 로그인 페이지 접속시 쿠키 헤더 확인 후 응답 처리 추가

* refactor: 불필요한 메서드 삭제

* feat: HttpRequest 클래스 구현

* feat: HttpRequest 클래스 적용

* fix: 컨텐트 타입 text/html로 응답 수정

* fix: favicon.ico 응답 추가

* fix: 로그 삭제

* refactor: 접근 제어자 수정

* refactor: 기존 메서드 활용

* fix: 기존 메서드 내용 구현

* refactor: HttpStatus enum 추가

* refactor: HttpMethod enum 추가

* feat: Controller 인터페이스 추가

* refactor: login, register Controller 도입

* refactor: Request url 매핑 컨트롤러 추가

* test: RequestMapping 테스트 코드 추가

* refactor: RootController 분리 및 메서드 삭제

* test: 테스트코드 추가

* feat: 쓰레드 풀 설정 + 세션 동시성 해결

* feat: 쓰레드 풀 설정 + 세션 동시성 해결

* fix: 로그인 페이지 불러오기 버그 수정

* refactor: 새로운 인스턴스 생기지 않도록 수정

* refactor: 메서드명 수정

* refactor: 필드 이름 수정

* refactor: 개행 제거

* refactor: 방어 로직 추가
  • Loading branch information
aiaiaiai1 authored Sep 15, 2023
1 parent df07c01 commit 56a9141
Show file tree
Hide file tree
Showing 15 changed files with 406 additions and 154 deletions.
18 changes: 11 additions & 7 deletions tomcat/src/main/java/org/apache/catalina/connector/Connector.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
package org.apache.catalina.connector;

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.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_MAX_THREADS = 10;

private final ServerSocket serverSocket;
private final ExecutorService executorService;
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.executorService = Executors.newFixedThreadPool(maxThreads);
this.stopped = false;
}

Expand Down Expand Up @@ -67,7 +71,7 @@ private void process(final Socket connection) {
return;
}
var processor = new Http11Processor(connection);
new Thread(processor).start();
executorService.execute(processor);
}

public void stop() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.apache.coyote.controller;

import static org.apache.coyote.http11.HttpMethod.GET;
import static org.apache.coyote.http11.HttpMethod.POST;

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

public abstract class AbstractController implements Controller {

@Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
if (request.getMethod() == GET) {
doGet(request, response);
return;
}

if (request.getMethod() == POST) {
doPost(request, response);
return;
}

throw new IllegalArgumentException("지원하지 않는 메서드 입니다.");
}

protected void doPost(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ }

protected void doGet(HttpRequest request, HttpResponse response) throws Exception { /* NOOP */ }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.apache.coyote.controller;


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

public interface Controller {
void service(HttpRequest request, HttpResponse response) throws Exception;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.apache.coyote.controller;

import static org.apache.coyote.http11.HttpStatus.FOUND;
import static org.apache.coyote.http11.HttpStatus.OK;

import java.util.Map;
import java.util.UUID;
import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.coyote.http11.HttpCookie;
import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpResponse;
import org.apache.coyote.http11.Session;
import org.apache.coyote.http11.SessionManager;
import org.apache.coyote.http11.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoginController extends AbstractController {
private static final Logger log = LoggerFactory.getLogger(LoginController.class);
private static final SessionManager sessionManager = new SessionManager();

@Override
protected void doPost(HttpRequest request, HttpResponse response) throws Exception {
Map<String, String> queryParms = Utils.parseToQueryParms(request.getBody());

try {
User user = InMemoryUserRepository.findByAccount(queryParms.get("account"))
.orElseThrow(() -> new IllegalArgumentException("해당 사용자 없음"));

if (!user.checkPassword(queryParms.get("password"))) {
throw new IllegalArgumentException("비밀번호 불일치");
}
log.info("user: {}", user);

Session session = new Session(UUID.randomUUID().toString());
session.setAttribute("user", user);
sessionManager.add(session);
response.setStatus(FOUND);
response.setRedirectUrl("/index.html");
response.setCookie("JSESSIONID=" + session.getId());

} catch (IllegalArgumentException e) {
log.error("error : {}", e);
response.setStatus(FOUND);
response.setRedirectUrl("/401.html");

}
}

@Override
protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
HttpCookie cookie = new HttpCookie(request.getHeaders().get("Cookie"));

String sessionId = cookie.findValue("JSESSIONID");
if (sessionManager.isExist(sessionId)) {
response.setStatus(FOUND);
response.setRedirectUrl("/index.html");
} else {
response.setStatus(OK);
response.setContentType("text/html");
response.setBody(Utils.readFile("static", "login.html"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.apache.coyote.controller;

import static org.apache.coyote.http11.HttpStatus.FOUND;
import static org.apache.coyote.http11.HttpStatus.OK;

import java.util.Map;
import java.util.Objects;
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.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RegisterController extends AbstractController {
private static final Logger log = LoggerFactory.getLogger(RegisterController.class);
public static final int LOGIN_QUERY_PARAMS = 3;

@Override
protected void doPost(HttpRequest request, HttpResponse response) {
Map<String, String> queryParms = Utils.parseToQueryParms(request.getBody());

validateQueryParms(queryParms);
User user = new User(queryParms.get("account"), queryParms.get("password"),
queryParms.get("email"));

InMemoryUserRepository.save(user);
response.setStatus(FOUND);
response.setRedirectUrl("/index.html");
}

private void validateQueryParms(Map<String, String> queryParms) {
long count = queryParms.entrySet().stream()
.filter(entry -> Objects.nonNull(entry.getValue()))
.count();
if (count != LOGIN_QUERY_PARAMS) {
throw new IllegalArgumentException();
}
}

@Override
protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
response.setStatus(OK);
response.setContentType("text/html");
response.setBody(Utils.readFile("static", "register.html"));
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.apache.coyote.controller;

import java.util.HashMap;
import java.util.Map;
import org.apache.coyote.http11.HttpRequest;

public class RequestMapping {

final Map<String, Controller> requestMapping = new HashMap<>();

public RequestMapping() {
initiateMapping();
}

private void initiateMapping() {
requestMapping.put("/login", new LoginController());
requestMapping.put("/register", new RegisterController());
requestMapping.put("/", new RootController());
requestMapping.put("resource", new ResourceController());
}

public Controller getController(HttpRequest request) {
Controller resourceController = requestMapping.get("resource");
return requestMapping.getOrDefault(request.getPath(), resourceController);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.apache.coyote.controller;

import static org.apache.coyote.http11.HttpStatus.FOUND;
import static org.apache.coyote.http11.HttpStatus.OK;

import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpResponse;
import org.apache.coyote.http11.Utils;

public class ResourceController extends AbstractController {

protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
response.setStatus(OK);

String path = request.getPath();
String fileName = path.substring(path.lastIndexOf('/') + 1);

if (fileName.endsWith(".html")) {
response.setContentType("text/html");
response.setBody(Utils.readFile("static", fileName));
return;
}

if (fileName.equals("styles.css")) {
response.setContentType("text/css");
response.setBody(Utils.readFile("static/css", fileName));
return;
}

if (fileName.endsWith(".js") && !fileName.equals("scripts.js")) {
response.setContentType("text/javascript");
response.setBody(Utils.readFile("static/assets", fileName));
return;
}

if (fileName.equals("scripts.js")) {
response.setContentType("text/javascript");
response.setBody(Utils.readFile("static/js", fileName));
return;
}

if (fileName.equals("favicon.ico")) {
response.setContentType("text/javascript");
response.setBody("Hello world!");
return;
}

response.setStatus(FOUND);
response.setRedirectUrl("404.html");
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.apache.coyote.controller;

import org.apache.coyote.http11.HttpRequest;
import org.apache.coyote.http11.HttpResponse;
import org.apache.coyote.http11.HttpStatus;

public class RootController extends AbstractController {

@Override
protected void doGet(HttpRequest request, HttpResponse response) throws Exception {
response.setStatus(HttpStatus.OK);
response.setContentType("text/html");
response.setBody("Hello world!");
}

}
Loading

0 comments on commit 56a9141

Please sign in to comment.