write(byte[] data)와 write(byte b[], int off, int len) 메서드는
* 1바이트 이상을 한 번에 전송 할 수 있어 훨씬 효율적이다.
@@ -63,7 +71,7 @@ class OutputStream_학습_테스트 {
/**
* 효율적인 전송을 위해 스트림에서 버퍼링을 사용 할 수 있다.
* BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다.
- *
+ *
* 버퍼링을 사용하면 OutputStream을 사용할 때 flush를 사용하자.
* flush() 메서드는 버퍼가 아직 가득 차지 않은 상황에서 강제로 버퍼의 내용을 전송한다.
* Stream은 동기(synchronous)로 동작하기 때문에 버퍼가 찰 때까지 기다리면
@@ -108,7 +116,7 @@ class OutputStream_학습_테스트 {
* InputStream은 다른 매체로부터 바이트로 데이터를 읽을 때 사용한다.
* InputStream의 read() 메서드는 기반 메서드이다.
* public abstract int read() throws IOException;
- *
+ *
* InputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 읽기 위해 read() 메서드를 사용한다.
*/
@Nested
diff --git a/tomcat/build.gradle b/tomcat/build.gradle
index 21063b298f..ccb3e2d92d 100644
--- a/tomcat/build.gradle
+++ b/tomcat/build.gradle
@@ -22,6 +22,7 @@ dependencies {
testImplementation 'org.mockito:mockito-core:5.12.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
}
test {
diff --git a/tomcat/src/main/java/com/techcourse/handler/GetLoginHandler.java b/tomcat/src/main/java/com/techcourse/handler/GetLoginHandler.java
new file mode 100644
index 0000000000..18274c6f64
--- /dev/null
+++ b/tomcat/src/main/java/com/techcourse/handler/GetLoginHandler.java
@@ -0,0 +1,25 @@
+package com.techcourse.handler;
+
+import org.apache.catalina.Manager;
+import org.apache.coyote.http11.AbstractHandler;
+import org.apache.coyote.http11.ForwardResult;
+import org.apache.coyote.http11.HttpRequest;
+import org.apache.coyote.http11.HttpStatus;
+
+import java.net.URI;
+
+public class GetLoginHandler extends AbstractHandler {
+
+ @Override
+ public boolean canHandle(HttpRequest httpRequest) {
+ URI uri = httpRequest.getUri();
+ String path = uri.getPath();
+
+ return "/login".equals(path) && httpRequest.getMethod().isGet();
+ }
+
+ @Override
+ protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
+ return new ForwardResult("login.html", HttpStatus.OK);
+ }
+}
diff --git a/tomcat/src/main/java/com/techcourse/handler/GetRegisterHandler.java b/tomcat/src/main/java/com/techcourse/handler/GetRegisterHandler.java
new file mode 100644
index 0000000000..5f05717cb7
--- /dev/null
+++ b/tomcat/src/main/java/com/techcourse/handler/GetRegisterHandler.java
@@ -0,0 +1,25 @@
+package com.techcourse.handler;
+
+import org.apache.catalina.Manager;
+import org.apache.coyote.http11.AbstractHandler;
+import org.apache.coyote.http11.ForwardResult;
+import org.apache.coyote.http11.HttpRequest;
+import org.apache.coyote.http11.HttpStatus;
+
+import java.net.URI;
+
+public class GetRegisterHandler extends AbstractHandler {
+
+ @Override
+ public boolean canHandle(HttpRequest httpRequest) {
+ URI uri = httpRequest.getUri();
+ String path = uri.getPath();
+
+ return "/register".equals(path) && httpRequest.getMethod().isGet();
+ }
+
+ @Override
+ protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
+ return new ForwardResult("register.html", HttpStatus.OK);
+ }
+}
diff --git a/tomcat/src/main/java/com/techcourse/handler/HelloHandler.java b/tomcat/src/main/java/com/techcourse/handler/HelloHandler.java
new file mode 100644
index 0000000000..df0c732af4
--- /dev/null
+++ b/tomcat/src/main/java/com/techcourse/handler/HelloHandler.java
@@ -0,0 +1,25 @@
+package com.techcourse.handler;
+
+import org.apache.catalina.Manager;
+import org.apache.coyote.http11.AbstractHandler;
+import org.apache.coyote.http11.ForwardResult;
+import org.apache.coyote.http11.HttpRequest;
+import org.apache.coyote.http11.HttpStatus;
+
+import java.net.URI;
+
+public class HelloHandler extends AbstractHandler {
+
+ @Override
+ public boolean canHandle(HttpRequest httpRequest) {
+ URI uri = httpRequest.getUri();
+ String path = uri.getPath();
+
+ return "/".equals(path);
+ }
+
+ @Override
+ protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
+ return new ForwardResult("hello.html", HttpStatus.OK);
+ }
+}
diff --git a/tomcat/src/main/java/com/techcourse/handler/NotFoundHandler.java b/tomcat/src/main/java/com/techcourse/handler/NotFoundHandler.java
new file mode 100644
index 0000000000..7cbd73605e
--- /dev/null
+++ b/tomcat/src/main/java/com/techcourse/handler/NotFoundHandler.java
@@ -0,0 +1,20 @@
+package com.techcourse.handler;
+
+import org.apache.catalina.Manager;
+import org.apache.coyote.http11.AbstractHandler;
+import org.apache.coyote.http11.ForwardResult;
+import org.apache.coyote.http11.HttpRequest;
+import org.apache.coyote.http11.HttpStatus;
+
+public class NotFoundHandler extends AbstractHandler {
+
+ @Override
+ public boolean canHandle(HttpRequest httpRequest) {
+ return true;
+ }
+
+ @Override
+ protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
+ return new ForwardResult("404.html", HttpStatus.NOT_FOUND);
+ }
+}
diff --git a/tomcat/src/main/java/com/techcourse/handler/PostLoginHandler.java b/tomcat/src/main/java/com/techcourse/handler/PostLoginHandler.java
new file mode 100644
index 0000000000..9a6e84b110
--- /dev/null
+++ b/tomcat/src/main/java/com/techcourse/handler/PostLoginHandler.java
@@ -0,0 +1,61 @@
+package com.techcourse.handler;
+
+import com.techcourse.db.InMemoryUserRepository;
+import com.techcourse.model.User;
+import jakarta.servlet.http.HttpSession;
+import org.apache.catalina.Manager;
+import org.apache.coyote.http11.AbstractHandler;
+import org.apache.coyote.http11.ForwardResult;
+import org.apache.coyote.http11.Header;
+import org.apache.coyote.http11.HttpHeaderKey;
+import org.apache.coyote.http11.HttpRequest;
+import org.apache.coyote.http11.HttpStatus;
+import org.apache.coyote.http11.QueryParameter;
+
+import java.net.URI;
+
+public class PostLoginHandler extends AbstractHandler {
+
+ @Override
+ public boolean canHandle(HttpRequest httpRequest) {
+ URI uri = httpRequest.getUri();
+ String path = uri.getPath();
+
+ return "/login".equals(path) && httpRequest.getMethod().isPost();
+ }
+
+ @Override
+ protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
+ if (httpRequest.hasNotApplicationXW3FormUrlEncodedBody()) {
+ throw new RuntimeException();
+ }
+
+ QueryParameter queryParameter = new QueryParameter(httpRequest.body());
+ Header header = Header.empty();
+ String redirectionPath = "401.html";
+
+ if (isLoggedIn(queryParameter)) {
+ HttpSession session = findSessionOrCreate(sessionManager, createCookie(httpRequest));
+ session.setAttribute("user", getUser(queryParameter));
+ header.append(HttpHeaderKey.SET_COOKIE, getSessionKey() + "=" + session.getId());
+ redirectionPath = "index.html";
+ }
+
+ header.append(HttpHeaderKey.LOCATION, redirectionPath);
+ return new ForwardResult(HttpStatus.FOUND, header);
+ }
+
+ private boolean isLoggedIn(QueryParameter queryParameter) {
+ String password = queryParameter.get("password").orElse("");
+
+ return queryParameter.get("account")
+ .flatMap(InMemoryUserRepository::findByAccount)
+ .map(it -> it.checkPassword(password))
+ .orElse(false);
+ }
+
+ private User getUser(QueryParameter queryParameter) {
+ String account = queryParameter.get("account").orElseThrow();
+ return InMemoryUserRepository.findByAccount(account).orElseThrow();
+ }
+}
diff --git a/tomcat/src/main/java/com/techcourse/handler/PostRegisterHandler.java b/tomcat/src/main/java/com/techcourse/handler/PostRegisterHandler.java
new file mode 100644
index 0000000000..7f0bf64eb7
--- /dev/null
+++ b/tomcat/src/main/java/com/techcourse/handler/PostRegisterHandler.java
@@ -0,0 +1,43 @@
+package com.techcourse.handler;
+
+import com.techcourse.db.InMemoryUserRepository;
+import com.techcourse.model.User;
+import org.apache.catalina.Manager;
+import org.apache.coyote.http11.AbstractHandler;
+import org.apache.coyote.http11.ForwardResult;
+import org.apache.coyote.http11.HttpRequest;
+import org.apache.coyote.http11.HttpStatus;
+import org.apache.coyote.http11.QueryParameter;
+
+import java.net.URI;
+
+public class PostRegisterHandler extends AbstractHandler {
+
+ @Override
+ public boolean canHandle(HttpRequest httpRequest) {
+ URI uri = httpRequest.getUri();
+ String path = uri.getPath();
+
+ return "/register".equals(path) && httpRequest.getMethod().isPost();
+ }
+
+ @Override
+ protected ForwardResult forward(HttpRequest httpRequest, Manager sessionManager) {
+ if (httpRequest.hasNotApplicationXW3FormUrlEncodedBody()) {
+ throw new RuntimeException();
+ }
+
+ registerNewUser(httpRequest);
+
+ return new ForwardResult("index.html", HttpStatus.OK);
+ }
+
+ private void registerNewUser(HttpRequest httpRequest) {
+ QueryParameter body = new QueryParameter(httpRequest.body());
+ String account = body.get("account").orElseThrow();
+ String password = body.get("password").orElseThrow();
+ String email = body.get("email").orElseThrow();
+
+ InMemoryUserRepository.save(new User(account, password, email));
+ }
+}
diff --git a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java
index 3b2c4dda7c..9fed635b96 100644
--- a/tomcat/src/main/java/org/apache/catalina/connector/Connector.java
+++ b/tomcat/src/main/java/org/apache/catalina/connector/Connector.java
@@ -1,5 +1,6 @@
package org.apache.catalina.connector;
+import org.apache.catalina.Manager;
import org.apache.coyote.http11.Http11Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,15 +18,18 @@ public class Connector implements Runnable {
private static final int DEFAULT_ACCEPT_COUNT = 100;
private final ServerSocket serverSocket;
+ private final Manager sessionManager;
+
private boolean stopped;
- public Connector() {
- this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT);
+ public Connector(Manager sessionManager) {
+ this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, sessionManager);
}
- public Connector(final int port, final int acceptCount) {
+ public Connector(final int port, final int acceptCount, final Manager sessionManager) {
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
+ this.sessionManager = sessionManager;
}
private ServerSocket createServerSocket(final int port, final int acceptCount) {
@@ -66,7 +70,7 @@ private void process(final Socket connection) {
if (connection == null) {
return;
}
- var processor = new Http11Processor(connection);
+ var processor = new Http11Processor(connection, sessionManager);
new Thread(processor).start();
}
diff --git a/tomcat/src/main/java/org/apache/catalina/session/SimpleSession.java b/tomcat/src/main/java/org/apache/catalina/session/SimpleSession.java
new file mode 100644
index 0000000000..bcfca52a58
--- /dev/null
+++ b/tomcat/src/main/java/org/apache/catalina/session/SimpleSession.java
@@ -0,0 +1,101 @@
+package org.apache.catalina.session;
+
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSessionContext;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class SimpleSession implements HttpSession {
+
+ private final UUID sessionId = UUID.randomUUID();
+ private final Map