Skip to content

[웹서버 2단계] Refactor #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
# 웹 애플리케이션 서버
## 진행 방법
* 웹 애플리케이션 서버 요구사항을 파악한다.
* 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다.
* 다음 단계를 도전하고 앞의 과정을 반복한다.
* 코드 리뷰가 완료되면 피드백에 대한 개선 작업을 한다.
* 다음 단계 PR 보낼 때 이전 단계 피드백이 잘 반영되었는지 점검한다.

## 온라인 코드 리뷰 과정
* [텍스트와 이미지로 살펴보는 코드스쿼드의 온라인 코드 리뷰 과정](https://github.com/code-squad/codesquad-docs/blob/master/codereview/README.md)
* [동영상으로 살펴보는 코드스쿼드의 온라인 코드 리뷰 과정](https://youtu.be/a5c9ku-_fok)
# 웹서버 구현
### [Ground Rule](https://github.com/beginin15/java-was/wiki/Ground-Rule)
### [Han's README](https://github.com/beginin15/java-was/wiki/%5BHan%5D-README)
### [Jay's README](https://github.com/beginin15/java-was/wiki/%5BJay%5D-README)
6 changes: 6 additions & 0 deletions src/main/java/http/HttpMethod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package http;

public enum HttpMethod {
GET,
POST;
}
64 changes: 64 additions & 0 deletions src/main/java/http/HttpRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package http;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.HttpRequestUtils;
import util.IOUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;

public class HttpRequest {

private static final Logger log = LoggerFactory.getLogger(HttpRequest.class);

private HttpMethod httpMethod;
private String path;
private Map<String, String> header;
private Map<String, String> parameter;

public HttpRequest(BufferedReader br) {
parseRequest(br);
}

public HttpMethod getMethod() {
return httpMethod;
}

public String getPath() {
return path;
}

public String getHeader(String key) {
return header.get(key);
}

public String getParameter(String key) {
return parameter.get(key);
}

private void parseRequest(BufferedReader br) {
String requestLine;

try {
requestLine = br.readLine();
httpMethod = HttpMethod.valueOf(HttpRequestUtils.getMethod(requestLine));
path = HttpRequestUtils.getURL(requestLine);
changePathIfRoot();
header = HttpRequestUtils.extractHeader(br);
if (httpMethod.equals(HttpMethod.POST)) {
String body = IOUtils.readData(br, Integer.parseInt(getHeader("Content-Length")));
parameter = HttpRequestUtils.parseQueryString(body);
}
} catch (IOException e) {
log.error("HttpRequest parse 과정 에러");
}
}

private void changePathIfRoot() {
if (this.path.equals("/")) {
path = "/index.html";
}
}
}
118 changes: 118 additions & 0 deletions src/main/java/http/HttpResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package http;


import model.User;
import util.HttpResponseUtils;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HttpResponse {

private Map<String, String> header;
private DataOutputStream dos;

public HttpResponse() {
header = new HashMap<>();
}

public HttpResponse(DataOutputStream dos) {
header = new HashMap<>();
this.dos = dos;
}

// public void addHeader(String key, String value) {
// header.put(key, value);
// }

public void forward(String path) throws IOException {
byte[] body;
if (HttpResponseUtils.isFileExist(path)) {
body = HttpResponseUtils.readFile(path);
response200Header(body.length);
responseBody(body);
return;
}
body = HttpResponseUtils.notExistPage();
response404Header(body.length);
responseBody(body);
}

public void forwardBody(String responseBody) {

}

public void response200Header(int lengthOfBodyContent) throws IOException {
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");
}

public void sendRedirect(String location) throws IOException {
dos.writeBytes("HTTP/1.1 302 Found \r\n");
dos.writeBytes("Location: " + location + "\r\n");
dos.writeBytes("\r\n");
}

public void sendRedirect(String location, String sessionId) throws IOException {
dos.writeBytes("HTTP/1.1 302 Found \r\n");
dos.writeBytes("Location: " + location + "\r\n");
dos.writeBytes("Set-Cookie: JSESSIONID=" + sessionId + "; Path=/" + "\r\n");
dos.writeBytes("\r\n");
}

public void readUserList(List<User> users) throws IOException {
byte[] body = HttpResponseUtils.readFile("/user/list.html");
String userListHtml = HttpResponseUtils.getUserListHTML(body, users);
response200Header(userListHtml.length());
responseBody(userListHtml.getBytes());
}

public void readCss(String path) throws IOException {
byte[] body = Files.readAllBytes(new File("./webapp" + path).toPath());
responseCssHeader(body.length);
responseBody(body);
}

public String processHeaders() {
StringBuilder sb = new StringBuilder();
header.entrySet().stream()
.map(entry -> entry.getKey() + ": " + entry.getValue())
.forEach(header -> sb.append(header).append("\r\n"));

sb.append("\r\n");
return sb.toString();
}

private void responseCssHeader(int lengthOfBodyContent) throws IOException {
dos.writeBytes("HTTP/1.1 200 OK \r\n");
dos.writeBytes("Content-Type: text/css;charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
}

private void response401Header(int lengthOfBodyContent) throws IOException {
dos.writeBytes("HTTP/1.1 401 Unauthorized \r\n");
dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
}

private void responseBody(byte[] body) throws IOException {
dos.write(body, 0, body.length);
dos.flush();
}

private void response404Header(int lengthOfBodyContent) throws IOException {
dos.writeBytes("HTTP/1.1 404 Not Found \r\n");
dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
}
}
8 changes: 8 additions & 0 deletions src/main/java/util/HttpRequestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
public class HttpRequestUtils {

private static final int INDEX_PATH = 1;
private static final int INDEX_METHOD = 0;


public static Map<String, String> extractHeader(BufferedReader br) throws IOException {
Map<String, String> header = new HashMap<>();
Expand All @@ -33,6 +35,12 @@ public static String getURL(String line) throws IOException {
return line.split(" ")[INDEX_PATH];
}

public static String getMethod(String line) throws IOException {
if (line == null) throw new IOException("잘못된 Request Start Line");
return line.split(" ")[INDEX_METHOD];
}


public static String decode(String line) throws UnsupportedEncodingException {
return URLDecoder.decode(line, StandardCharsets.UTF_8.toString());
}
Expand Down
110 changes: 27 additions & 83 deletions src/main/java/util/HttpResponseUtils.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
package util;


import model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;


public class HttpResponseUtils {
private static final Logger log = LoggerFactory.getLogger(HttpResponseUtils.class);

public static void readUserList(DataOutputStream dos, List<User> users) throws IOException {
byte[] body = Files.readAllBytes(new File("./webapp" + "/user/list.html").toPath());
public static final String PAGE_LOGIN_FAILED = "/user/login_failed.html";


public static boolean isFileExist(String path) {
return Files.exists(Paths.get(new File("./webapp") + path));
}

public static byte[] readFile(String path) throws IOException {
return Files.readAllBytes(new File("./webapp" + path).toPath());
}

public static byte[] notExistPage() {
return "요청하신 페이지가 없습니다".getBytes();
}

public static String getUserListHTML(byte[] body, List<User> users) {
StringBuilder list = new StringBuilder(new String(body));
int index = list.indexOf("<table class=\"table table-hover\">");
String temp = "<table class=\"table table-hover\">";
String target = "<table class=\"table table-hover\">";
int index = list.indexOf(target);
list.insert(index + target.length(), createUserListHTML(users));
return list.toString();
}

private static String createUserListHTML(List<User> users) {
StringBuilder sb = new StringBuilder();

sb.append("<thead>");
sb.append("<tr>");
sb.append("<th>#</th> <th>사용자 아이디</th> <th>이름</th> <th>이메일</th><th></th>");
Expand All @@ -38,82 +58,6 @@ public static void readUserList(DataOutputStream dos, List<User> users) throws I
sb.append("</tr>");
}
sb.append("</tbody>");

list.insert(index + temp.length(), sb);
String html = list.toString();
response200Header(dos, html.length());
responseBody(dos, html.getBytes());
}

public static void readLoginFailed(DataOutputStream dos) throws IOException {
byte[] body = Files.readAllBytes(new File("./webapp/user/login_failed.html").toPath());
response401Header(dos, body.length);
responseBody(dos, body);
}

public static void redirect(DataOutputStream dos, String location) throws IOException {
dos.writeBytes("HTTP/1.1 302 Found \r\n");
dos.writeBytes("Location: " + location + "\r\n");
dos.writeBytes("\r\n");
}

public static void redirectWithCookie(DataOutputStream dos, String sessionId) throws IOException {
dos.writeBytes("HTTP/1.1 302 Found \r\n");
dos.writeBytes("Location: /\r\n");
dos.writeBytes("Set-Cookie: JSESSIONID=" + sessionId + "; Path=/" + "\r\n");
dos.writeBytes("\r\n");
}

public static void readCss(DataOutputStream dos, String url) throws IOException {
byte[] body = Files.readAllBytes(new File("./webapp" + url).toPath());
responseCssHeader(dos, body.length);
responseBody(dos, body);
}

public static void readStaticFile(DataOutputStream dos, String url) throws IOException {
byte[] body;
if (Files.exists(Paths.get(new File("./webapp") + url))) {
body = Files.readAllBytes(new File("./webapp" + url).toPath());
response200Header(dos, body.length);
responseBody(dos, body);
return;
}
body = "요청하신 페이지가 없습니다".getBytes();
response404Header(dos, body.length);
responseBody(dos, body);
}

private static void responseCssHeader(DataOutputStream dos, int lengthOfBodyContent) throws IOException {
dos.writeBytes("HTTP/1.1 200 OK \r\n");
dos.writeBytes("Content-Type: text/css;charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
}

private static void response200Header(DataOutputStream dos, int lengthOfBodyContent) throws IOException {
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");
}


private static void response401Header(DataOutputStream dos, int lengthOfBodyContent) throws IOException {
dos.writeBytes("HTTP/1.1 401 Unauthorized \r\n");
dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
}

private static void responseBody(DataOutputStream dos, byte[] body) throws IOException {
dos.write(body, 0, body.length);
dos.flush();
}

private static void response404Header(DataOutputStream dos, int lengthOfBodyContent) throws IOException {
dos.writeBytes("HTTP/1.1 404 Not Found \r\n");
dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
return sb.toString();
}
}
Loading