Skip to content
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

Main #33

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Main #33

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
89 changes: 89 additions & 0 deletions src/main/java/webserver/HttpRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package webserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import util.HttpRequestUtils;
import util.IOUtils;

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

private String method;
private String path;
private Map<String, String> headers = new HashMap<String, String>();
private Map<String, String> params = new HashMap<String, String>();

public HttpRequest(InputStream in) {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
String line = br.readLine();

if (line == null) {
return;
}

processRequestLine(line);

while (line.equals("")) {
log.debug("header line: {}", line);
line = br.readLine();
String[] tokens = line.split(":");
headers.put(tokens[0].trim(), tokens[1].trim());

}
if("POST".equals(method)) {
String body = IOUtils.readData(br, Integer.parseInt(headers.get("Content-Length")));
params = HttpRequestUtils.parseQueryString(body);

}
} catch (IOException io) {
log.error(io.getMessage());
}

}

private void processRequestLine(String requestline) {
log.debug("request line: {}", requestline); // GET /doc/text.html HTTP/1.1
String[] tokens = requestline.split(" ");
method = tokens[0]; // GET

if ("POST".equals(method)) {
path = tokens[1];
return;
}
int index = tokens[1].indexOf("?");
if (index == -1) {
path = tokens[1];
} else {
path = tokens[1].substring(0, index); // 잘라내고 싶은 범위 정하기 (0부터 index까지)
params = HttpRequestUtils.parseQueryString(tokens[1].substring(index + 1));// 파라미터 받아오기

}

}

public String getMethod() {
return method;
}

public String getPath() {
return path;
}

public String getHeader(String name) {
return headers.get(name);
}

public String getParameter(String name) {
return params.get(name);
}
}
266 changes: 223 additions & 43 deletions src/main/java/webserver/RequestHandler.java
Original file line number Diff line number Diff line change
@@ -1,55 +1,235 @@
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.Collection;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import db.DataBase;
import model.User;
import util.HttpRequestUtils;
import util.IOUtils;


public class RequestHandler extends Thread {
private static final Logger log = LoggerFactory.getLogger(RequestHandler.class);

private Socket connection;

public RequestHandler(Socket connectionSocket) {
this.connection = connectionSocket;
}

public void run() {
log.debug("New Client Connect! Connected IP : {}, Port : {}", connection.getInetAddress(),
connection.getPort());

try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()) {
// TODO 사용자 요청에 대한 처리는 이 곳에 구현하면 된다.
DataOutputStream dos = new DataOutputStream(out);
byte[] body = "Hello World".getBytes();
response200Header(dos, body.length);
responseBody(dos, body);
} catch (IOException e) {
log.error(e.getMessage());
}
}

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.error(e.getMessage());
}
}

