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

[테리] Step 3,4: HTTP 웹서버 구현 #7

Open
wants to merge 10 commits into
base: mybloom
Choose a base branch
from
Open
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
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -5,11 +5,18 @@ plugins {
group 'org.example'
version '1.0-SNAPSHOT'

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.projectlombok:lombok:1.18.20'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.22.0'
@@ -22,6 +29,9 @@ dependencies {
implementation group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.9.0'
// https://mvnrepository.com/artifact/com.h2database/h2
implementation group: 'com.h2database', name: 'h2', version: '2.1.210'

compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.22'
annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.22'
}

test {
2 changes: 2 additions & 0 deletions docs/InputOutputStream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Input/Output Stream

28 changes: 5 additions & 23 deletions src/main/java/model/User.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,16 @@
package model;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class User {
private String userId;
private String password;
private String name;
private String email;

public User(String userId, String password, String name, String email) {
this.userId = userId;
this.password = password;
this.name = name;
this.email = email;
}

public String getUserId() {
return userId;
}

public String getPassword() {
return password;
}

public String getName() {
return name;
}

public String getEmail() {
return email;
}

@Override
public String toString() {
return "User [userId=" + userId + ", password=" + password + ", name=" + name + ", email=" + email + "]";
119 changes: 119 additions & 0 deletions src/main/java/webserver/Request.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package webserver;

import db.DataBase;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.HttpRequestUtils;
import util.IOUtils;
import webserver.domain.HttpMethod;
import webserver.domain.RequestHeader;
import webserver.domain.RequestLine;

public class Request {

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

private RequestHeader requestHeader;
private int contentLength;

public RequestLine handleUserRequest(InputStream in) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));

makeRequestHeader(bufferedReader);
processHttpMethod();

return requestHeader.getRequestLine();
}

private void makeRequestHeader(BufferedReader bufferedReader)
throws IOException {

String line = bufferedReader.readLine();
String startLine = line;
log.debug("requestHeader: {}", line);

List<String> requestData = new ArrayList<>();
while (!"".equals(line)) {
line = bufferedReader.readLine();
log.debug("requestHeader: {}", line);

if (line.contains("Content-Length")) {
String[] token = line.split(":");
contentLength = Integer.parseInt(token[1].trim());
}

if (line == null) {
return;
}
requestData.add(line);
}

requestHeader.setBody(IOUtils.readData(bufferedReader, contentLength));


this.requestHeader = new RequestHeader(startLine, requestData);
}

private void processHttpMethod() {
HttpMethod httpMethod = requestHeader.getRequestLine().getHttpMethod();
String url = requestHeader.getRequestLine().getUrl();

if (httpMethod.equals(HttpMethod.GET)) {
int indexOfQueryParameter = url.indexOf('?');
if (indexOfQueryParameter != -1) {
processQueryParameter(url, indexOfQueryParameter);
}
} else if (httpMethod.equals(HttpMethod.POST)) {
Map<String, String> queryStrings = HttpRequestUtils.parseQueryString(requestHeader.getBody());
saveUserInDatabase(queryStrings);
}

}

private void processQueryParameter(String url, int indexOfQueryParameter) {
String requestPath = url.substring(0, indexOfQueryParameter);
String queryString = url.substring(indexOfQueryParameter + 1);

Map<String, String> queryStringMap = HttpRequestUtils.parseQueryString(queryString);

saveUserInDatabase(queryStringMap);
}

private void saveUserInDatabase(Map<String, String> queryStringMap) {
User user = new User();
for (Entry<String, String> entry : queryStringMap.entrySet()) {
switch (entry.getKey()) {
case "userId":
user.setUserId(entry.getValue());
break;
case "name":
user.setName(entry.getValue());
break;
case "password":
user.setPassword(entry.getValue());
break;
case "email":
user.setEmail(URLDecoder.decode(entry.getValue(), StandardCharsets.UTF_8));
break;
}
}

DataBase.addUser(user);
DataBase.findAll().stream()
.forEach(userInDatabase -> log.debug("**Database.findAll() : {}",
userInDatabase.toString()));
//TODO : index.html로 redirection 되도록 처리해야하지 않을까? 요구사항에 없으니 패스
}

}
69 changes: 26 additions & 43 deletions src/main/java/webserver/RequestHandler.java
Original file line number Diff line number Diff line change
@@ -1,55 +1,38 @@
package webserver;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import webserver.domain.RequestLine;


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;
private Request request = new Request();
private Response response = new Response();

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 사용자 요청에 대한 처리는 이 곳에 구현하면 된다.
RequestLine requestLine = request.handleUserRequest(in);
response.makeResponse(requestLine.getUrl(), out);

} catch (IOException e) {
log.error(e.getMessage());
}
}
}
62 changes: 62 additions & 0 deletions src/main/java/webserver/Response.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package webserver;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Response {

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

public void makeResponse(String url, OutputStream out) {
DataOutputStream dos = new DataOutputStream(out);

byte[] body = null;

if (url.equals("/index.html") || url.equals("/user/form.html")) {
body = makeRequestBody(url);
} else {
body = "Hello World".getBytes();
}

response200Header(dos, body.length);
responseBody(dos, body);
}

private byte[] makeRequestBody(String url) {
byte[] body = null;

try {
body = Files.readAllBytes(new File("./webapp" + url).toPath());
} catch (IOException e) {
e.printStackTrace();
}

return body;
}

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

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

import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class RequestHeader {

private RequestLine requestLine;
private List<String> requestHeaders;
private String body;

private RequestHeader(){
}

public RequestHeader (String startLine, List<String> requestData) {
this();
this.requestLine = makeRequestLine(startLine);
}

private RequestLine makeRequestLine(String startLine) {
String[] requestLine = startLine.split(" ");
return new RequestLine(requestLine[0], requestLine[1], requestLine[2]);
}
}
20 changes: 20 additions & 0 deletions src/main/java/webserver/domain/RequestLine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package webserver.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class RequestLine {

private HttpMethod httpMethod;
private String url;
private String httpVersion;

public RequestLine(String httpMethod, String url, String httpVersion) {
this.httpMethod = HttpMethod.valueOf(httpMethod);
this.url = url;
this.httpVersion = httpVersion;
}

}
Loading