From 7d43eb02330af7d43db3bfcfcee5199052788073 Mon Sep 17 00:00:00 2001 From: kisusu Date: Tue, 1 Oct 2024 23:18:29 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=201=EC=B0=A8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/Controller.java | 9 ++ .../java/controller/ForwardController.java | 15 +++ src/main/java/controller/HomeController.java | 15 +++ src/main/java/controller/ListController.java | 24 ++++ src/main/java/controller/LoginController.java | 47 ++++++++ .../java/controller/SignUpController.java | 49 ++++++++ src/main/java/db/MemoryUserRepository.java | 1 + .../enums/exception/ExceptionMessage.java | 15 +++ .../java/enums/extension/FileExtension.java | 19 ++++ src/main/java/enums/http/HttpMethod.java | 16 +++ src/main/java/enums/http/HttpStatus.java | 16 +++ .../java/enums/http/header/EntityHeader.java | 20 ++++ .../java/enums/http/header/RequestHeader.java | 15 +++ .../enums/http/header/ResponseHeader.java | 20 ++++ src/main/java/enums/key/UserQueryKey.java | 18 +++ src/main/java/enums/route/PageRoute.java | 18 +++ src/main/java/enums/route/StaticRoute.java | 18 +++ src/main/java/http/HttpRequest.java | 105 ++++++++++++++++++ src/main/java/http/HttpResponse.java | 80 +++++++++++++ src/main/java/model/User.java | 6 +- src/main/java/webserver/RequestHandler.java | 73 ++++++++---- src/test/java/http/HttpRequestTest.java | 95 ++++++++++++++++ src/test/java/http/HttpResponseTest.java | 42 +++++++ src/test/java/resource/httpRequestPostExample | 7 ++ src/test/java/resource/outputCheckFile | 4 + 25 files changed, 723 insertions(+), 24 deletions(-) create mode 100644 src/main/java/controller/Controller.java create mode 100644 src/main/java/controller/ForwardController.java create mode 100644 src/main/java/controller/HomeController.java create mode 100644 src/main/java/controller/ListController.java create mode 100644 src/main/java/controller/LoginController.java create mode 100644 src/main/java/controller/SignUpController.java create mode 100644 src/main/java/enums/exception/ExceptionMessage.java create mode 100644 src/main/java/enums/extension/FileExtension.java create mode 100644 src/main/java/enums/http/HttpMethod.java create mode 100644 src/main/java/enums/http/HttpStatus.java create mode 100644 src/main/java/enums/http/header/EntityHeader.java create mode 100644 src/main/java/enums/http/header/RequestHeader.java create mode 100644 src/main/java/enums/http/header/ResponseHeader.java create mode 100644 src/main/java/enums/key/UserQueryKey.java create mode 100644 src/main/java/enums/route/PageRoute.java create mode 100644 src/main/java/enums/route/StaticRoute.java create mode 100644 src/main/java/http/HttpRequest.java create mode 100644 src/main/java/http/HttpResponse.java create mode 100644 src/test/java/http/HttpRequestTest.java create mode 100644 src/test/java/http/HttpResponseTest.java create mode 100644 src/test/java/resource/httpRequestPostExample create mode 100644 src/test/java/resource/outputCheckFile diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java new file mode 100644 index 0000000..826f9a9 --- /dev/null +++ b/src/main/java/controller/Controller.java @@ -0,0 +1,9 @@ +package controller; + +import java.io.IOException; +import http.HttpRequest; +import http.HttpResponse; + +public interface Controller { + public void execute(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException; +} diff --git a/src/main/java/controller/ForwardController.java b/src/main/java/controller/ForwardController.java new file mode 100644 index 0000000..8b10dd3 --- /dev/null +++ b/src/main/java/controller/ForwardController.java @@ -0,0 +1,15 @@ +package controller; + +import java.io.IOException; +import http.HttpRequest; +import http.HttpResponse; + +// url이 html로 들어오면 200으로 body에 html 파일 보내주기 +public class ForwardController implements Controller{ + + @Override + public void execute(HttpRequest httpRequest, HttpResponse httpResponse) throws IOException { + String path = httpRequest.getUrl(); + httpResponse.forward(path); + } +} diff --git a/src/main/java/controller/HomeController.java b/src/main/java/controller/HomeController.java new file mode 100644 index 0000000..565c1e9 --- /dev/null +++ b/src/main/java/controller/HomeController.java @@ -0,0 +1,15 @@ +package controller; + +import enums.route.StaticRoute; +import http.HttpRequest; +import http.HttpResponse; + +// url이 "/"로 들어오면 302로 /index.html로 redirect, 페이지 반환은 재요청 받으면 200이 반환 +public class HomeController implements Controller{ + + @Override + public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { + String location = StaticRoute.INDEX_HTML.getRoute(); + httpResponse.redirect(location); + } +} diff --git a/src/main/java/controller/ListController.java b/src/main/java/controller/ListController.java new file mode 100644 index 0000000..343c9ef --- /dev/null +++ b/src/main/java/controller/ListController.java @@ -0,0 +1,24 @@ +package controller; + +import enums.http.header.RequestHeader; +import http.HttpRequest; +import http.HttpResponse; + +import static enums.route.StaticRoute.*; + +public class ListController implements Controller { + @Override + public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { + + String cookie = httpRequest.getHeader().get(RequestHeader.COOKIE.getValue()); + + if (cookie != null && cookie.contains("logined=true")) { + String location = USER_LIST_HTML.getRoute(); + httpResponse.redirect(location); + } + else{ + String location = LOGIN_HTML.getRoute(); + httpResponse.redirect(location); + } + } +} diff --git a/src/main/java/controller/LoginController.java b/src/main/java/controller/LoginController.java new file mode 100644 index 0000000..d5f3106 --- /dev/null +++ b/src/main/java/controller/LoginController.java @@ -0,0 +1,47 @@ +package controller; + +import db.Repository; +import http.HttpRequest; +import http.HttpResponse; +import model.User; + +import static enums.http.HttpMethod.POST; +import static enums.key.UserQueryKey.PASSWORD; +import static enums.key.UserQueryKey.USERID; +import static enums.route.StaticRoute.*; + +public class LoginController implements Controller{ + Repository repository; + + public LoginController(Repository repository) { + this.repository = repository; + } + + @Override + public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { + boolean isLoginSuccessed = false; + + // if (httpRequest.getHttpMethod().equals("GET")){ } // 일단 POST 방식으로 전송되니까 보류 + + if (httpRequest.getHttpMethod().equals(POST.getValue())) { + String userId = httpRequest.getBody().get(USERID.getValue()); + String password = httpRequest.getBody().get(PASSWORD.getValue()); + + User user = repository.findUserById(userId); + if(user != null){ + if(user.getPassword().equals(password)){ + isLoginSuccessed = true; + } + } + } + + if(isLoginSuccessed){ + String location = INDEX_HTML.getRoute(); + httpResponse.redirectSettingCookie(location); + } + if(!isLoginSuccessed){ + String location = LOGIN_FAILED_HTML.getRoute(); + httpResponse.redirect(location); + } + } +} diff --git a/src/main/java/controller/SignUpController.java b/src/main/java/controller/SignUpController.java new file mode 100644 index 0000000..c7d588b --- /dev/null +++ b/src/main/java/controller/SignUpController.java @@ -0,0 +1,49 @@ +package controller; + +import db.Repository; +import http.HttpRequest; +import http.HttpResponse; +import model.User; + +import java.util.Map; + +import static enums.http.HttpMethod.GET; +import static enums.http.HttpMethod.POST; +import static enums.key.UserQueryKey.*; +import static enums.route.StaticRoute.*; + +public class SignUpController implements Controller{ + Repository repository; + + public SignUpController(Repository repository) { + this.repository = repository; + } + + @Override + public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { + + if (httpRequest.getHttpMethod().equals(GET.getValue())){ + Map queryMap = httpRequest.getQueryMap(); + User user = makeUserFromMap(queryMap); + repository.addUser(user); + } + + // todo : application/x-www-form-urlencoded로 전달되는 값 decode??? >> URLDecoder + if (httpRequest.getHttpMethod().equals(POST.getValue())) { + Map bodyMap = httpRequest.getBody(); + User user = makeUserFromMap(bodyMap); + repository.addUser(user); + } + + String location = INDEX_HTML.getRoute(); + httpResponse.redirect(location); + } + + private User makeUserFromMap(Map map){ + String userId = map.get(USERID.getValue()); + String password = map.get(PASSWORD.getValue()); + String name = map.get(NAME.getValue()); + String email = map.get(EMAIL.getValue()); + return User.of(userId, password, name, email); + } +} diff --git a/src/main/java/db/MemoryUserRepository.java b/src/main/java/db/MemoryUserRepository.java index e8181ae..2903526 100644 --- a/src/main/java/db/MemoryUserRepository.java +++ b/src/main/java/db/MemoryUserRepository.java @@ -23,6 +23,7 @@ public static MemoryUserRepository getInstance() { public void addUser(User user) { users.put(user.getUserId(), user); + System.out.println(user.getUserId()+"님 이 회원가입 하였습니다."); } public User findUserById(String userId) { diff --git a/src/main/java/enums/exception/ExceptionMessage.java b/src/main/java/enums/exception/ExceptionMessage.java new file mode 100644 index 0000000..1ba215c --- /dev/null +++ b/src/main/java/enums/exception/ExceptionMessage.java @@ -0,0 +1,15 @@ +package enums.exception; + +public enum ExceptionMessage { + INVALID_STARTLINE("요청의 1번째 줄이 비어있습니다."); + + private final String message; + + ExceptionMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/enums/extension/FileExtension.java b/src/main/java/enums/extension/FileExtension.java new file mode 100644 index 0000000..82a3879 --- /dev/null +++ b/src/main/java/enums/extension/FileExtension.java @@ -0,0 +1,19 @@ +package enums.extension; + +public enum FileExtension { + HTML("html"), CSS("css"); + + private final String value; + + FileExtension(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public String addFrontPoint() { + return "."+value; + } +} diff --git a/src/main/java/enums/http/HttpMethod.java b/src/main/java/enums/http/HttpMethod.java new file mode 100644 index 0000000..83f855f --- /dev/null +++ b/src/main/java/enums/http/HttpMethod.java @@ -0,0 +1,16 @@ +package enums.http; + +public enum HttpMethod { + GET("GET"), + POST("POST"); + + private final String value; + + HttpMethod(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/enums/http/HttpStatus.java b/src/main/java/enums/http/HttpStatus.java new file mode 100644 index 0000000..a9691ea --- /dev/null +++ b/src/main/java/enums/http/HttpStatus.java @@ -0,0 +1,16 @@ +package enums.http; + +public enum HttpStatus { + OK("HTTP/1.1 200 OK \r\n"), + REDIRECT("HTTP/1.1 302 Found \r\n"); + + private final String value; + + HttpStatus(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/enums/http/header/EntityHeader.java b/src/main/java/enums/http/header/EntityHeader.java new file mode 100644 index 0000000..86682f3 --- /dev/null +++ b/src/main/java/enums/http/header/EntityHeader.java @@ -0,0 +1,20 @@ +package enums.http.header; + +public enum EntityHeader { + CONTENTTYPE("Content-Type"), + CONTENTLENGTH("Content-Length"); + + private final String value; + + EntityHeader(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public String toResponseString() { + return value + ": "; + } +} diff --git a/src/main/java/enums/http/header/RequestHeader.java b/src/main/java/enums/http/header/RequestHeader.java new file mode 100644 index 0000000..1d80f9b --- /dev/null +++ b/src/main/java/enums/http/header/RequestHeader.java @@ -0,0 +1,15 @@ +package enums.http.header; + +public enum RequestHeader { + COOKIE("Cookie"); + + private final String value; + + RequestHeader(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/enums/http/header/ResponseHeader.java b/src/main/java/enums/http/header/ResponseHeader.java new file mode 100644 index 0000000..e09fc86 --- /dev/null +++ b/src/main/java/enums/http/header/ResponseHeader.java @@ -0,0 +1,20 @@ +package enums.http.header; + +public enum ResponseHeader { + LOCATION("Location"), + SETCOOKIE("Set-Cookie"); + + private final String value; + + ResponseHeader(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public String toResponseString() { + return value + ": "; + } +} diff --git a/src/main/java/enums/key/UserQueryKey.java b/src/main/java/enums/key/UserQueryKey.java new file mode 100644 index 0000000..49bd12a --- /dev/null +++ b/src/main/java/enums/key/UserQueryKey.java @@ -0,0 +1,18 @@ +package enums.key; + +public enum UserQueryKey { + USERID("userId"), + PASSWORD("password"), + NAME("name"), + EMAIL("email"); + + private final String value; + + UserQueryKey(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/enums/route/PageRoute.java b/src/main/java/enums/route/PageRoute.java new file mode 100644 index 0000000..d304437 --- /dev/null +++ b/src/main/java/enums/route/PageRoute.java @@ -0,0 +1,18 @@ +package enums.route; + +public enum PageRoute { + HOME("/"), + SIGNUP("/user/signup"), + LOGIN("/user/login"), + USER_LIST("/user/userList"); + + private final String route; + + PageRoute(String route) { + this.route = route; + } + + public String getRoute() { + return route; + } +} diff --git a/src/main/java/enums/route/StaticRoute.java b/src/main/java/enums/route/StaticRoute.java new file mode 100644 index 0000000..c978c6b --- /dev/null +++ b/src/main/java/enums/route/StaticRoute.java @@ -0,0 +1,18 @@ +package enums.route; + +public enum StaticRoute { + INDEX_HTML("/index.html"), + LOGIN_HTML("/user/login.html"), + LOGIN_FAILED_HTML("/user/login_failed.html"), + USER_LIST_HTML("/user/list.html"); + + private final String route; + + StaticRoute(String route) { + this.route = route; + } + + public String getRoute() { + return route; + } +} diff --git a/src/main/java/http/HttpRequest.java b/src/main/java/http/HttpRequest.java new file mode 100644 index 0000000..64c45ae --- /dev/null +++ b/src/main/java/http/HttpRequest.java @@ -0,0 +1,105 @@ +package http; + +import enums.exception.ExceptionMessage; +import http.util.HttpRequestUtils; +import http.util.IOUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static enums.http.header.EntityHeader.*; + +public class HttpRequest { + private String startLine; + private Map header; + private Map body; + + public HttpRequest(String startLine, + Map header, + Map body) + { + this.startLine = startLine; + this.header = header; + this.body = body; + } + + public static HttpRequest from(BufferedReader br) throws IOException { + // startLine + String startLine = br.readLine(); + if (startLine == null || startLine.isEmpty()) { + throw new IOException(ExceptionMessage.INVALID_STARTLINE.getMessage()); + } + + // header + Map headerMap = new HashMap<>(); + String line; + while ((line = br.readLine()) != null) { + if (line.isEmpty()) break; + String[] headerParts = line.split(": "); + if (headerParts.length == 2) { + headerMap.put(headerParts[0], headerParts[1]); + } + } + + int contentLength = 0; + String rawContentLength = headerMap.get(CONTENTLENGTH.getValue()); + if(rawContentLength != null) contentLength= Integer.parseInt(rawContentLength); + + // message body 추출, 나중에 POST 할 때 Map 형식으로 변환 + String rawMessageBody = ""; + if (contentLength > 0) { + rawMessageBody = IOUtils.readData(br, contentLength); + } + Map bodyMap = extractBodyParameters(rawMessageBody); + + return new HttpRequest(startLine, headerMap, bodyMap); + } + + private static Map extractBodyParameters(String rawMessageBody) { + if (rawMessageBody.isEmpty()) return new HashMap<>(); + return HttpRequestUtils.parseQueryParameter(rawMessageBody); + } + + public String getHttpMethod() { + return startLine.split(" ")[0]; + } + + public String getUrl() { + String rawUrl = startLine.split(" ")[1]; + return extractUrl(rawUrl); + } + + public Map getQueryMap() { + String rawUrl = startLine.split(" ")[1]; + return extractQueryParameters(rawUrl); + } + + private String extractUrl(String rawUrl) { + int questionMarkIndex = rawUrl.indexOf('?'); + String url = questionMarkIndex != -1 ? rawUrl.substring(0, questionMarkIndex) : rawUrl; + + if (url.endsWith("/")) url = url.substring(0, url.length() - 1); + if (!url.startsWith("/")) url = "/" + url; + + return url; + } + + private Map extractQueryParameters(String rawUrl) { + int questionMarkIndex = rawUrl.indexOf('?'); + if (questionMarkIndex == -1) { + return new HashMap<>(); + } + String queryString = rawUrl.substring(questionMarkIndex + 1); + return HttpRequestUtils.parseQueryParameter(queryString); + } + + public Map getHeader() { + return header; + } + + public Map getBody() { + return body; + } +} diff --git a/src/main/java/http/HttpResponse.java b/src/main/java/http/HttpResponse.java new file mode 100644 index 0000000..4505d99 --- /dev/null +++ b/src/main/java/http/HttpResponse.java @@ -0,0 +1,80 @@ +package http; + +import enums.http.HttpStatus; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static enums.extension.FileExtension.CSS; +import static enums.extension.FileExtension.HTML; +import static enums.http.header.EntityHeader.CONTENTLENGTH; +import static enums.http.header.EntityHeader.CONTENTTYPE; +import static enums.http.header.ResponseHeader.LOCATION; +import static enums.http.header.ResponseHeader.SETCOOKIE; + +public class HttpResponse { + private static final Logger log = Logger.getLogger(HttpResponse.class.getName()); + private DataOutputStream dos; + + public HttpResponse(DataOutputStream dos) { + this.dos = dos; + } + + public void forward(String path) throws IOException { + String relativePath = "webapp"+path; + byte[] body = Files.readAllBytes(Paths.get(relativePath)); + + if(path.endsWith(HTML.addFrontPoint())){ + sendHeader(dos, HTML.getValue(), body.length); + } + if(path.endsWith(CSS.addFrontPoint())){ + sendHeader(dos, CSS.getValue(), body.length); + } + sendBody(dos, body); + } + + public void redirect(String location){ + try { + dos.writeBytes(HttpStatus.REDIRECT.getValue()); + dos.writeBytes(LOCATION.toResponseString() + location + "\r\n"); + dos.writeBytes("\r\n"); + } catch (IOException e) { + log.log(Level.SEVERE, e.getMessage()); + } + } + + public void redirectSettingCookie(String location){ + try { + dos.writeBytes(HttpStatus.REDIRECT.getValue()); + dos.writeBytes(SETCOOKIE.toResponseString()+ "logined=true" + "\r\n"); + dos.writeBytes(LOCATION.toResponseString() + location + "\r\n"); + dos.writeBytes("\r\n"); + } catch (IOException e) { + log.log(Level.SEVERE, e.getMessage()); + } + } + + private void sendHeader(DataOutputStream dos, String extension, int lengthOfBodyContent) { + try { + dos.writeBytes(HttpStatus.OK.getValue()); + dos.writeBytes(CONTENTTYPE.toResponseString() + "text/" + extension + ";charset=utf-8\r\n"); + dos.writeBytes(CONTENTLENGTH.toResponseString() + lengthOfBodyContent + "\r\n"); + dos.writeBytes("\r\n"); + } catch (IOException e) { + log.log(Level.SEVERE, e.getMessage()); + } + } + + private void sendBody(DataOutputStream dos, byte[] body) { + try { + dos.write(body, 0, body.length); + dos.flush(); + } catch (IOException e) { + log.log(Level.SEVERE, e.getMessage()); + } + } +} diff --git a/src/main/java/model/User.java b/src/main/java/model/User.java index 680c0cd..a2e9470 100644 --- a/src/main/java/model/User.java +++ b/src/main/java/model/User.java @@ -8,13 +8,17 @@ public class User { private String name; private String email; - public User(String userId, String password, String name, String email) { + private User(String userId, String password, String name, String email) { this.userId = userId; this.password = password; this.name = name; this.email = email; } + public static User of(String userId, String password, String name, String email){ + return new User(userId, password, name, email); + } + public String getUserId() { return userId; } diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java index f87ac24..0872214 100644 --- a/src/main/java/webserver/RequestHandler.java +++ b/src/main/java/webserver/RequestHandler.java @@ -1,16 +1,30 @@ package webserver; +import controller.*; +import db.MemoryUserRepository; +import db.Repository; +import enums.route.PageRoute; +import http.HttpRequest; +import http.HttpResponse; + import java.io.*; import java.net.Socket; import java.util.logging.Level; import java.util.logging.Logger; +import static enums.http.HttpMethod.GET; +import static enums.extension.FileExtension.*; + public class RequestHandler implements Runnable{ Socket connection; private static final Logger log = Logger.getLogger(RequestHandler.class.getName()); + private final Repository repository; + private Controller controller = new ForwardController(); + public RequestHandler(Socket connection) { this.connection = connection; + repository = MemoryUserRepository.getInstance(); } @Override @@ -20,33 +34,46 @@ public void run() { BufferedReader br = new BufferedReader(new InputStreamReader(in)); DataOutputStream dos = new DataOutputStream(out); - byte[] body = "Hello World".getBytes(); - response200Header(dos, body.length); - responseBody(dos, body); + HttpRequest httpRequest = HttpRequest.from(br); + HttpResponse httpResponse = new HttpResponse(dos); - } catch (IOException e) { - log.log(Level.SEVERE,e.getMessage()); - } - } + String requestMethod = httpRequest.getHttpMethod(); + String requestUrl = httpRequest.getUrl(); - private void response200Header(DataOutputStream dos, int lengthOfBodyContent) { - 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: " + lengthOfBodyContent + "\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { - log.log(Level.SEVERE, e.getMessage()); - } - } + // 요구 사항 1번 + if (requestMethod.equals(GET.getValue()) && requestUrl.endsWith(HTML.addFrontPoint())) { + controller = new ForwardController(); + } + + // 요구 사항 7번 + if(requestMethod.equals(GET.getValue()) && requestUrl.endsWith(CSS.addFrontPoint())) { + controller = new ForwardController(); + } + + if (requestUrl.equals(PageRoute.HOME.getRoute())) { + controller = new HomeController(); + } + + // 요구 사항 2,3,4번 + if (requestUrl.equals(PageRoute.SIGNUP.getRoute())) { + controller = new SignUpController(repository); + } + + // 요구 사항 5번 + if (requestUrl.equals(PageRoute.LOGIN.getRoute())) { + controller = new LoginController(repository); + } + + // 요구 사항 6번 + if (requestUrl.equals(PageRoute.USER_LIST.getRoute())) { + controller = new ListController(); + } + + controller.execute(httpRequest, httpResponse); - private void responseBody(DataOutputStream dos, byte[] body) { - try { - dos.write(body, 0, body.length); - dos.flush(); } catch (IOException e) { - log.log(Level.SEVERE, e.getMessage()); + // 예외 처리할 때 400 응답 뱉어야 될 것 같은데.. 헷갈리네 + log.log(Level.SEVERE,e.getMessage()); } } - } diff --git a/src/test/java/http/HttpRequestTest.java b/src/test/java/http/HttpRequestTest.java new file mode 100644 index 0000000..eb0c0db --- /dev/null +++ b/src/test/java/http/HttpRequestTest.java @@ -0,0 +1,95 @@ +package http; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HttpRequestTest { + HttpRequest httpRequest; + + @BeforeEach + void setHttpRequestFromFile() throws IOException { + String filePath = "src/test/java/resource/httpRequestPostExample"; + BufferedReader br = new BufferedReader(new FileReader(filePath)); + + httpRequest = HttpRequest.from(br); + } + + @Test + void getHttpMethod() { + //when + String actualMethod = httpRequest.getHttpMethod(); + + //given + String expectedMethod = "POST"; + + //then + assertEquals(actualMethod, expectedMethod); + } + + @Test + void getUrl() { + //when + String actualUrl = httpRequest.getUrl(); + + //given + String expectedUrl = "/user/test"; + + //then + assertEquals(actualUrl, expectedUrl); + } + + @Test + void getQueryMap() { + //when + Map actualQueryMap = httpRequest.getQueryMap(); + + //given + Map expectedQueryMap = Map.of( + "userId", "query_id", + "password", "query_password" + ); + + //then + assertEquals(actualQueryMap, expectedQueryMap); + } + + @Test + void getHeader() { + //when + Map actualHeaderMap = httpRequest.getHeader(); + + //given + Map expectedHeaderMap = Map.of( + "Host", "localhost:80", + "Connection", "keep-alive", + "Content-Length", "52", + "Accept", "*/*" + ); + + //then + assertEquals(actualHeaderMap, expectedHeaderMap); + } + + @Test + void getBody() { + //when + Map actualBodyMap = httpRequest.getBody(); + + //given + Map expectedBodyMap = Map.of( + "userId", "body_id", + "password", "body_password", + "name", "body_name" + ); + + //then + assertEquals(actualBodyMap, expectedBodyMap); + } +} \ No newline at end of file diff --git a/src/test/java/http/HttpResponseTest.java b/src/test/java/http/HttpResponseTest.java new file mode 100644 index 0000000..8f32ae9 --- /dev/null +++ b/src/test/java/http/HttpResponseTest.java @@ -0,0 +1,42 @@ +package http; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +import static enums.route.StaticRoute.*; + +class HttpResponseTest { + + HttpResponse httpResponse; + + @BeforeEach + void setResponseFile() throws IOException { + String testFilePath = "src/test/java/resource/outputCheckFile"; + httpResponse = new HttpResponse(new DataOutputStream(outputStreamToFile(testFilePath))); + } + + private OutputStream outputStreamToFile(String path) throws IOException { + return Files.newOutputStream(Paths.get(path)); + } + + @Test + void forwardTest() throws IOException { + httpResponse.forward(USER_LIST_HTML.getRoute()); + } + + @Test + void redirectTest() { + httpResponse.redirect(LOGIN_HTML.getRoute()); + } + + @Test + void redirectSettingCookieTest() { + httpResponse.redirectSettingCookie(INDEX_HTML.getRoute()); + } +} \ No newline at end of file diff --git a/src/test/java/resource/httpRequestPostExample b/src/test/java/resource/httpRequestPostExample new file mode 100644 index 0000000..8ab55ce --- /dev/null +++ b/src/test/java/resource/httpRequestPostExample @@ -0,0 +1,7 @@ +POST /user/test?userId=query_id&password=query_password HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Content-Length: 52 +Accept: */* + +userId=body_id&password=body_password&name=body_name diff --git a/src/test/java/resource/outputCheckFile b/src/test/java/resource/outputCheckFile new file mode 100644 index 0000000..b159180 --- /dev/null +++ b/src/test/java/resource/outputCheckFile @@ -0,0 +1,4 @@ +HTTP/1.1 302 Found +Set-Cookie: logined=true +Location: /index.html + From fa4ebd1acc218819fc339f7fe14f804a065d3c65 Mon Sep 17 00:00:00 2001 From: kisusu Date: Wed, 2 Oct 2024 14:16:01 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20RequestMapper=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/LoginController.java | 7 +- .../java/controller/SignUpController.java | 7 +- .../enums/exception/ExceptionMessage.java | 3 +- src/main/java/http/HttpRequest.java | 2 +- src/main/java/webserver/RequestHandler.java | 36 +------ src/main/java/webserver/RequestMapper.java | 58 +++++++++++ .../resource/webserver/httpRequestForwardCss | 4 + .../resource/webserver/httpRequestForwardHtml | 4 + .../java/resource/webserver/httpRequestHome | 4 + .../webserver/httpRequestListNoCookie | 4 + .../webserver/httpRequestListWithCookie | 5 + .../java/resource/webserver/httpRequestLogin | 7 ++ .../java/resource/webserver/httpRequestSignUp | 7 ++ .../java/webserver/RequestMapperTest.java | 99 +++++++++++++++++++ 14 files changed, 202 insertions(+), 45 deletions(-) create mode 100644 src/main/java/webserver/RequestMapper.java create mode 100644 src/test/java/resource/webserver/httpRequestForwardCss create mode 100644 src/test/java/resource/webserver/httpRequestForwardHtml create mode 100644 src/test/java/resource/webserver/httpRequestHome create mode 100644 src/test/java/resource/webserver/httpRequestListNoCookie create mode 100644 src/test/java/resource/webserver/httpRequestListWithCookie create mode 100644 src/test/java/resource/webserver/httpRequestLogin create mode 100644 src/test/java/resource/webserver/httpRequestSignUp create mode 100644 src/test/java/webserver/RequestMapperTest.java diff --git a/src/main/java/controller/LoginController.java b/src/main/java/controller/LoginController.java index d5f3106..18b70a0 100644 --- a/src/main/java/controller/LoginController.java +++ b/src/main/java/controller/LoginController.java @@ -1,5 +1,6 @@ package controller; +import db.MemoryUserRepository; import db.Repository; import http.HttpRequest; import http.HttpResponse; @@ -11,11 +12,7 @@ import static enums.route.StaticRoute.*; public class LoginController implements Controller{ - Repository repository; - - public LoginController(Repository repository) { - this.repository = repository; - } + Repository repository = MemoryUserRepository.getInstance(); @Override public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { diff --git a/src/main/java/controller/SignUpController.java b/src/main/java/controller/SignUpController.java index c7d588b..3ce9cfa 100644 --- a/src/main/java/controller/SignUpController.java +++ b/src/main/java/controller/SignUpController.java @@ -1,5 +1,6 @@ package controller; +import db.MemoryUserRepository; import db.Repository; import http.HttpRequest; import http.HttpResponse; @@ -13,11 +14,7 @@ import static enums.route.StaticRoute.*; public class SignUpController implements Controller{ - Repository repository; - - public SignUpController(Repository repository) { - this.repository = repository; - } + Repository repository = MemoryUserRepository.getInstance(); @Override public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { diff --git a/src/main/java/enums/exception/ExceptionMessage.java b/src/main/java/enums/exception/ExceptionMessage.java index 1ba215c..520d421 100644 --- a/src/main/java/enums/exception/ExceptionMessage.java +++ b/src/main/java/enums/exception/ExceptionMessage.java @@ -1,7 +1,8 @@ package enums.exception; public enum ExceptionMessage { - INVALID_STARTLINE("요청의 1번째 줄이 비어있습니다."); + INVALID_START_LINE("요청의 1번째 줄이 비어있습니다."), + INVALID_REQUEST_URL("요청의 URL이 유효하지 않습니다."); private final String message; diff --git a/src/main/java/http/HttpRequest.java b/src/main/java/http/HttpRequest.java index 64c45ae..074de42 100644 --- a/src/main/java/http/HttpRequest.java +++ b/src/main/java/http/HttpRequest.java @@ -29,7 +29,7 @@ public static HttpRequest from(BufferedReader br) throws IOException { // startLine String startLine = br.readLine(); if (startLine == null || startLine.isEmpty()) { - throw new IOException(ExceptionMessage.INVALID_STARTLINE.getMessage()); + throw new IOException(ExceptionMessage.INVALID_START_LINE.getMessage()); } // header diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java index 0872214..ed7a36f 100644 --- a/src/main/java/webserver/RequestHandler.java +++ b/src/main/java/webserver/RequestHandler.java @@ -31,45 +31,15 @@ public RequestHandler(Socket connection) { public void run() { log.log(Level.INFO, "New Client Connect! Connected IP : " + connection.getInetAddress() + ", Port : " + connection.getPort()); try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()){ + BufferedReader br = new BufferedReader(new InputStreamReader(in)); DataOutputStream dos = new DataOutputStream(out); HttpRequest httpRequest = HttpRequest.from(br); HttpResponse httpResponse = new HttpResponse(dos); - String requestMethod = httpRequest.getHttpMethod(); - String requestUrl = httpRequest.getUrl(); - - // 요구 사항 1번 - if (requestMethod.equals(GET.getValue()) && requestUrl.endsWith(HTML.addFrontPoint())) { - controller = new ForwardController(); - } - - // 요구 사항 7번 - if(requestMethod.equals(GET.getValue()) && requestUrl.endsWith(CSS.addFrontPoint())) { - controller = new ForwardController(); - } - - if (requestUrl.equals(PageRoute.HOME.getRoute())) { - controller = new HomeController(); - } - - // 요구 사항 2,3,4번 - if (requestUrl.equals(PageRoute.SIGNUP.getRoute())) { - controller = new SignUpController(repository); - } - - // 요구 사항 5번 - if (requestUrl.equals(PageRoute.LOGIN.getRoute())) { - controller = new LoginController(repository); - } - - // 요구 사항 6번 - if (requestUrl.equals(PageRoute.USER_LIST.getRoute())) { - controller = new ListController(); - } - - controller.execute(httpRequest, httpResponse); + RequestMapper requestMapper = RequestMapper.from(httpRequest,httpResponse); + requestMapper.proceed(); } catch (IOException e) { // 예외 처리할 때 400 응답 뱉어야 될 것 같은데.. 헷갈리네 diff --git a/src/main/java/webserver/RequestMapper.java b/src/main/java/webserver/RequestMapper.java new file mode 100644 index 0000000..99c827a --- /dev/null +++ b/src/main/java/webserver/RequestMapper.java @@ -0,0 +1,58 @@ +package webserver; + +import controller.*; +import enums.route.PageRoute; +import http.HttpRequest; +import http.HttpResponse; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static enums.exception.ExceptionMessage.INVALID_REQUEST_URL; +import static enums.extension.FileExtension.CSS; +import static enums.extension.FileExtension.HTML; +import static enums.http.HttpMethod.GET; + +public class RequestMapper { + Controller controller; + HttpRequest httpRequest; + HttpResponse httpResponse; + + private RequestMapper(Controller controller, HttpRequest httpRequest, HttpResponse httpResponse) { + this.controller = controller; + this.httpRequest = httpRequest; + this.httpResponse = httpResponse; + } + + public static RequestMapper from(HttpRequest httpRequest, HttpResponse httpResponse){ + String requestMethod = httpRequest.getHttpMethod(); + String requestUrl = httpRequest.getUrl(); + + if (requestMethod.equals(GET.getValue()) && requestUrl.endsWith(HTML.addFrontPoint()) || requestUrl.endsWith(CSS.addFrontPoint())) { + Controller controller = new ForwardController(); + return new RequestMapper(controller, httpRequest, httpResponse); + } + + Map controllers = setControllerMap(); + Controller controller = controllers.get(requestUrl); + + if(controller == null) throw new IllegalArgumentException(INVALID_REQUEST_URL.getMessage()); + return new RequestMapper(controller, httpRequest, httpResponse); + } + + private static Map setControllerMap(){ + Map controllers = new HashMap(); + + controllers.put(PageRoute.HOME.getRoute(), new HomeController()); + controllers.put(PageRoute.SIGNUP.getRoute(), new SignUpController()); + controllers.put(PageRoute.LOGIN.getRoute(), new LoginController()); + controllers.put(PageRoute.USER_LIST.getRoute(), new ListController()); + + return controllers; + } + + public void proceed() throws IOException { + controller.execute(httpRequest, httpResponse); + } +} diff --git a/src/test/java/resource/webserver/httpRequestForwardCss b/src/test/java/resource/webserver/httpRequestForwardCss new file mode 100644 index 0000000..f95bd32 --- /dev/null +++ b/src/test/java/resource/webserver/httpRequestForwardCss @@ -0,0 +1,4 @@ +GET /css/styles.css HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Accept: */* diff --git a/src/test/java/resource/webserver/httpRequestForwardHtml b/src/test/java/resource/webserver/httpRequestForwardHtml new file mode 100644 index 0000000..43ab6d7 --- /dev/null +++ b/src/test/java/resource/webserver/httpRequestForwardHtml @@ -0,0 +1,4 @@ +GET /index.html HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Accept: */* diff --git a/src/test/java/resource/webserver/httpRequestHome b/src/test/java/resource/webserver/httpRequestHome new file mode 100644 index 0000000..e42fd1e --- /dev/null +++ b/src/test/java/resource/webserver/httpRequestHome @@ -0,0 +1,4 @@ +GET / HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Accept: */* \ No newline at end of file diff --git a/src/test/java/resource/webserver/httpRequestListNoCookie b/src/test/java/resource/webserver/httpRequestListNoCookie new file mode 100644 index 0000000..2a6cd23 --- /dev/null +++ b/src/test/java/resource/webserver/httpRequestListNoCookie @@ -0,0 +1,4 @@ +GET /user/userList HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Accept: */* \ No newline at end of file diff --git a/src/test/java/resource/webserver/httpRequestListWithCookie b/src/test/java/resource/webserver/httpRequestListWithCookie new file mode 100644 index 0000000..f88b63e --- /dev/null +++ b/src/test/java/resource/webserver/httpRequestListWithCookie @@ -0,0 +1,5 @@ +GET /user/userList HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Cookie: logined=true +Accept: */* \ No newline at end of file diff --git a/src/test/java/resource/webserver/httpRequestLogin b/src/test/java/resource/webserver/httpRequestLogin new file mode 100644 index 0000000..4d0ef93 --- /dev/null +++ b/src/test/java/resource/webserver/httpRequestLogin @@ -0,0 +1,7 @@ +POST /user/login HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Content-Length: 37 +Accept: */* + +userId=body_id&password=body_password \ No newline at end of file diff --git a/src/test/java/resource/webserver/httpRequestSignUp b/src/test/java/resource/webserver/httpRequestSignUp new file mode 100644 index 0000000..71b220a --- /dev/null +++ b/src/test/java/resource/webserver/httpRequestSignUp @@ -0,0 +1,7 @@ +POST /user/signup HTTP/1.1 +Host: localhost:80 +Connection: keep-alive +Content-Length: 69 +Accept: */* + +userId=body_id&password=body_password&name=body_name&email=body_email \ No newline at end of file diff --git a/src/test/java/webserver/RequestMapperTest.java b/src/test/java/webserver/RequestMapperTest.java new file mode 100644 index 0000000..280c2d2 --- /dev/null +++ b/src/test/java/webserver/RequestMapperTest.java @@ -0,0 +1,99 @@ +package webserver; + +import http.HttpRequest; +import http.HttpResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; + +import static org.junit.jupiter.api.Assertions.*; + +class RequestMapperTest { + HttpRequest httpRequest; + HttpResponse httpResponse; + + @BeforeEach + void setResponseFile() throws IOException { + String testFilePath = "src/test/java/resource/outputCheckFile"; + httpResponse = new HttpResponse(new DataOutputStream(outputStreamToFile(testFilePath))); + } + + private OutputStream outputStreamToFile(String path) throws IOException { + return Files.newOutputStream(Paths.get(path)); + } + + private RequestMapper setRequestMapperFromFilePath(String filePath) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(filePath)); + + httpRequest = HttpRequest.from(br); + RequestMapper requestMapper = RequestMapper.from(httpRequest, httpResponse); + return requestMapper; + } + + @Test + @DisplayName("ForwardController Case - HTML") + void proceedForwardHtml() throws IOException { + String requestFilePath = "src/test/java/resource/webserver/httpRequestForwardHtml"; + + RequestMapper requestMapper = setRequestMapperFromFilePath(requestFilePath); + requestMapper.proceed(); + } + + @Test + @DisplayName("ForwardController Case - CSS") + void proceedForwardCss() throws IOException { + String requestFilePath = "src/test/java/resource/webserver/httpRequestForwardCss"; + + RequestMapper requestMapper = setRequestMapperFromFilePath(requestFilePath); + requestMapper.proceed(); + } + + @Test + @DisplayName("HomeController Case") + void proceedHome() throws IOException { + String requestFilePath = "src/test/java/resource/webserver/httpRequestHome"; + + RequestMapper requestMapper = setRequestMapperFromFilePath(requestFilePath); + requestMapper.proceed(); + } + + @Test + @DisplayName("ListController Case - With Cookie") + void proceedListCookie() throws IOException { + String requestFilePath = "src/test/java/resource/webserver/httpRequestListWithCookie"; + + RequestMapper requestMapper = setRequestMapperFromFilePath(requestFilePath); + requestMapper.proceed(); + } + + @Test + @DisplayName("ListController Case - No Cookie") + void proceedListFail() throws IOException { + String requestFilePath = "src/test/java/resource/webserver/httpRequestListNoCookie"; + + RequestMapper requestMapper = setRequestMapperFromFilePath(requestFilePath); + requestMapper.proceed(); + } + + @Test + @DisplayName("LoginController Case") + void proceedLogin() throws IOException { + String requestFilePath = "src/test/java/resource/webserver/httpRequestLogin"; + + RequestMapper requestMapper = setRequestMapperFromFilePath(requestFilePath); + requestMapper.proceed(); + } + + @Test + @DisplayName("SignUpController Case") + void proceedSignUp() throws IOException { + String requestFilePath = "src/test/java/resource/webserver/httpRequestSignUp"; + + RequestMapper requestMapper = setRequestMapperFromFilePath(requestFilePath); + requestMapper.proceed(); + } +} \ No newline at end of file From d2f8ceadf78c79aa5326e33486cbcd2ead49e154 Mon Sep 17 00:00:00 2001 From: kisusu Date: Wed, 2 Oct 2024 21:06:51 +0900 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20HttpRequest=20=EC=A0=95?= =?UTF-8?q?=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20from()=EC=97=90=EC=84=9C=EC=9D=98=20=EB=A9=94?= =?UTF-8?q?=EC=86=8C=EB=93=9C=20=EC=B6=94=EC=B6=9C=20=EB=B0=8F=20=ED=95=84?= =?UTF-8?q?=EB=93=9C/=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=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/ListController.java | 10 ++--- src/main/java/controller/LoginController.java | 21 +++++---- .../java/controller/SignUpController.java | 2 +- src/main/java/http/HttpRequest.java | 45 +++++++++++-------- src/test/java/http/HttpRequestTest.java | 4 +- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/main/java/controller/ListController.java b/src/main/java/controller/ListController.java index 343c9ef..69587fd 100644 --- a/src/main/java/controller/ListController.java +++ b/src/main/java/controller/ListController.java @@ -10,15 +10,15 @@ public class ListController implements Controller { @Override public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { - String cookie = httpRequest.getHeader().get(RequestHeader.COOKIE.getValue()); + String cookie = httpRequest.getHeaderMap().get(RequestHeader.COOKIE.getValue()); if (cookie != null && cookie.contains("logined=true")) { String location = USER_LIST_HTML.getRoute(); httpResponse.redirect(location); + return; } - else{ - String location = LOGIN_HTML.getRoute(); - httpResponse.redirect(location); - } + + String location = LOGIN_HTML.getRoute(); + httpResponse.redirect(location); } } diff --git a/src/main/java/controller/LoginController.java b/src/main/java/controller/LoginController.java index 18b70a0..3dff1ae 100644 --- a/src/main/java/controller/LoginController.java +++ b/src/main/java/controller/LoginController.java @@ -16,20 +16,14 @@ public class LoginController implements Controller{ @Override public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { - boolean isLoginSuccessed = false; + boolean isLoginSuccessed = false; // if (httpRequest.getHttpMethod().equals("GET")){ } // 일단 POST 방식으로 전송되니까 보류 - if (httpRequest.getHttpMethod().equals(POST.getValue())) { - String userId = httpRequest.getBody().get(USERID.getValue()); - String password = httpRequest.getBody().get(PASSWORD.getValue()); - - User user = repository.findUserById(userId); - if(user != null){ - if(user.getPassword().equals(password)){ - isLoginSuccessed = true; - } - } + String userId = httpRequest.getBodyMap().get(USERID.getValue()); + String password = httpRequest.getBodyMap().get(PASSWORD.getValue()); + + isLoginSuccessed = checkIdPwValid(userId, password); } if(isLoginSuccessed){ @@ -41,4 +35,9 @@ public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { httpResponse.redirect(location); } } + + private boolean checkIdPwValid(String userId, String password){User user = repository.findUserById(userId); + if(user != null && user.getPassword().equals(password)) return true; + return false; + } } diff --git a/src/main/java/controller/SignUpController.java b/src/main/java/controller/SignUpController.java index 3ce9cfa..6dda920 100644 --- a/src/main/java/controller/SignUpController.java +++ b/src/main/java/controller/SignUpController.java @@ -27,7 +27,7 @@ public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { // todo : application/x-www-form-urlencoded로 전달되는 값 decode??? >> URLDecoder if (httpRequest.getHttpMethod().equals(POST.getValue())) { - Map bodyMap = httpRequest.getBody(); + Map bodyMap = httpRequest.getBodyMap(); User user = makeUserFromMap(bodyMap); repository.addUser(user); } diff --git a/src/main/java/http/HttpRequest.java b/src/main/java/http/HttpRequest.java index 074de42..8d4b07e 100644 --- a/src/main/java/http/HttpRequest.java +++ b/src/main/java/http/HttpRequest.java @@ -13,26 +13,33 @@ public class HttpRequest { private String startLine; - private Map header; - private Map body; + private Map headerMap; + private Map bodyMap; public HttpRequest(String startLine, - Map header, - Map body) - { + Map headerMap, + Map bodyMap) { this.startLine = startLine; - this.header = header; - this.body = body; + this.headerMap = headerMap; + this.bodyMap = bodyMap; } public static HttpRequest from(BufferedReader br) throws IOException { - // startLine + String startLine = extractStartLine(br); + Map headerMap = extractHeaderMap(br); + Map bodyMap = extractBodyMap(br, headerMap); + return new HttpRequest(startLine, headerMap, bodyMap); + } + + private static String extractStartLine(BufferedReader br) throws IOException { String startLine = br.readLine(); if (startLine == null || startLine.isEmpty()) { throw new IOException(ExceptionMessage.INVALID_START_LINE.getMessage()); } + return startLine; + } - // header + private static Map extractHeaderMap(BufferedReader br) throws IOException { Map headerMap = new HashMap<>(); String line; while ((line = br.readLine()) != null) { @@ -42,22 +49,22 @@ public static HttpRequest from(BufferedReader br) throws IOException { headerMap.put(headerParts[0], headerParts[1]); } } + return headerMap; + } + private static Map extractBodyMap(BufferedReader br, Map headerMap) throws IOException { int contentLength = 0; String rawContentLength = headerMap.get(CONTENTLENGTH.getValue()); - if(rawContentLength != null) contentLength= Integer.parseInt(rawContentLength); + if (rawContentLength != null) contentLength = Integer.parseInt(rawContentLength); - // message body 추출, 나중에 POST 할 때 Map 형식으로 변환 String rawMessageBody = ""; if (contentLength > 0) { rawMessageBody = IOUtils.readData(br, contentLength); } - Map bodyMap = extractBodyParameters(rawMessageBody); - - return new HttpRequest(startLine, headerMap, bodyMap); + return buildBodyMapFromMessageBody(rawMessageBody); } - private static Map extractBodyParameters(String rawMessageBody) { + private static Map buildBodyMapFromMessageBody(String rawMessageBody) { if (rawMessageBody.isEmpty()) return new HashMap<>(); return HttpRequestUtils.parseQueryParameter(rawMessageBody); } @@ -95,11 +102,11 @@ private Map extractQueryParameters(String rawUrl) { return HttpRequestUtils.parseQueryParameter(queryString); } - public Map getHeader() { - return header; + public Map getHeaderMap() { + return headerMap; } - public Map getBody() { - return body; + public Map getBodyMap() { + return bodyMap; } } diff --git a/src/test/java/http/HttpRequestTest.java b/src/test/java/http/HttpRequestTest.java index eb0c0db..e6eeb39 100644 --- a/src/test/java/http/HttpRequestTest.java +++ b/src/test/java/http/HttpRequestTest.java @@ -63,7 +63,7 @@ void getQueryMap() { @Test void getHeader() { //when - Map actualHeaderMap = httpRequest.getHeader(); + Map actualHeaderMap = httpRequest.getHeaderMap(); //given Map expectedHeaderMap = Map.of( @@ -80,7 +80,7 @@ void getHeader() { @Test void getBody() { //when - Map actualBodyMap = httpRequest.getBody(); + Map actualBodyMap = httpRequest.getBodyMap(); //given Map expectedBodyMap = Map.of( From 4c2e4513428b859222a45f1c12134a99d40d4ba0 Mon Sep 17 00:00:00 2001 From: kisusu Date: Thu, 3 Oct 2024 22:06:09 +0900 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20RequestStartLine=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=84=A0=EC=96=B8=ED=95=98=EC=97=AC=20sta?= =?UTF-8?q?rtLine=20=EB=B6=84=EB=A6=AC,=20URLDecoder=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=97=AC=20urlencoded=20=EB=90=9C=20=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=EC=97=B4=20decode,=20HttpResponse=EC=97=90=EC=84=9C?= =?UTF-8?q?=20StringBuilder=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=97=AC=20heade?= =?UTF-8?q?r=20=EB=AA=A8=EC=95=84=EC=84=9C=20=EC=A0=84=EC=86=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/LoginController.java | 3 +- .../java/controller/SignUpController.java | 1 - src/main/java/http/HttpRequest.java | 69 ++++++++++-------- src/main/java/http/HttpResponse.java | 73 +++++++++++-------- src/main/java/http/RequestStartLine.java | 31 ++++++++ webapp/user/login.html | 2 +- 6 files changed, 116 insertions(+), 63 deletions(-) create mode 100644 src/main/java/http/RequestStartLine.java diff --git a/src/main/java/controller/LoginController.java b/src/main/java/controller/LoginController.java index 3dff1ae..520d49e 100644 --- a/src/main/java/controller/LoginController.java +++ b/src/main/java/controller/LoginController.java @@ -36,7 +36,8 @@ public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { } } - private boolean checkIdPwValid(String userId, String password){User user = repository.findUserById(userId); + private boolean checkIdPwValid(String userId, String password){ + User user = repository.findUserById(userId); if(user != null && user.getPassword().equals(password)) return true; return false; } diff --git a/src/main/java/controller/SignUpController.java b/src/main/java/controller/SignUpController.java index 6dda920..136a60d 100644 --- a/src/main/java/controller/SignUpController.java +++ b/src/main/java/controller/SignUpController.java @@ -25,7 +25,6 @@ public void execute(HttpRequest httpRequest, HttpResponse httpResponse) { repository.addUser(user); } - // todo : application/x-www-form-urlencoded로 전달되는 값 decode??? >> URLDecoder if (httpRequest.getHttpMethod().equals(POST.getValue())) { Map bodyMap = httpRequest.getBodyMap(); User user = makeUserFromMap(bodyMap); diff --git a/src/main/java/http/HttpRequest.java b/src/main/java/http/HttpRequest.java index 8d4b07e..9a7a78c 100644 --- a/src/main/java/http/HttpRequest.java +++ b/src/main/java/http/HttpRequest.java @@ -6,17 +6,18 @@ import java.io.BufferedReader; import java.io.IOException; +import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; import static enums.http.header.EntityHeader.*; public class HttpRequest { - private String startLine; + private RequestStartLine startLine; private Map headerMap; private Map bodyMap; - public HttpRequest(String startLine, + private HttpRequest(RequestStartLine startLine, Map headerMap, Map bodyMap) { this.startLine = startLine; @@ -25,7 +26,8 @@ public HttpRequest(String startLine, } public static HttpRequest from(BufferedReader br) throws IOException { - String startLine = extractStartLine(br); + String rawStartLine = extractStartLine(br); + RequestStartLine startLine = makeRequestStartLine(rawStartLine); Map headerMap = extractHeaderMap(br); Map bodyMap = extractBodyMap(br, headerMap); return new HttpRequest(startLine, headerMap, bodyMap); @@ -39,6 +41,33 @@ private static String extractStartLine(BufferedReader br) throws IOException { return startLine; } + private static RequestStartLine makeRequestStartLine(String rawStartLine){ + String httpMethod = rawStartLine.split(" ")[0]; + String rawUrl = rawStartLine.split(" ")[1]; + String url = extractUrl(rawUrl); + Map queryMap = extractQueryParameters(rawUrl); + return RequestStartLine.from(httpMethod, url, queryMap); + } + + private static String extractUrl(String rawUrl) { + int questionMarkIndex = rawUrl.indexOf('?'); + String url = questionMarkIndex != -1 ? rawUrl.substring(0, questionMarkIndex) : rawUrl; + + if (url.endsWith("/")) url = url.substring(0, url.length() - 1); + if (!url.startsWith("/")) url = "/" + url; + + return url; + } + + private static Map extractQueryParameters(String rawUrl) { + int questionMarkIndex = rawUrl.indexOf('?'); + if (questionMarkIndex == -1) { + return new HashMap<>(); + } + String queryString = rawUrl.substring(questionMarkIndex + 1); + return HttpRequestUtils.parseQueryParameter(queryString); + } + private static Map extractHeaderMap(BufferedReader br) throws IOException { Map headerMap = new HashMap<>(); String line; @@ -57,11 +86,12 @@ private static Map extractBodyMap(BufferedReader br, Map 0) { - rawMessageBody = IOUtils.readData(br, contentLength); + String rawMessageBody = IOUtils.readData(br, contentLength); + decodedMessageBody = URLDecoder.decode(rawMessageBody, "UTF-8"); } - return buildBodyMapFromMessageBody(rawMessageBody); + return buildBodyMapFromMessageBody(decodedMessageBody); } private static Map buildBodyMapFromMessageBody(String rawMessageBody) { @@ -70,36 +100,15 @@ private static Map buildBodyMapFromMessageBody(String rawMessage } public String getHttpMethod() { - return startLine.split(" ")[0]; + return startLine.getHttpMethod(); } public String getUrl() { - String rawUrl = startLine.split(" ")[1]; - return extractUrl(rawUrl); + return startLine.getUrl(); } public Map getQueryMap() { - String rawUrl = startLine.split(" ")[1]; - return extractQueryParameters(rawUrl); - } - - private String extractUrl(String rawUrl) { - int questionMarkIndex = rawUrl.indexOf('?'); - String url = questionMarkIndex != -1 ? rawUrl.substring(0, questionMarkIndex) : rawUrl; - - if (url.endsWith("/")) url = url.substring(0, url.length() - 1); - if (!url.startsWith("/")) url = "/" + url; - - return url; - } - - private Map extractQueryParameters(String rawUrl) { - int questionMarkIndex = rawUrl.indexOf('?'); - if (questionMarkIndex == -1) { - return new HashMap<>(); - } - String queryString = rawUrl.substring(questionMarkIndex + 1); - return HttpRequestUtils.parseQueryParameter(queryString); + return startLine.getQueryMap(); } public Map getHeaderMap() { diff --git a/src/main/java/http/HttpResponse.java b/src/main/java/http/HttpResponse.java index 4505d99..cdb49ee 100644 --- a/src/main/java/http/HttpResponse.java +++ b/src/main/java/http/HttpResponse.java @@ -11,6 +11,7 @@ import static enums.extension.FileExtension.CSS; import static enums.extension.FileExtension.HTML; +import static enums.http.HttpStatus.*; import static enums.http.header.EntityHeader.CONTENTLENGTH; import static enums.http.header.EntityHeader.CONTENTTYPE; import static enums.http.header.ResponseHeader.LOCATION; @@ -19,57 +20,69 @@ public class HttpResponse { private static final Logger log = Logger.getLogger(HttpResponse.class.getName()); private DataOutputStream dos; + private StringBuilder responseHeaderSB; public HttpResponse(DataOutputStream dos) { this.dos = dos; + this.responseHeaderSB = new StringBuilder(); } public void forward(String path) throws IOException { String relativePath = "webapp"+path; byte[] body = Files.readAllBytes(Paths.get(relativePath)); - if(path.endsWith(HTML.addFrontPoint())){ - sendHeader(dos, HTML.getValue(), body.length); - } - if(path.endsWith(CSS.addFrontPoint())){ - sendHeader(dos, CSS.getValue(), body.length); - } - sendBody(dos, body); + setStatusLine(HttpStatus.OK); + + if(path.endsWith(HTML.addFrontPoint())) addContentInfo(HTML.getValue(), body.length); + if(path.endsWith(CSS.addFrontPoint())) addContentInfo(CSS.getValue(), body.length); + + sendHeader(); + sendBody(body); } public void redirect(String location){ - try { - dos.writeBytes(HttpStatus.REDIRECT.getValue()); - dos.writeBytes(LOCATION.toResponseString() + location + "\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { - log.log(Level.SEVERE, e.getMessage()); - } + setStatusLine(REDIRECT); + addLocation(location); + sendHeader(); } public void redirectSettingCookie(String location){ - try { - dos.writeBytes(HttpStatus.REDIRECT.getValue()); - dos.writeBytes(SETCOOKIE.toResponseString()+ "logined=true" + "\r\n"); - dos.writeBytes(LOCATION.toResponseString() + location + "\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { - log.log(Level.SEVERE, e.getMessage()); - } + setStatusLine(REDIRECT); + addSetCookie(); + addLocation(location); + sendHeader(); } - private void sendHeader(DataOutputStream dos, String extension, int lengthOfBodyContent) { - try { - dos.writeBytes(HttpStatus.OK.getValue()); - dos.writeBytes(CONTENTTYPE.toResponseString() + "text/" + extension + ";charset=utf-8\r\n"); - dos.writeBytes(CONTENTLENGTH.toResponseString() + lengthOfBodyContent + "\r\n"); - dos.writeBytes("\r\n"); - } catch (IOException e) { + private void setStatusLine(HttpStatus httpStatus){ + responseHeaderSB.append(httpStatus.getValue()); + } + + private void addContentInfo(String extension, int lengthOfBodyContent){ + responseHeaderSB.append(CONTENTTYPE.toResponseString() + "text/" + extension + ";charset=utf-8\r\n"); + responseHeaderSB.append(CONTENTLENGTH.toResponseString() + lengthOfBodyContent + "\r\n"); + } + + private void addLocation(String location){ + responseHeaderSB.append(LOCATION.toResponseString() + location + "\r\n"); + } + + private void addSetCookie(){ + responseHeaderSB.append(SETCOOKIE.toResponseString()+ "logined=true" + "\r\n"); + } + + private void sendHeader() { + responseHeaderSB.append("\r\n"); + try{ + dos.writeBytes(responseHeaderSB.toString()); + responseHeaderSB.setLength(0); + dos.flush(); + } + catch (IOException e) { log.log(Level.SEVERE, e.getMessage()); } } - private void sendBody(DataOutputStream dos, byte[] body) { + private void sendBody(byte[] body) { try { dos.write(body, 0, body.length); dos.flush(); diff --git a/src/main/java/http/RequestStartLine.java b/src/main/java/http/RequestStartLine.java new file mode 100644 index 0000000..c40d7b8 --- /dev/null +++ b/src/main/java/http/RequestStartLine.java @@ -0,0 +1,31 @@ +package http; + +import java.util.Map; + +public class RequestStartLine { + private String httpMethod; + private String url; + private Map queryMap; + + private RequestStartLine(String httpMethod, String url, Map queryMap) { + this.httpMethod = httpMethod; + this.url = url; + this.queryMap = queryMap; + } + + public static RequestStartLine from(String httpMethod, String url, Map queryMap){ + return new RequestStartLine(httpMethod, url, queryMap); + } + + public String getUrl() { + return url; + } + + public String getHttpMethod() { + return httpMethod; + } + + public Map getQueryMap() { + return queryMap; + } +} diff --git a/webapp/user/login.html b/webapp/user/login.html index 23b990b..49e0a5e 100644 --- a/webapp/user/login.html +++ b/webapp/user/login.html @@ -40,7 +40,7 @@ From 4979c3aa7666dff936b1303625bc1e8260f9c8e0 Mon Sep 17 00:00:00 2001 From: kisusu Date: Thu, 3 Oct 2024 22:26:26 +0900 Subject: [PATCH 5/5] =?UTF-8?q?refactor:=20RequestStartLine=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1=20=EC=B1=85=EC=9E=84=EC=9D=84=20?= =?UTF-8?q?RequestStartLine=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=97=90?= =?UTF-8?q?=EA=B2=8C=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/http/HttpRequest.java | 29 +----------------------- src/main/java/http/RequestStartLine.java | 28 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/main/java/http/HttpRequest.java b/src/main/java/http/HttpRequest.java index 9a7a78c..44bfc8f 100644 --- a/src/main/java/http/HttpRequest.java +++ b/src/main/java/http/HttpRequest.java @@ -27,7 +27,7 @@ private HttpRequest(RequestStartLine startLine, public static HttpRequest from(BufferedReader br) throws IOException { String rawStartLine = extractStartLine(br); - RequestStartLine startLine = makeRequestStartLine(rawStartLine); + RequestStartLine startLine = RequestStartLine.from(rawStartLine); Map headerMap = extractHeaderMap(br); Map bodyMap = extractBodyMap(br, headerMap); return new HttpRequest(startLine, headerMap, bodyMap); @@ -41,33 +41,6 @@ private static String extractStartLine(BufferedReader br) throws IOException { return startLine; } - private static RequestStartLine makeRequestStartLine(String rawStartLine){ - String httpMethod = rawStartLine.split(" ")[0]; - String rawUrl = rawStartLine.split(" ")[1]; - String url = extractUrl(rawUrl); - Map queryMap = extractQueryParameters(rawUrl); - return RequestStartLine.from(httpMethod, url, queryMap); - } - - private static String extractUrl(String rawUrl) { - int questionMarkIndex = rawUrl.indexOf('?'); - String url = questionMarkIndex != -1 ? rawUrl.substring(0, questionMarkIndex) : rawUrl; - - if (url.endsWith("/")) url = url.substring(0, url.length() - 1); - if (!url.startsWith("/")) url = "/" + url; - - return url; - } - - private static Map extractQueryParameters(String rawUrl) { - int questionMarkIndex = rawUrl.indexOf('?'); - if (questionMarkIndex == -1) { - return new HashMap<>(); - } - String queryString = rawUrl.substring(questionMarkIndex + 1); - return HttpRequestUtils.parseQueryParameter(queryString); - } - private static Map extractHeaderMap(BufferedReader br) throws IOException { Map headerMap = new HashMap<>(); String line; diff --git a/src/main/java/http/RequestStartLine.java b/src/main/java/http/RequestStartLine.java index c40d7b8..ea6db45 100644 --- a/src/main/java/http/RequestStartLine.java +++ b/src/main/java/http/RequestStartLine.java @@ -1,5 +1,8 @@ package http; +import http.util.HttpRequestUtils; + +import java.util.HashMap; import java.util.Map; public class RequestStartLine { @@ -13,10 +16,33 @@ private RequestStartLine(String httpMethod, String url, Map quer this.queryMap = queryMap; } - public static RequestStartLine from(String httpMethod, String url, Map queryMap){ + public static RequestStartLine from(String rawStartLine){ + String httpMethod = rawStartLine.split(" ")[0]; + String rawUrl = rawStartLine.split(" ")[1]; + String url = extractUrl(rawUrl); + Map queryMap = extractQueryParameters(rawUrl); return new RequestStartLine(httpMethod, url, queryMap); } + private static String extractUrl(String rawUrl) { + int questionMarkIndex = rawUrl.indexOf('?'); + String url = questionMarkIndex != -1 ? rawUrl.substring(0, questionMarkIndex) : rawUrl; + + if (url.endsWith("/")) url = url.substring(0, url.length() - 1); + if (!url.startsWith("/")) url = "/" + url; + + return url; + } + + private static Map extractQueryParameters(String rawUrl) { + int questionMarkIndex = rawUrl.indexOf('?'); + if (questionMarkIndex == -1) { + return new HashMap<>(); + } + String queryString = rawUrl.substring(questionMarkIndex + 1); + return HttpRequestUtils.parseQueryParameter(queryString); + } + public String getUrl() { return url; }