From d63694d93d44cf7d1f1d04f7febd6a5126935fba Mon Sep 17 00:00:00 2001 From: nathan29849 Date: Mon, 28 Mar 2022 11:25:25 +0900 Subject: [PATCH 01/13] =?UTF-8?q?refactor:=20Request,=20Response=20Class?= =?UTF-8?q?=20package=20=EC=9D=B4=EB=8F=99(util=20->=20webserver)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/{util => webserver}/Request.java | 4 +++- src/main/java/webserver/RequestHandler.java | 9 --------- src/main/java/{util => webserver}/Response.java | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) rename src/main/java/{util => webserver}/Request.java (97%) rename src/main/java/{util => webserver}/Response.java (99%) diff --git a/src/main/java/util/Request.java b/src/main/java/webserver/Request.java similarity index 97% rename from src/main/java/util/Request.java rename to src/main/java/webserver/Request.java index 376a6e9e..3c5ade7d 100644 --- a/src/main/java/util/Request.java +++ b/src/main/java/webserver/Request.java @@ -1,4 +1,4 @@ -package util; +package webserver; import java.io.BufferedReader; import java.io.IOException; @@ -11,7 +11,9 @@ import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import util.HttpRequestUtils; import util.HttpRequestUtils.Pair; +import util.IOUtils; public class Request { diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java index 587e7a29..2c535740 100644 --- a/src/main/java/webserver/RequestHandler.java +++ b/src/main/java/webserver/RequestHandler.java @@ -1,21 +1,12 @@ package webserver; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; -import java.nio.file.Files; -import java.util.Map; -import model.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import util.PrintUtils; -import util.Request; -import util.Response; public class RequestHandler extends Thread { private static final Logger log = LoggerFactory.getLogger(RequestHandler.class); diff --git a/src/main/java/util/Response.java b/src/main/java/webserver/Response.java similarity index 99% rename from src/main/java/util/Response.java rename to src/main/java/webserver/Response.java index 15d300f4..59d38ee2 100644 --- a/src/main/java/util/Response.java +++ b/src/main/java/webserver/Response.java @@ -1,4 +1,4 @@ -package util; +package webserver; import db.DataBase; import java.io.DataOutputStream; From e54e6323e39c6b652ab452e879ea1888c36926d0 Mon Sep 17 00:00:00 2001 From: hsjang Date: Mon, 28 Mar 2022 11:56:11 +0900 Subject: [PATCH 02/13] =?UTF-8?q?refactor:=20String=20httpMethod=20->=20Ht?= =?UTF-8?q?tpMethod=20Enum=20class=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/HttpMethod.java | 25 +++++++++++++++++++++++++ src/main/java/webserver/Request.java | 8 ++++---- src/main/java/webserver/Response.java | 2 +- 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 src/main/java/webserver/HttpMethod.java diff --git a/src/main/java/webserver/HttpMethod.java b/src/main/java/webserver/HttpMethod.java new file mode 100644 index 00000000..6d14baef --- /dev/null +++ b/src/main/java/webserver/HttpMethod.java @@ -0,0 +1,25 @@ +package webserver; + +public enum HttpMethod { + + GET, POST; + + public static HttpMethod create(String httpMethod) { + if (httpMethod.equals("GET")) { + return GET; + } + if (httpMethod.equals("POST")) { + return POST; + } + return null; + } + + public static boolean isGet(Request request) { + return request.getHttpMethod().equals(GET); + } + + public static boolean isPost(Request request) { + return request.getHttpMethod().equals(POST); + } + +} diff --git a/src/main/java/webserver/Request.java b/src/main/java/webserver/Request.java index 3c5ade7d..1496339c 100644 --- a/src/main/java/webserver/Request.java +++ b/src/main/java/webserver/Request.java @@ -28,7 +28,7 @@ public class Request { private String requestLine; private String[] parsedRequestLine; - private String httpMethod; + private HttpMethod httpMethod; private String path; private List headerPairs; private Map parsedQueryString; @@ -48,7 +48,7 @@ public void readRequest() throws IOException { private void extractRequestLine(BufferedReader br) throws IOException { this.requestLine = br.readLine(); this.parsedRequestLine = requestLine.split(" "); - this.httpMethod = parsedRequestLine[HTTP_METHOD]; + this.httpMethod = HttpMethod.create(parsedRequestLine[HTTP_METHOD]); this.path = parseRequestURL()[PATH]; this.parsedQueryString = takeParsedQueryString(); } @@ -81,8 +81,8 @@ private String decode(String target) { return URLDecoder.decode(target, StandardCharsets.UTF_8); } - public boolean isPOST() { - return httpMethod.equals("POST"); + public HttpMethod getHttpMethod() { + return httpMethod; } public List getHeaderPairs() { diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index 59d38ee2..aac9481f 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -24,7 +24,7 @@ public Response(OutputStream out, Request request) { public void writeResponse() throws IOException { log.debug("requestLine: {}", request.getRequestLine()); - if (request.isPOST() && request.getPath().equals("/user/create")) { + if (HttpMethod.isPost(request) && request.getPath().equals("/user/create")) { this.body = Files.readAllBytes(new File("./webapp/index.html").toPath()); From ff4dbae0d7f7a730173da0baa755bd03583d7008 Mon Sep 17 00:00:00 2001 From: hsjang Date: Mon, 28 Mar 2022 14:18:10 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=ED=99=95=EC=9D=B8=ED=95=98=EA=B3=A0=20res?= =?UTF-8?q?ponse=EC=97=90=20Set-Cookie=20=ED=97=A4=EB=8D=94=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/Response.java | 40 +++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index aac9481f..b3994f50 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -12,8 +12,9 @@ import org.slf4j.LoggerFactory; public class Response { + private Logger log = LoggerFactory.getLogger(Response.class); - private byte[] body; + private byte[] body = new byte[0]; private DataOutputStream dos; private Request request; @@ -24,9 +25,8 @@ public Response(OutputStream out, Request request) { public void writeResponse() throws IOException { log.debug("requestLine: {}", request.getRequestLine()); - if (HttpMethod.isPost(request) && request.getPath().equals("/user/create")) { - this.body = Files.readAllBytes(new File("./webapp/index.html").toPath()); + if (HttpMethod.isPost(request) && request.getPath().equals("/user/create")) { Map parsedBody = request.takeParsedBody(); log.debug("POST BODY: {}", parsedBody); @@ -39,13 +39,31 @@ public void writeResponse() throws IOException { saveUser(user); return; } + + if (HttpMethod.isPost(request) && request.getPath().equals("/user/login")) { + Map parsedBody = request.takeParsedBody(); + log.debug("POST BODY: {}", parsedBody); + + User user = DataBase.findUserById(parsedBody.get("userId")); + + if (user != null && user.getPassword().equals(parsedBody.get("password"))) { + response302Header("http://localhost:8080/index.html", user.getUserId()); + responseBody(); + return; + } + response302Header("http://localhost:8080/user/login_failed.html"); + responseBody(); + return; + } + + //GET 일 때 this.body = Files.readAllBytes(new File("./webapp" + request.getPath()).toPath()); response200Header(); responseBody(); } private void saveUser(User user) { - if (DataBase.validateDuplicatedId(user)){ + if (DataBase.validateDuplicatedId(user)) { DataBase.addUser(user); response302Header("http://localhost:8080/index.html"); responseBody(); @@ -53,7 +71,6 @@ private void saveUser(User user) { } response302Header("http://localhost:8080/user/form.html"); responseBody(); - return; } private void response302Header(String redirectURL) { @@ -68,6 +85,19 @@ private void response302Header(String redirectURL) { } } + private void response302Header(String redirectURL, String userId) { + try { + dos.writeBytes("HTTP/1.1 302 Found\r\n"); + dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); + dos.writeBytes("Content-Length: " + body.length + "\r\n"); + dos.writeBytes("Location: " + redirectURL + "\r\n"); + dos.writeBytes("Set-Cookie: sessionId=" + userId + "; Path=/"); + dos.writeBytes("\r\n"); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + private void response200Header() { try { dos.writeBytes("HTTP/1.1 200 OK \r\n"); From 9b79ba765365eaf09921d68b9cf42fddec46ed00 Mon Sep 17 00:00:00 2001 From: nathan29849 Date: Mon, 28 Mar 2022 16:33:00 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat:=20Cookie=EB=A5=BC=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20logout=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 ++++++++++++++ src/main/java/webserver/Response.java | 20 +++++++++++++++++++- webapp/index.html | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 732dba3d..5858786b 100644 --- a/README.md +++ b/README.md @@ -73,3 +73,17 @@ - orElseGet - Supplier로 wrapping한 값을 받는다. - **`null`일 경우에만** 뒤의 로직이 실행된다.(lazy) + +--- + +## Step4 : 웹서버 4단계 - 쿠키를 이용한 로그인 구현 + +- 302, 304 차이 +- response body가 없어도 되는 상태 코드(302, 304, 204) +- 로그아웃 방법(Cookie 생명주기 설정, session의 역할 ~ store(Map)) +- Post -> Redirect -> Get +- [Set-Cookie] HTTP/1.1 vs. HTTP/2 : 세미콜론(;)으로 결합이 가능한지 아닌지 +- [Set-Cookie] 작성 순서 +- [Set-Cookie] Path value default는 없는건가? + - 참고 : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie + - 참고2: https://stackoverflow.com/questions/16305814/are-multiple-cookie-headers-allowed-in-an-http-request diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index b3994f50..e9073717 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -25,6 +25,11 @@ public Response(OutputStream out, Request request) { public void writeResponse() throws IOException { log.debug("requestLine: {}", request.getRequestLine()); + if (HttpMethod.isGet(request) && request.getPath().equals("/user/logout")) { + logoutHeader("http://localhost:8080/index.html"); + responseBody(); + return; + } if (HttpMethod.isPost(request) && request.getPath().equals("/user/create")) { @@ -91,7 +96,20 @@ private void response302Header(String redirectURL, String userId) { dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); dos.writeBytes("Content-Length: " + body.length + "\r\n"); dos.writeBytes("Location: " + redirectURL + "\r\n"); - dos.writeBytes("Set-Cookie: sessionId=" + userId + "; Path=/"); + dos.writeBytes("Set-Cookie: sessionId=" + userId + "; max-age=20; Path=/; HttpOnly\r\n"); + dos.writeBytes("\r\n"); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + + private void logoutHeader(String redirectURL) { + try { + dos.writeBytes("HTTP/1.1 302 Found\r\n"); + dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); + dos.writeBytes("Content-Length: " + body.length + "\r\n"); + dos.writeBytes("Location: " + redirectURL + "\r\n"); + dos.writeBytes("Set-Cookie: sessionId=; max-age=-1; Path=/\r\n"); dos.writeBytes("\r\n"); } catch (IOException e) { log.error(e.getMessage()); diff --git a/webapp/index.html b/webapp/index.html index 4ee2a02d..939884b9 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -71,7 +71,7 @@
  • 로그인
  • 회원가입
  • --> -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • From ae90448d6ef1a8a4391357a2030c34cfdd28c1b8 Mon Sep 17 00:00:00 2001 From: hsjang Date: Tue, 29 Mar 2022 12:03:48 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EB=A7=A4=ED=95=91=EC=9D=84=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?httpMethod,=20path=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EA=B0=80?= =?UTF-8?q?=EC=A7=84=20ControllerMapper=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/util/IOUtils.java | 1 - src/main/java/webserver/ControllerMapper.java | 32 +++++++++++++++++++ src/main/java/webserver/Request.java | 6 ++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/main/java/webserver/ControllerMapper.java diff --git a/src/main/java/util/IOUtils.java b/src/main/java/util/IOUtils.java index a0470ee2..ed39b930 100644 --- a/src/main/java/util/IOUtils.java +++ b/src/main/java/util/IOUtils.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import util.HttpRequestUtils.Pair; public class IOUtils { diff --git a/src/main/java/webserver/ControllerMapper.java b/src/main/java/webserver/ControllerMapper.java new file mode 100644 index 00000000..89dff35f --- /dev/null +++ b/src/main/java/webserver/ControllerMapper.java @@ -0,0 +1,32 @@ +package webserver; + +import java.util.Objects; + +public class ControllerMapper { + + private HttpMethod httpMethod; + private String path; + + public ControllerMapper(HttpMethod httpMethod, String path) { + this.httpMethod = httpMethod; + this.path = path; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ControllerMapper that = (ControllerMapper) o; + return httpMethod == that.httpMethod && Objects.equals(path, that.path); + } + + @Override + public int hashCode() { + return Objects.hash(httpMethod, path); + } + +} diff --git a/src/main/java/webserver/Request.java b/src/main/java/webserver/Request.java index 1496339c..aa088c55 100644 --- a/src/main/java/webserver/Request.java +++ b/src/main/java/webserver/Request.java @@ -30,6 +30,7 @@ public class Request { private String[] parsedRequestLine; private HttpMethod httpMethod; private String path; + private ControllerMapper controllerMapper; private List headerPairs; private Map parsedQueryString; private String requestBody; @@ -50,6 +51,7 @@ private void extractRequestLine(BufferedReader br) throws IOException { this.parsedRequestLine = requestLine.split(" "); this.httpMethod = HttpMethod.create(parsedRequestLine[HTTP_METHOD]); this.path = parseRequestURL()[PATH]; + this.controllerMapper = new ControllerMapper(httpMethod, path); this.parsedQueryString = takeParsedQueryString(); } @@ -85,6 +87,10 @@ public HttpMethod getHttpMethod() { return httpMethod; } + public ControllerMapper getControllerMapper() { + return controllerMapper; + } + public List getHeaderPairs() { return headerPairs; } From 4709c99987e62006b7eda2b528b72e0d362362dc Mon Sep 17 00:00:00 2001 From: hsjang Date: Wed, 30 Mar 2022 11:00:30 +0900 Subject: [PATCH 06/13] =?UTF-8?q?feat:=20FirstController,=20Controller=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/Controller.java | 10 ++++++ src/main/java/controller/FirstController.java | 34 +++++++++++++++++++ src/main/java/webserver/RequestHandler.java | 6 +++- src/main/java/webserver/Response.java | 4 +-- 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 src/main/java/controller/Controller.java create mode 100644 src/main/java/controller/FirstController.java diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java new file mode 100644 index 00000000..79f5d1f0 --- /dev/null +++ b/src/main/java/controller/Controller.java @@ -0,0 +1,10 @@ +package controller; + +import webserver.Request; +import webserver.Response; + +public interface Controller { + + void process(Request request, Response response); + +} diff --git a/src/main/java/controller/FirstController.java b/src/main/java/controller/FirstController.java new file mode 100644 index 00000000..e0ebd8ed --- /dev/null +++ b/src/main/java/controller/FirstController.java @@ -0,0 +1,34 @@ +package controller; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import webserver.ControllerMapper; +import webserver.HttpMethod; +import webserver.Request; +import webserver.Response; + +public class FirstController { + + //todo + // map 으로 controllermapper, 컨트롤러 매칭 (컨트롤러들을 넣겠다 put) + // 매칭된 컨트롤러 찾아서(get) 실행 + + private static final FirstController instance = new FirstController(); + + private final Map map = new ConcurrentHashMap<>(); + + private FirstController() { + map.put(new ControllerMapper(HttpMethod.GET, "/index.html"), HomeController.getInstance()); + } + + public void run(Request request, Response response) { + Controller controller = map.get(new ControllerMapper(request.getHttpMethod(), request.getPath())); + controller.process(request, response); + response.responseBody(); + } + + public static FirstController getInstance() { + return instance; + } + +} diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java index 2c535740..c1999c9f 100644 --- a/src/main/java/webserver/RequestHandler.java +++ b/src/main/java/webserver/RequestHandler.java @@ -1,5 +1,6 @@ package webserver; +import controller.FirstController; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -27,7 +28,10 @@ public void run() { request.readRequest(); Response response = new Response(out, request); - response.writeResponse(); +// response.writeResponse(); + + FirstController firstController = FirstController.getInstance(); + firstController.run(request, response); PrintUtils.printRequestHeaders(request.getHeaderPairs(), request.getRequestLine()); diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index e9073717..72a8e3bd 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -116,7 +116,7 @@ private void logoutHeader(String redirectURL) { } } - private void response200Header() { + public void response200Header() { try { dos.writeBytes("HTTP/1.1 200 OK \r\n"); dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); @@ -127,7 +127,7 @@ private void response200Header() { } } - private void responseBody() { + public void responseBody() { try { dos.write(body, 0, body.length); dos.flush(); From e8c75ef8395069d3afe5b550918111f0e6eb9423 Mon Sep 17 00:00:00 2001 From: hsjang Date: Wed, 30 Mar 2022 11:17:24 +0900 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20GET=20index.html=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8A=94=20HomeControll?= =?UTF-8?q?er=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/Controller.java | 3 ++- src/main/java/controller/FirstController.java | 4 +-- src/main/java/controller/HomeController.java | 27 +++++++++++++++++++ src/main/java/webserver/Response.java | 22 ++++++++++++++- 4 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/main/java/controller/HomeController.java diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java index 79f5d1f0..0949a38d 100644 --- a/src/main/java/controller/Controller.java +++ b/src/main/java/controller/Controller.java @@ -1,10 +1,11 @@ package controller; +import java.io.IOException; import webserver.Request; import webserver.Response; public interface Controller { - void process(Request request, Response response); + void process(Request request, Response response) throws IOException; } diff --git a/src/main/java/controller/FirstController.java b/src/main/java/controller/FirstController.java index e0ebd8ed..2af850d4 100644 --- a/src/main/java/controller/FirstController.java +++ b/src/main/java/controller/FirstController.java @@ -1,5 +1,6 @@ package controller; +import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import webserver.ControllerMapper; @@ -21,10 +22,9 @@ private FirstController() { map.put(new ControllerMapper(HttpMethod.GET, "/index.html"), HomeController.getInstance()); } - public void run(Request request, Response response) { + public void run(Request request, Response response) throws IOException { Controller controller = map.get(new ControllerMapper(request.getHttpMethod(), request.getPath())); controller.process(request, response); - response.responseBody(); } public static FirstController getInstance() { diff --git a/src/main/java/controller/HomeController.java b/src/main/java/controller/HomeController.java new file mode 100644 index 00000000..9c244668 --- /dev/null +++ b/src/main/java/controller/HomeController.java @@ -0,0 +1,27 @@ +package controller; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import webserver.Request; +import webserver.Response; + +public class HomeController implements Controller { + + private static final HomeController instance = new HomeController(); + + private HomeController() { + } + + public static HomeController getInstance() { + return instance; + } + + @Override + public void process(Request request, Response response) throws IOException { + byte[] body = Files.readAllBytes(new File("./webapp" + request.getPath()).toPath()); + response.response200Header(body); + response.responseBody(body); + } + +} diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index 72a8e3bd..34486099 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -116,9 +116,29 @@ private void logoutHeader(String redirectURL) { } } + public void response200Header(byte[] body) { + try { + dos.writeBytes("HTTP/1.1 200 OK\r\n"); + dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); + dos.writeBytes("Content-Length: " + body.length + "\r\n"); + dos.writeBytes("\r\n"); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + + public void responseBody(byte[] body) { + try { + dos.write(body, 0, body.length); + dos.flush(); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + public void response200Header() { try { - dos.writeBytes("HTTP/1.1 200 OK \r\n"); + dos.writeBytes("HTTP/1.1 200 OK\r\n"); dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); dos.writeBytes("Content-Length: " + body.length + "\r\n"); dos.writeBytes("\r\n"); From 29556df9e62f4b543be8a2417691c389044a7060 Mon Sep 17 00:00:00 2001 From: nathan29849 Date: Wed, 30 Mar 2022 11:54:27 +0900 Subject: [PATCH 08/13] =?UTF-8?q?feat:=20UserJoinController=EB=A1=9C=20POS?= =?UTF-8?q?T=20/user/create=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 +++++-- src/main/java/controller/FirstController.java | 5 +- .../java/controller/UserJoinController.java | 48 +++++++++++++++++++ src/main/java/webserver/Response.java | 13 +++++ 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 src/main/java/controller/UserJoinController.java diff --git a/README.md b/README.md index 5858786b..a4d77370 100644 --- a/README.md +++ b/README.md @@ -82,8 +82,19 @@ - response body가 없어도 되는 상태 코드(302, 304, 204) - 로그아웃 방법(Cookie 생명주기 설정, session의 역할 ~ store(Map)) - Post -> Redirect -> Get -- [Set-Cookie] HTTP/1.1 vs. HTTP/2 : 세미콜론(;)으로 결합이 가능한지 아닌지 -- [Set-Cookie] 작성 순서 -- [Set-Cookie] Path value default는 없는건가? +- [Set-Cookie] HTTP/1.1 vs. HTTP/2 : 세미콜론(;)으로 결합이 가능한지 아닌지 ... 아닌 것 같음 +- [Set-Cookie] 작성 순서(중요한 것 같음) +- [Set-Cookie] Path value default는 없는건가? (Path는 필수인듯?) - 참고 : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie - 참고2: https://stackoverflow.com/questions/16305814/are-multiple-cookie-headers-allowed-in-an-http-request + +//TODO +- Refactoring + - Response (Controller 역할 중이라 분리를 해야함) | 각자 생각해오면 좋을듯 + - Response - responseXXXHeader 메서드 줄일 수 있는 방안 생각해보기 +- wheejuni Review 생각하기 + +> nathan : 일급컬렉션 사용, 컨트롤러의 개념 차용 +> (루이 조는 Controller를 인터페이스로 구현하여 행동 양식을 지정함) +> (쿠킴 조는 Controller를 추상메서드로 구현함) + diff --git a/src/main/java/controller/FirstController.java b/src/main/java/controller/FirstController.java index 2af850d4..9a007ce9 100644 --- a/src/main/java/controller/FirstController.java +++ b/src/main/java/controller/FirstController.java @@ -19,11 +19,14 @@ public class FirstController { private final Map map = new ConcurrentHashMap<>(); private FirstController() { - map.put(new ControllerMapper(HttpMethod.GET, "/index.html"), HomeController.getInstance()); + map.put(new ControllerMapper(HttpMethod.POST, "/user/create"), UserJoinController.getInstance()); } public void run(Request request, Response response) throws IOException { Controller controller = map.get(new ControllerMapper(request.getHttpMethod(), request.getPath())); + if (controller == null) { + controller = HomeController.getInstance(); + } controller.process(request, response); } diff --git a/src/main/java/controller/UserJoinController.java b/src/main/java/controller/UserJoinController.java new file mode 100644 index 00000000..a6855604 --- /dev/null +++ b/src/main/java/controller/UserJoinController.java @@ -0,0 +1,48 @@ +package controller; + +import db.DataBase; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Map; +import model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import webserver.Request; +import webserver.Response; + +public class UserJoinController implements Controller { + + private static final UserJoinController instance = new UserJoinController(); + + private Logger log = LoggerFactory.getLogger(UserJoinController.class); + + private UserJoinController() { + } + + public static UserJoinController getInstance() { + return instance; + } + + @Override + public void process(Request request, Response response) throws IOException { + Map parsedBody = request.takeParsedBody(); + log.debug("POST BODY: {}", parsedBody); + User user = new User( + parsedBody.get("userId"), + parsedBody.get("password"), + parsedBody.get("name"), + parsedBody.get("email") + ); + saveUser(user, response); + } + + private void saveUser(User user, Response response) { + if (DataBase.validateDuplicatedId(user)) { + DataBase.addUser(user); + response.newResponse302("http://localhost:8080/index.html"); + return; + } + response.newResponse302("http://localhost:8080/user/form.html"); + } +} diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index 34486099..e254a775 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -90,6 +90,19 @@ private void response302Header(String redirectURL) { } } + + public void newResponse302(String redirectURL) { + try { + dos.writeBytes("HTTP/1.1 302 Found\r\n"); + dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); + dos.writeBytes("Location: " + redirectURL + "\r\n"); + dos.writeBytes("\r\n"); + dos.flush(); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + private void response302Header(String redirectURL, String userId) { try { dos.writeBytes("HTTP/1.1 302 Found\r\n"); From 139a5fb55a635acdd54a96513ff98cdf89fd5c98 Mon Sep 17 00:00:00 2001 From: hsjang Date: Wed, 30 Mar 2022 12:06:01 +0900 Subject: [PATCH 09/13] =?UTF-8?q?feat:=20login,=20logout=20Controller=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/FirstController.java | 2 + .../java/controller/UserLoginController.java | 38 +++++++++++++++++++ .../java/controller/UserLogoutController.java | 23 +++++++++++ src/main/java/webserver/Response.java | 16 +++++++- 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/main/java/controller/UserLoginController.java create mode 100644 src/main/java/controller/UserLogoutController.java diff --git a/src/main/java/controller/FirstController.java b/src/main/java/controller/FirstController.java index 9a007ce9..a8db3be2 100644 --- a/src/main/java/controller/FirstController.java +++ b/src/main/java/controller/FirstController.java @@ -20,6 +20,8 @@ public class FirstController { private FirstController() { map.put(new ControllerMapper(HttpMethod.POST, "/user/create"), UserJoinController.getInstance()); + map.put(new ControllerMapper(HttpMethod.GET, "/user/logout"), UserLogoutController.getInstance()); + map.put(new ControllerMapper(HttpMethod.POST, "/user/login"), UserLoginController.getInstance()); } public void run(Request request, Response response) throws IOException { diff --git a/src/main/java/controller/UserLoginController.java b/src/main/java/controller/UserLoginController.java new file mode 100644 index 00000000..b2808d72 --- /dev/null +++ b/src/main/java/controller/UserLoginController.java @@ -0,0 +1,38 @@ +package controller; + +import db.DataBase; +import java.util.Map; +import model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import webserver.Request; +import webserver.Response; + +public class UserLoginController implements Controller { + + private static final UserLoginController instance = new UserLoginController(); + + private Logger log = LoggerFactory.getLogger(UserLoginController.class); + + private UserLoginController() { + } + + public static UserLoginController getInstance() { + return instance; + } + + @Override + public void process(Request request, Response response) { + Map parsedBody = request.takeParsedBody(); + log.debug("POST BODY: {}", parsedBody); + + User user = DataBase.findUserById(parsedBody.get("userId")); + + if (user != null && user.getPassword().equals(parsedBody.get("password"))) { + response.newResponse302("http://localhost:8080/index.html", user.getUserId()); + return; + } + response.newResponse302("http://localhost:8080/user/login_failed.html"); + } + +} diff --git a/src/main/java/controller/UserLogoutController.java b/src/main/java/controller/UserLogoutController.java new file mode 100644 index 00000000..ead68bc1 --- /dev/null +++ b/src/main/java/controller/UserLogoutController.java @@ -0,0 +1,23 @@ +package controller; + +import java.io.IOException; +import webserver.Request; +import webserver.Response; + +public class UserLogoutController implements Controller { + + private static final UserLogoutController instance = new UserLogoutController(); + + private UserLogoutController() { + } + + public static UserLogoutController getInstance() { + return instance; + } + + @Override + public void process(Request request, Response response) { + response.logoutHeader("http://localhost:8080/index.html"); + } + +} diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index e254a775..ea06d200 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -103,6 +103,19 @@ public void newResponse302(String redirectURL) { } } + public void newResponse302(String redirectURL, String userId) { + try { + dos.writeBytes("HTTP/1.1 302 Found\r\n"); + dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); + dos.writeBytes("Content-Length: " + body.length + "\r\n"); + dos.writeBytes("Location: " + redirectURL + "\r\n"); + dos.writeBytes("Set-Cookie: sessionId=" + userId + "; max-age=20; Path=/; HttpOnly\r\n"); + dos.writeBytes("\r\n"); + } catch (IOException e) { + log.error(e.getMessage()); + } + } + private void response302Header(String redirectURL, String userId) { try { dos.writeBytes("HTTP/1.1 302 Found\r\n"); @@ -116,7 +129,7 @@ private void response302Header(String redirectURL, String userId) { } } - private void logoutHeader(String redirectURL) { + public void logoutHeader(String redirectURL) { try { dos.writeBytes("HTTP/1.1 302 Found\r\n"); dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); @@ -124,6 +137,7 @@ private void logoutHeader(String redirectURL) { dos.writeBytes("Location: " + redirectURL + "\r\n"); dos.writeBytes("Set-Cookie: sessionId=; max-age=-1; Path=/\r\n"); dos.writeBytes("\r\n"); + dos.flush(); } catch (IOException e) { log.error(e.getMessage()); } From 7fe704cf4599bb8035baa48279217dcf4b13d55e Mon Sep 17 00:00:00 2001 From: nathan29849 Date: Wed, 30 Mar 2022 14:56:45 +0900 Subject: [PATCH 10/13] =?UTF-8?q?refactor:=20Response=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EB=B2=94=EC=9A=A9=EC=A0=81=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=84=A4=EA=B3=84=20=EB=B0=8F=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/HomeController.java | 5 +- .../java/controller/UserJoinController.java | 11 +- .../java/controller/UserLoginController.java | 13 +- .../java/controller/UserLogoutController.java | 10 +- src/main/java/util/HttpRequestUtils.java | 59 ------- src/main/java/util/IOUtils.java | 1 - src/main/java/util/Pair.java | 61 +++++++ src/main/java/util/PrintUtils.java | 1 - src/main/java/webserver/HttpStatus.java | 23 +++ src/main/java/webserver/Request.java | 2 +- src/main/java/webserver/RequestHandler.java | 2 +- src/main/java/webserver/Response.java | 160 ++---------------- 12 files changed, 126 insertions(+), 222 deletions(-) create mode 100644 src/main/java/util/Pair.java create mode 100644 src/main/java/webserver/HttpStatus.java diff --git a/src/main/java/controller/HomeController.java b/src/main/java/controller/HomeController.java index 9c244668..19b6b64f 100644 --- a/src/main/java/controller/HomeController.java +++ b/src/main/java/controller/HomeController.java @@ -3,6 +3,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; +import webserver.HttpStatus; import webserver.Request; import webserver.Response; @@ -20,8 +21,6 @@ public static HomeController getInstance() { @Override public void process(Request request, Response response) throws IOException { byte[] body = Files.readAllBytes(new File("./webapp" + request.getPath()).toPath()); - response.response200Header(body); - response.responseBody(body); + response.write(body, HttpStatus.OK); } - } diff --git a/src/main/java/controller/UserJoinController.java b/src/main/java/controller/UserJoinController.java index a6855604..dd53e041 100644 --- a/src/main/java/controller/UserJoinController.java +++ b/src/main/java/controller/UserJoinController.java @@ -4,10 +4,14 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import model.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import util.Pair; +import webserver.HttpStatus; import webserver.Request; import webserver.Response; @@ -38,11 +42,14 @@ public void process(Request request, Response response) throws IOException { } private void saveUser(User user, Response response) { + List pairs = new ArrayList<>(); if (DataBase.validateDuplicatedId(user)) { DataBase.addUser(user); - response.newResponse302("http://localhost:8080/index.html"); + pairs.add(new Pair("Location", "http://localhost:8080/index.html")); + response.write(HttpStatus.FOUND, pairs); return; } - response.newResponse302("http://localhost:8080/user/form.html"); + pairs.add(new Pair("Location", "http://localhost:8080/user/form.html")); + response.write(HttpStatus.FOUND, pairs); } } diff --git a/src/main/java/controller/UserLoginController.java b/src/main/java/controller/UserLoginController.java index b2808d72..6cb578a0 100644 --- a/src/main/java/controller/UserLoginController.java +++ b/src/main/java/controller/UserLoginController.java @@ -1,10 +1,14 @@ package controller; import db.DataBase; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import model.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import util.Pair; +import webserver.HttpStatus; import webserver.Request; import webserver.Response; @@ -27,12 +31,17 @@ public void process(Request request, Response response) { log.debug("POST BODY: {}", parsedBody); User user = DataBase.findUserById(parsedBody.get("userId")); + List pairs = new ArrayList<>(); if (user != null && user.getPassword().equals(parsedBody.get("password"))) { - response.newResponse302("http://localhost:8080/index.html", user.getUserId()); + pairs.add(new Pair("Location", "http://localhost:8080/index.html")); + pairs.add(new Pair("Set-Cookie", "sessionId=" + user.getUserId() + "; max-age=20; Path=/; HttpOnly")); + response.write(HttpStatus.FOUND, pairs); return; } - response.newResponse302("http://localhost:8080/user/login_failed.html"); + pairs.add(new Pair("Location", "http://localhost:8080/user/login_failed.html")); + response.write(HttpStatus.FOUND, pairs); } + } diff --git a/src/main/java/controller/UserLogoutController.java b/src/main/java/controller/UserLogoutController.java index ead68bc1..c1fb17c1 100644 --- a/src/main/java/controller/UserLogoutController.java +++ b/src/main/java/controller/UserLogoutController.java @@ -1,6 +1,9 @@ package controller; -import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import util.Pair; +import webserver.HttpStatus; import webserver.Request; import webserver.Response; @@ -17,7 +20,10 @@ public static UserLogoutController getInstance() { @Override public void process(Request request, Response response) { - response.logoutHeader("http://localhost:8080/index.html"); + List pairs = new ArrayList<>(); + pairs.add(new Pair("Location", "http://localhost:8080/index.html")); + pairs.add(new Pair("Set-Cookie", "sessionId=; max-age=-1; Path=/")); + response.write(HttpStatus.FOUND, pairs); } } diff --git a/src/main/java/util/HttpRequestUtils.java b/src/main/java/util/HttpRequestUtils.java index 731966fe..e884e2bf 100644 --- a/src/main/java/util/HttpRequestUtils.java +++ b/src/main/java/util/HttpRequestUtils.java @@ -53,63 +53,4 @@ static Pair getKeyValue(String keyValue, String regex) { public static Pair parseHeader(String header) { return getKeyValue(header, ": "); } - - public static class Pair { - private final String key; - private final String value; - - Pair(String key, String value) { - this.key = key.trim(); - this.value = value.trim(); - } - - public String getKey() { - return key; - } - - public String getValue() { - return value; - } - - public boolean isContentLength() { - return key.equals("Content-Length"); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((key == null) ? 0 : key.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Pair other = (Pair) obj; - if (key == null) { - if (other.key != null) - return false; - } else if (!key.equals(other.key)) - return false; - if (value == null) { - if (other.value != null) - return false; - } else if (!value.equals(other.value)) - return false; - return true; - } - - @Override - public String toString() { - return key + ": " + value; -// return "Pair [key=" + key + ", value=" + value + "]"; - } - } } diff --git a/src/main/java/util/IOUtils.java b/src/main/java/util/IOUtils.java index ed39b930..0cf4268b 100644 --- a/src/main/java/util/IOUtils.java +++ b/src/main/java/util/IOUtils.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import util.HttpRequestUtils.Pair; public class IOUtils { /** diff --git a/src/main/java/util/Pair.java b/src/main/java/util/Pair.java new file mode 100644 index 00000000..33a25d66 --- /dev/null +++ b/src/main/java/util/Pair.java @@ -0,0 +1,61 @@ +package util; + +public class Pair { + private final String key; + private final String value; + + public Pair(String key, String value) { + this.key = key.trim(); + this.value = value.trim(); + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } + + public boolean isContentLength() { + return key.equals("Content-Length"); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key == null) ? 0 : key.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Pair other = (Pair) obj; + if (key == null) { + if (other.key != null) + return false; + } else if (!key.equals(other.key)) + return false; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } + + @Override + public String toString() { + return key + ": " + value; + } +} + + diff --git a/src/main/java/util/PrintUtils.java b/src/main/java/util/PrintUtils.java index 7b2fd0fd..1422fefe 100644 --- a/src/main/java/util/PrintUtils.java +++ b/src/main/java/util/PrintUtils.java @@ -1,7 +1,6 @@ package util; import java.util.List; -import util.HttpRequestUtils.Pair; public class PrintUtils { diff --git a/src/main/java/webserver/HttpStatus.java b/src/main/java/webserver/HttpStatus.java new file mode 100644 index 00000000..beac8871 --- /dev/null +++ b/src/main/java/webserver/HttpStatus.java @@ -0,0 +1,23 @@ +package webserver; + +public enum HttpStatus { + + OK(200, "200 OK"), + FOUND(302, "302 Found"); + + private int status; + private String message; + + HttpStatus(int status, String message) { + this.status = status; + this.message = message; + } + + public int getStatus() { + return status; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/webserver/Request.java b/src/main/java/webserver/Request.java index aa088c55..cf4eb044 100644 --- a/src/main/java/webserver/Request.java +++ b/src/main/java/webserver/Request.java @@ -12,7 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import util.HttpRequestUtils; -import util.HttpRequestUtils.Pair; +import util.Pair; import util.IOUtils; public class Request { diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java index c1999c9f..d8a50970 100644 --- a/src/main/java/webserver/RequestHandler.java +++ b/src/main/java/webserver/RequestHandler.java @@ -27,7 +27,7 @@ public void run() { Request request = new Request(in); request.readRequest(); - Response response = new Response(out, request); + Response response = new Response(out); // response.writeResponse(); FirstController firstController = FirstController.getInstance(); diff --git a/src/main/java/webserver/Response.java b/src/main/java/webserver/Response.java index ea06d200..8787027a 100644 --- a/src/main/java/webserver/Response.java +++ b/src/main/java/webserver/Response.java @@ -1,161 +1,28 @@ package webserver; -import db.DataBase; import java.io.DataOutputStream; -import java.io.File; import java.io.IOException; import java.io.OutputStream; -import java.nio.file.Files; -import java.util.Map; -import model.User; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import util.Pair; public class Response { private Logger log = LoggerFactory.getLogger(Response.class); - private byte[] body = new byte[0]; private DataOutputStream dos; - private Request request; - public Response(OutputStream out, Request request) { + public Response(OutputStream out) { this.dos = new DataOutputStream(out); - this.request = request; } - public void writeResponse() throws IOException { - log.debug("requestLine: {}", request.getRequestLine()); - if (HttpMethod.isGet(request) && request.getPath().equals("/user/logout")) { - logoutHeader("http://localhost:8080/index.html"); - responseBody(); - return; - } - - if (HttpMethod.isPost(request) && request.getPath().equals("/user/create")) { - - Map parsedBody = request.takeParsedBody(); - log.debug("POST BODY: {}", parsedBody); - User user = new User( - parsedBody.get("userId"), - parsedBody.get("password"), - parsedBody.get("name"), - parsedBody.get("email") - ); - saveUser(user); - return; - } - - if (HttpMethod.isPost(request) && request.getPath().equals("/user/login")) { - Map parsedBody = request.takeParsedBody(); - log.debug("POST BODY: {}", parsedBody); - - User user = DataBase.findUserById(parsedBody.get("userId")); - - if (user != null && user.getPassword().equals(parsedBody.get("password"))) { - response302Header("http://localhost:8080/index.html", user.getUserId()); - responseBody(); - return; - } - response302Header("http://localhost:8080/user/login_failed.html"); - responseBody(); - return; - } - - //GET 일 때 - this.body = Files.readAllBytes(new File("./webapp" + request.getPath()).toPath()); - response200Header(); - responseBody(); - } - - private void saveUser(User user) { - if (DataBase.validateDuplicatedId(user)) { - DataBase.addUser(user); - response302Header("http://localhost:8080/index.html"); - responseBody(); - return; - } - response302Header("http://localhost:8080/user/form.html"); - responseBody(); - } - - private void response302Header(String redirectURL) { - try { - dos.writeBytes("HTTP/1.1 302 Found\r\n"); - dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); - dos.writeBytes("Content-Length: " + body.length + "\r\n"); - dos.writeBytes("Location: " + redirectURL + "\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - - - public void newResponse302(String redirectURL) { - try { - dos.writeBytes("HTTP/1.1 302 Found\r\n"); - dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); - dos.writeBytes("Location: " + redirectURL + "\r\n"); - dos.writeBytes("\r\n"); - dos.flush(); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - - public void newResponse302(String redirectURL, String userId) { - try { - dos.writeBytes("HTTP/1.1 302 Found\r\n"); - dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); - dos.writeBytes("Content-Length: " + body.length + "\r\n"); - dos.writeBytes("Location: " + redirectURL + "\r\n"); - dos.writeBytes("Set-Cookie: sessionId=" + userId + "; max-age=20; Path=/; HttpOnly\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - - private void response302Header(String redirectURL, String userId) { - try { - dos.writeBytes("HTTP/1.1 302 Found\r\n"); - dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); - dos.writeBytes("Content-Length: " + body.length + "\r\n"); - dos.writeBytes("Location: " + redirectURL + "\r\n"); - dos.writeBytes("Set-Cookie: sessionId=" + userId + "; max-age=20; Path=/; HttpOnly\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - - public void logoutHeader(String redirectURL) { + public void write(byte[] body, HttpStatus httpStatus) { try { - dos.writeBytes("HTTP/1.1 302 Found\r\n"); + dos.writeBytes("HTTP/1.1 " + httpStatus.getMessage() + "\r\n"); dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); dos.writeBytes("Content-Length: " + body.length + "\r\n"); - dos.writeBytes("Location: " + redirectURL + "\r\n"); - dos.writeBytes("Set-Cookie: sessionId=; max-age=-1; Path=/\r\n"); dos.writeBytes("\r\n"); - dos.flush(); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - - public void response200Header(byte[] body) { - try { - dos.writeBytes("HTTP/1.1 200 OK\r\n"); - dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); - dos.writeBytes("Content-Length: " + body.length + "\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - - public void responseBody(byte[] body) { - try { dos.write(body, 0, body.length); dos.flush(); } catch (IOException e) { @@ -163,24 +30,17 @@ public void responseBody(byte[] body) { } } - public void response200Header() { + public void write(HttpStatus httpStatus, List pairs) { try { - dos.writeBytes("HTTP/1.1 200 OK\r\n"); + dos.writeBytes("HTTP/1.1 " + httpStatus.getMessage() + "\r\n"); dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n"); - dos.writeBytes("Content-Length: " + body.length + "\r\n"); + for (Pair pair : pairs) { + dos.writeBytes(pair.toString() + "\r\n"); + } dos.writeBytes("\r\n"); - } catch (IOException e) { - log.error(e.getMessage()); - } - } - - public void responseBody() { - try { - dos.write(body, 0, body.length); dos.flush(); } catch (IOException e) { log.error(e.getMessage()); } } - } From 6d28924613e0038a19adc1eb0e7437282ebc8af5 Mon Sep 17 00:00:00 2001 From: hsjang Date: Wed, 30 Mar 2022 15:44:46 +0900 Subject: [PATCH 11/13] =?UTF-8?q?add:=20controller=EC=97=90=20log=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 --- src/main/java/controller/FirstController.java | 8 ++++---- src/main/java/controller/HomeController.java | 4 ++++ src/main/java/controller/UserJoinController.java | 2 ++ src/main/java/controller/UserLoginController.java | 2 ++ src/main/java/controller/UserLogoutController.java | 6 ++++++ src/main/java/util/HttpRequestUtils.java | 4 ---- src/main/java/webserver/ControllerMapper.java | 4 ++-- src/main/java/webserver/HttpMethod.java | 8 -------- src/main/java/webserver/HttpStatus.java | 4 ++-- src/main/java/webserver/Request.java | 13 +------------ src/main/java/webserver/RequestHandler.java | 2 +- 12 files changed, 24 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index a4d77370..01880720 100644 --- a/README.md +++ b/README.md @@ -89,9 +89,6 @@ - 참고2: https://stackoverflow.com/questions/16305814/are-multiple-cookie-headers-allowed-in-an-http-request //TODO -- Refactoring - - Response (Controller 역할 중이라 분리를 해야함) | 각자 생각해오면 좋을듯 - - Response - responseXXXHeader 메서드 줄일 수 있는 방안 생각해보기 - wheejuni Review 생각하기 > nathan : 일급컬렉션 사용, 컨트롤러의 개념 차용 diff --git a/src/main/java/controller/FirstController.java b/src/main/java/controller/FirstController.java index a8db3be2..331d8b80 100644 --- a/src/main/java/controller/FirstController.java +++ b/src/main/java/controller/FirstController.java @@ -3,6 +3,8 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import webserver.ControllerMapper; import webserver.HttpMethod; import webserver.Request; @@ -10,13 +12,10 @@ public class FirstController { - //todo - // map 으로 controllermapper, 컨트롤러 매칭 (컨트롤러들을 넣겠다 put) - // 매칭된 컨트롤러 찾아서(get) 실행 - private static final FirstController instance = new FirstController(); private final Map map = new ConcurrentHashMap<>(); + private Logger log = LoggerFactory.getLogger(FirstController.class); private FirstController() { map.put(new ControllerMapper(HttpMethod.POST, "/user/create"), UserJoinController.getInstance()); @@ -29,6 +28,7 @@ public void run(Request request, Response response) throws IOException { if (controller == null) { controller = HomeController.getInstance(); } + log.debug("call {}", controller); controller.process(request, response); } diff --git a/src/main/java/controller/HomeController.java b/src/main/java/controller/HomeController.java index 19b6b64f..5550a98a 100644 --- a/src/main/java/controller/HomeController.java +++ b/src/main/java/controller/HomeController.java @@ -3,6 +3,8 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import webserver.HttpStatus; import webserver.Request; import webserver.Response; @@ -11,6 +13,7 @@ public class HomeController implements Controller { private static final HomeController instance = new HomeController(); + private Logger log = LoggerFactory.getLogger(HomeController.class); private HomeController() { } @@ -21,6 +24,7 @@ public static HomeController getInstance() { @Override public void process(Request request, Response response) throws IOException { byte[] body = Files.readAllBytes(new File("./webapp" + request.getPath()).toPath()); + log.debug("path: {}", request.getPath()); response.write(body, HttpStatus.OK); } } diff --git a/src/main/java/controller/UserJoinController.java b/src/main/java/controller/UserJoinController.java index dd53e041..79601f06 100644 --- a/src/main/java/controller/UserJoinController.java +++ b/src/main/java/controller/UserJoinController.java @@ -45,10 +45,12 @@ private void saveUser(User user, Response response) { List pairs = new ArrayList<>(); if (DataBase.validateDuplicatedId(user)) { DataBase.addUser(user); + log.debug("SavedUser: {}", user); pairs.add(new Pair("Location", "http://localhost:8080/index.html")); response.write(HttpStatus.FOUND, pairs); return; } + log.debug("Save Fail: {}", user); pairs.add(new Pair("Location", "http://localhost:8080/user/form.html")); response.write(HttpStatus.FOUND, pairs); } diff --git a/src/main/java/controller/UserLoginController.java b/src/main/java/controller/UserLoginController.java index 6cb578a0..7ed20775 100644 --- a/src/main/java/controller/UserLoginController.java +++ b/src/main/java/controller/UserLoginController.java @@ -34,11 +34,13 @@ public void process(Request request, Response response) { List pairs = new ArrayList<>(); if (user != null && user.getPassword().equals(parsedBody.get("password"))) { + log.debug("login 성공"); pairs.add(new Pair("Location", "http://localhost:8080/index.html")); pairs.add(new Pair("Set-Cookie", "sessionId=" + user.getUserId() + "; max-age=20; Path=/; HttpOnly")); response.write(HttpStatus.FOUND, pairs); return; } + log.debug("login 실패"); pairs.add(new Pair("Location", "http://localhost:8080/user/login_failed.html")); response.write(HttpStatus.FOUND, pairs); } diff --git a/src/main/java/controller/UserLogoutController.java b/src/main/java/controller/UserLogoutController.java index c1fb17c1..3225009f 100644 --- a/src/main/java/controller/UserLogoutController.java +++ b/src/main/java/controller/UserLogoutController.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import util.Pair; import webserver.HttpStatus; import webserver.Request; @@ -11,6 +13,8 @@ public class UserLogoutController implements Controller { private static final UserLogoutController instance = new UserLogoutController(); + private Logger log = LoggerFactory.getLogger(UserLogoutController.class); + private UserLogoutController() { } @@ -24,6 +28,8 @@ public void process(Request request, Response response) { pairs.add(new Pair("Location", "http://localhost:8080/index.html")); pairs.add(new Pair("Set-Cookie", "sessionId=; max-age=-1; Path=/")); response.write(HttpStatus.FOUND, pairs); + + log.debug("logout 성공"); } } diff --git a/src/main/java/util/HttpRequestUtils.java b/src/main/java/util/HttpRequestUtils.java index e884e2bf..dd2dae64 100644 --- a/src/main/java/util/HttpRequestUtils.java +++ b/src/main/java/util/HttpRequestUtils.java @@ -5,12 +5,8 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class HttpRequestUtils { - private static final Logger log = LoggerFactory.getLogger(HttpRequestUtils.class); - /** * @param queryString은 URL에서 ? 이후에 전달되는 field1=value1&field2=value2 형식임 * @return diff --git a/src/main/java/webserver/ControllerMapper.java b/src/main/java/webserver/ControllerMapper.java index 89dff35f..d1deab9b 100644 --- a/src/main/java/webserver/ControllerMapper.java +++ b/src/main/java/webserver/ControllerMapper.java @@ -4,8 +4,8 @@ public class ControllerMapper { - private HttpMethod httpMethod; - private String path; + private final HttpMethod httpMethod; + private final String path; public ControllerMapper(HttpMethod httpMethod, String path) { this.httpMethod = httpMethod; diff --git a/src/main/java/webserver/HttpMethod.java b/src/main/java/webserver/HttpMethod.java index 6d14baef..65755794 100644 --- a/src/main/java/webserver/HttpMethod.java +++ b/src/main/java/webserver/HttpMethod.java @@ -14,12 +14,4 @@ public static HttpMethod create(String httpMethod) { return null; } - public static boolean isGet(Request request) { - return request.getHttpMethod().equals(GET); - } - - public static boolean isPost(Request request) { - return request.getHttpMethod().equals(POST); - } - } diff --git a/src/main/java/webserver/HttpStatus.java b/src/main/java/webserver/HttpStatus.java index beac8871..e0dcee86 100644 --- a/src/main/java/webserver/HttpStatus.java +++ b/src/main/java/webserver/HttpStatus.java @@ -5,8 +5,8 @@ public enum HttpStatus { OK(200, "200 OK"), FOUND(302, "302 Found"); - private int status; - private String message; + private final int status; + private final String message; HttpStatus(int status, String message) { this.status = status; diff --git a/src/main/java/webserver/Request.java b/src/main/java/webserver/Request.java index cf4eb044..cbdf65f9 100644 --- a/src/main/java/webserver/Request.java +++ b/src/main/java/webserver/Request.java @@ -9,28 +9,22 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import util.HttpRequestUtils; -import util.Pair; import util.IOUtils; +import util.Pair; public class Request { - private Logger log = LoggerFactory.getLogger(Request.class); - private static final int HTTP_METHOD = 0; private static final int REQUEST_TARGET = 1; private static final int PATH = 0; private static final int QUERY_STRING = 1; private final BufferedReader br; - private String requestLine; private String[] parsedRequestLine; private HttpMethod httpMethod; private String path; - private ControllerMapper controllerMapper; private List headerPairs; private Map parsedQueryString; private String requestBody; @@ -51,7 +45,6 @@ private void extractRequestLine(BufferedReader br) throws IOException { this.parsedRequestLine = requestLine.split(" "); this.httpMethod = HttpMethod.create(parsedRequestLine[HTTP_METHOD]); this.path = parseRequestURL()[PATH]; - this.controllerMapper = new ControllerMapper(httpMethod, path); this.parsedQueryString = takeParsedQueryString(); } @@ -87,10 +80,6 @@ public HttpMethod getHttpMethod() { return httpMethod; } - public ControllerMapper getControllerMapper() { - return controllerMapper; - } - public List getHeaderPairs() { return headerPairs; } diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java index d8a50970..2052f6ec 100644 --- a/src/main/java/webserver/RequestHandler.java +++ b/src/main/java/webserver/RequestHandler.java @@ -18,6 +18,7 @@ public RequestHandler(Socket connectionSocket) { this.connection = connectionSocket; } + @Override public void run() { log.debug("New Client Connect! Connected IP : {}, Port : {}", connection.getInetAddress(), connection.getPort()); @@ -28,7 +29,6 @@ public void run() { request.readRequest(); Response response = new Response(out); -// response.writeResponse(); FirstController firstController = FirstController.getInstance(); firstController.run(request, response); From db2daee47e43c7f899d78e5389fb84c7932255a6 Mon Sep 17 00:00:00 2001 From: hsjang Date: Wed, 30 Mar 2022 16:09:31 +0900 Subject: [PATCH 12/13] =?UTF-8?q?feat:=20sessionId=20uuid=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/UserLoginController.java | 3 +- src/main/java/db/DataBase.java | 5 ++- src/main/java/webserver/HttpSession.java | 31 +++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/main/java/webserver/HttpSession.java diff --git a/src/main/java/controller/UserLoginController.java b/src/main/java/controller/UserLoginController.java index 7ed20775..2b2707cc 100644 --- a/src/main/java/controller/UserLoginController.java +++ b/src/main/java/controller/UserLoginController.java @@ -8,6 +8,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import util.Pair; +import webserver.HttpSession; import webserver.HttpStatus; import webserver.Request; import webserver.Response; @@ -36,7 +37,7 @@ public void process(Request request, Response response) { if (user != null && user.getPassword().equals(parsedBody.get("password"))) { log.debug("login 성공"); pairs.add(new Pair("Location", "http://localhost:8080/index.html")); - pairs.add(new Pair("Set-Cookie", "sessionId=" + user.getUserId() + "; max-age=20; Path=/; HttpOnly")); + pairs.add(new Pair("Set-Cookie", "sessionId=" + HttpSession.makeUUID(user.getUserId()) + "; max-age=20; Path=/; HttpOnly")); response.write(HttpStatus.FOUND, pairs); return; } diff --git a/src/main/java/db/DataBase.java b/src/main/java/db/DataBase.java index 956b489b..433bfeae 100644 --- a/src/main/java/db/DataBase.java +++ b/src/main/java/db/DataBase.java @@ -1,14 +1,13 @@ package db; import java.util.Collection; +import java.util.HashMap; import java.util.Map; -import com.google.common.collect.Maps; - import model.User; public class DataBase { - private static Map users = Maps.newHashMap(); + private static Map users = new HashMap<>(); public static void addUser(User user) { users.put(user.getUserId(), user); diff --git a/src/main/java/webserver/HttpSession.java b/src/main/java/webserver/HttpSession.java new file mode 100644 index 00000000..baa68b9f --- /dev/null +++ b/src/main/java/webserver/HttpSession.java @@ -0,0 +1,31 @@ +package webserver; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HttpSession { + + // UUID, userId + private static Map session = new HashMap<>(); + + private static Logger log = LoggerFactory.getLogger(HttpSession.class); + + public static String makeUUID(String userId) { + String uuid = UUID.randomUUID().toString(); + session.put(uuid, userId); + log.debug("uuid, userId: {}, {}", uuid, userId); + return uuid; + } + + public static String checkUser(String uuid) { + return session.get(uuid); + } + + public static void logout(String uuid) { + session.remove(uuid); + } + +} From 3798a828ae2168c4c69f20df8b327a4ce638b504 Mon Sep 17 00:00:00 2001 From: hsjang Date: Wed, 30 Mar 2022 16:14:19 +0900 Subject: [PATCH 13/13] =?UTF-8?q?docs:=204=EB=8B=A8=EA=B3=84=20README=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 01880720..63984420 100644 --- a/README.md +++ b/README.md @@ -79,19 +79,12 @@ ## Step4 : 웹서버 4단계 - 쿠키를 이용한 로그인 구현 - 302, 304 차이 -- response body가 없어도 되는 상태 코드(302, 304, 204) -- 로그아웃 방법(Cookie 생명주기 설정, session의 역할 ~ store(Map)) -- Post -> Redirect -> Get + - 302는 리다이렉트, 304는 Not Modified로 브라우저의 캐시를 사용하므로 절대 response body를 넣으면 안된다. +- response body가 없어도 되는 상태 코드는 302, 304, 204 등이 있다. - [Set-Cookie] HTTP/1.1 vs. HTTP/2 : 세미콜론(;)으로 결합이 가능한지 아닌지 ... 아닌 것 같음 -- [Set-Cookie] 작성 순서(중요한 것 같음) -- [Set-Cookie] Path value default는 없는건가? (Path는 필수인듯?) +- [Set-Cookie] 작성 순서(cookie-name=cookie-value; 옵션들(max-age, path, domain 등등)) +- [Set-Cookie] Path value default 있음 (/user/create -> /user가 기본 값) +- [Set-Cookie] Path를 set-Cookie 했을 때와 동일한 Path 값을 설정해야 정상적인 로그아웃이 가능함 - 참고 : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie - 참고2: https://stackoverflow.com/questions/16305814/are-multiple-cookie-headers-allowed-in-an-http-request -//TODO -- wheejuni Review 생각하기 - -> nathan : 일급컬렉션 사용, 컨트롤러의 개념 차용 -> (루이 조는 Controller를 인터페이스로 구현하여 행동 양식을 지정함) -> (쿠킴 조는 Controller를 추상메서드로 구현함) -