private void responseBody(DataOutputStream dos, byte[] body) {
try {
dos.write(body, 0, body.length);
dos.flush();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
private static final Logger log = LoggerFactory.getLogger(RequestHandler.class);

private Socket connection;

public RequestHandler(Socket connectionSocket) {
this.connection = connectionSocket;
}

public void run() {
log.debug("New Client Connect! Connected IP : {}, Port : {}", connection.getInetAddress(),
connection.getPort());

try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()) {

// 1.1 inputstream 한 줄로 읽기
BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
// 1.2 라인별로 HTTP 요청 정보 읽어오기
String line = br.readLine();

log.debug("request line : {}", line);
// 3.1 post의 경우 본문에 값이 담기므로 length를 0으로 초기화시켜준다.
int contentLength = 0;
// 1.3 line이 null값인 경우 예외 처리하기
if (line == null) {
return;
}
// 1.5 문자열 분리하기 ( GET /index.html HTTP/1.1 )
String[] tokens = line.split(" ");

// 6.1 사용자 목록에서 로그인 유무를 판단해서 보여주기 위한 변수
boolean logined = false;

// 1.4 헤더 마지막은 while문으로 확인이 가능하다.
while (!line.equals("")) {
log.debug("header line: {} ", line);
line = br.readLine();
if (line.contains("Cookie")) {
logined = isLogin(line);
}
// 3.2 contentLength 읽어와서 가져오기
if (line.contains("Content-Length")) {
// 콘턴츠 길이 가져오기
contentLength = getContentLength(line);
}
}
// 2.1 HTTP 요청 첫 번째 라인에서 요청 URL을 추출한다.
String url = tokens[1]; // user\create?userId=apple&....

if ("/user/create".contains(url)) {
// 3.3 본문 길이만큼 읽어오기
String body = IOUtils.readData(br, contentLength);
// 2.3 이름이랑 값 파싱하기 (필자가 구현한 API)
Map<String, String> params = HttpRequestUtils.parseQueryString(body);
// 2.4 User 객체에 저장해주기
User user = new User(params.get("userId"), params.get("password"), params.get("name"),
params.get("email"));

log.debug("user: {}" , user);
// 4.1 리다이렉트방식으로 페이지 이동하므로 302코드 이용하기
DataOutputStream dos = new DataOutputStream(out);
response302Header(dos, "/index.html");

// 5.1 database에 user정보를 저장해둔다.
DataBase.addUser(user);

//7.1 css파일 읽어오기
} else if (url.endsWith(".css")) {
DataOutputStream dos = new DataOutputStream(out);
byte[] body = Files.readAllBytes(new File("./webapp" + url).toPath());
response200CssHeader(dos, body.length);
responseBody(dos, body);
}
// 5.2 login버튼 눌렀을때 body 읽어오고 값 파싱하고 저장해둔 database에 userid 와 같으면 성공했음 알려주기
else if ("/user/login".contains(url)) {
String body = IOUtils.readData(br, contentLength);
Map<String, String> params = HttpRequestUtils.parseQueryString(body);
User user = DataBase.findUserById(params.get("userId"));
if (user == null) {
responseResource(out, "/user/login_failed.html");
}
if (user.getPassword().equals(params.get("password"))) {
DataOutputStream dos = new DataOutputStream(out);
response302LoginSuccessHeader(dos);
} else {
responseResource(out, "/user/login_failed.html");

}
// 6.1 사용자 목록 들어갔을때 목록 띄우기
} else if ("/user/list".contains(url)) {
if (!logined) {
responseResource(out, "/user/login.html");
return;

}
System.out.println("뭐지?");
// 6.2 담아준 user 가져오기
Collection<User> users = DataBase.findAll();
log.debug("user: {}",users);
// 6.3 StringBuilder 사용해서 출력하기
StringBuilder sb = new StringBuilder();

sb.append("<table border='1'>");
for (User user : users) {
sb.append("<tr>");
sb.append("<td>" + user.getUserId() + "</td>");
sb.append("<td>" + user.getName() + "</td>");
sb.append("<td>" + user.getEmail() + "</td>");
sb.append("</tr>");
}
sb.append("</table>");
// 6.4 출력문 byte형식으로 변환해서 읽어오기
byte[] body = sb.toString().getBytes();
// 6.5 츨력스트림 열기
DataOutputStream dos = new DataOutputStream(out);
// 6.6 성공했으므로 200코드로 출력스트림이랑 body길이 보내기
response200Header(dos, body.length);
// 6.7 스트림 닫기
responseBody(dos, body);
}

else {
responseResource(out, url);
}
} catch (IOException e) {
log.error(e.getMessage());
}
}

private void response200CssHeader(DataOutputStream dos, int lengthOfBodyContent) {
try {
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");
} catch (IOException e) {
log.error(e.getMessage());
}

}

private boolean isLogin(String line) {
String[] headerTokens = line.split(":");
Map<String, String> cookies = HttpRequestUtils.parseCookies(headerTokens[1].trim());
String value = cookies.get("logined");

if (value == null) {
return false;
}
return Boolean.parseBoolean(value);
}

// 로그인 성공했을 경우 리다이렉트로 이동하게 해줌.
private void response302LoginSuccessHeader(DataOutputStream dos) {
try {
dos.writeBytes("HTTP/1.1 302 Redirect \r\n");
dos.writeBytes("Set-Cookie: logined=true \r\n");
dos.writeBytes("Location: /index.html" + "\r\n");
dos.writeBytes("\r\n");
} catch (IOException e) {
log.error(e.getMessage());

}
}

// 파일 읽고 응답해주는 메소드
private void responseResource(OutputStream out, String url) throws IOException {
DataOutputStream dos = new DataOutputStream(out);
byte[] body = Files.readAllBytes(new File("./webapp" + url).toPath());
response200Header(dos, body.length);
responseBody(dos, body);

}

private int getContentLength(String line) {
// line : Content-length:59 // headertokens {Content-length, 59}
String[] headertokens = line.split(":");
return Integer.parseInt(headertokens[1].trim()); // 59
}

// 2xx: 성공
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.error(e.getMessage());
}
}

// 3xx : 리다이렉션(요청을 마치기 위해 추가 동작이 필요하다)
private void response302Header(DataOutputStream dos, String url) {
try {
dos.writeBytes("HTTP/1.1 302 Redirect \r\n");
dos.writeBytes("Location: " + url + "\r\n");
dos.writeBytes("\r\n");
} catch (IOException e) {
log.error(e.getMessage());
}
}

private void responseBody(DataOutputStream dos, byte[] body) {
try {
dos.write(body, 0, body.length);
dos.flush();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
2 changes: 1 addition & 1 deletion webapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<li><a href="https://facebook.com" target="_blank">Facebook</a></li>
</ul>
</li>
<li><a href="./user/list.html"><i class="glyphicon glyphicon-user"></i></a></li>
<li><a href="./user/list.html">=<i class="glyphicon glyphicon-user"></i></a></li>
</ul>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion webapp/user/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
<div class="container" id="main">
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-default content-main">
<form name="question" method="get" action="/user/create">
<form name="question" method="post" action="/user/create">
<div class="form-group">
<label for="userId">사용자 아이디</label>
<input class="form-control" id="userId" name="userId" placeholder="User ID">
Expand Down