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

[톰캣 구현하기 - 3, 4단계] 오잉(이하늘) 미션 제출합니다. #428

Merged
merged 16 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from 15 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
2 changes: 1 addition & 1 deletion study/src/test/java/thread/stage0/SynchronizationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private static final class SynchronizedMethods {

private int sum = 0;

public void calculate() {
public synchronized void calculate() {
setSum(getSum() + 1);
}

Expand Down
6 changes: 3 additions & 3 deletions study/src/test/java/thread/stage0/ThreadPoolsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void testNewFixedThreadPool() {
executor.submit(logWithSleep("hello fixed thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedQueueSize = 0;
final int expectedPoolSize = 2;
final int expectedQueueSize = 1;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size());
Expand All @@ -46,7 +46,7 @@ void testNewCachedThreadPool() {
executor.submit(logWithSleep("hello cached thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedPoolSize = 3;
final int expectedQueueSize = 0;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
Expand Down
2 changes: 1 addition & 1 deletion study/src/test/java/thread/stage1/ConcurrencyTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package thread.stage1;

import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -16,7 +17,6 @@
* 어떤 사례가 있는지 아래 테스트 코드를 통해 알아보자.
*/
class ConcurrencyTest {

@Test
void test() throws InterruptedException {
final var userServlet = new UserServlet();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.apache.catalina.connector;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.coyote.http11.Http11Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -15,17 +17,21 @@ public class Connector implements Runnable {

private static final int DEFAULT_PORT = 8080;
private static final int DEFAULT_ACCEPT_COUNT = 100;
private static final int DEFAULT_MAX_THREAD = 10;


private final ServerSocket serverSocket;
private final ExecutorService executorService;
private boolean stopped;

public Connector() {
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT);
this(DEFAULT_PORT, DEFAULT_ACCEPT_COUNT, DEFAULT_MAX_THREAD);
}

public Connector(final int port, final int acceptCount) {
public Connector(final int port, final int acceptCount, final int maxThreads) {
this.serverSocket = createServerSocket(port, acceptCount);
this.stopped = false;
this.executorService = Executors.newFixedThreadPool(maxThreads);
}

private ServerSocket createServerSocket(final int port, final int acceptCount) {
Expand Down Expand Up @@ -67,7 +73,7 @@ private void process(final Socket connection) {
return;
}
var processor = new Http11Processor(connection);
new Thread(processor).start();
executorService.execute(processor);
}

public void stop() {
Expand Down
5 changes: 2 additions & 3 deletions tomcat/src/main/java/org/apache/coyote/Processor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@
public interface Processor {

/**
* Process a connection. This is called whenever an event occurs (e.g. more
* data arrives) that allows processing to continue for a connection that is
* not currently being processed.
* Process a connection. This is called whenever an event occurs (e.g. more data arrives) that allows processing to
* continue for a connection that is not currently being processed.
*/
void process(Socket socket);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ public void process(final Socket connection) {
final var bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

HttpRequest request = HttpRequest.create(bufferedReader);
HttpResponse response = HttpResponse.create();

Servlet servlet = ServletFinder.find(request);
HttpResponse response = servlet.handle(request);
servlet.service(request, response);

outputStream.write(response.getBytes());
outputStream.flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public enum ContentType {
TEXT_PLAIN("", "text/plain;charset=utf-8"),
TEXT_HTML(".html", "text/html;charset=utf-8"),
TEXT_CSS(".css", "text/css"),
IMAGE_SVG(".svg", "image/svg+xml"),
APPLICATION_JAVASCRIPT(".js", "application/javascript");

private String extension;
Expand All @@ -24,11 +25,10 @@ public String getDetail() {
return detail;
}

public static String getDetailfromExtension(String extension) {
public static ContentType getContentTypeFromExtension(String extension) {
return Arrays.stream(ContentType.values())
.filter(it -> it.extension.equals(extension))
.findFirst()
.map(ContentType::getDetail)
.orElseThrow(() -> new IllegalArgumentException("No enum constant with extension: " + extension));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.apache.coyote.http11.common.request;
package org.apache.coyote.http11.common;

public enum HttpMethod {
GET, POST, PATCH, PUT, DELETE, NONE;
GET, POST, NONE;

public static HttpMethod from(final String name) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import java.util.UUID;
import org.apache.coyote.http11.common.Cookies;
import org.apache.coyote.http11.common.HttpHeaderName;
import org.apache.coyote.http11.common.HttpHeaders;
import org.apache.coyote.http11.common.HttpMethod;
import org.apache.coyote.http11.common.MessageBody;
import org.apache.coyote.http11.common.Session;
import org.apache.coyote.http11.common.SessionManager;
Expand All @@ -18,41 +18,41 @@ public class HttpRequest {
public static final String SESSIONID = "JSESSIONID";
public static final String COOKIE = "Cookie";

private final StartLine startLine;
private final HttpHeaders headers;
private final RequestLine requestLine;
private final RequestHeaders headers;
private final MessageBody body;
private final SessionManager sessionManager;

private HttpRequest(final StartLine startLine, final HttpHeaders headers, final MessageBody body) {
this.startLine = startLine;
private HttpRequest(final RequestLine requestLine, final RequestHeaders headers, final MessageBody body) {
this.requestLine = requestLine;
this.headers = headers;
this.body = body;
this.sessionManager = new SessionManager();
}

public static HttpRequest create(BufferedReader br) throws IOException {
StartLine startLine = findStartLine(br);
HttpHeaders headers = findHeaders(br);
RequestLine requestLine = findRequestLine(br);
RequestHeaders headers = findHeaders(br);
MessageBody body = findBody(headers, br);
return new HttpRequest(startLine, headers, body);
return new HttpRequest(requestLine, headers, body);
}

private static StartLine findStartLine(BufferedReader br) throws IOException {
private static RequestLine findRequestLine(BufferedReader br) throws IOException {
String firstLine = br.readLine();
return StartLine.create(firstLine);
return RequestLine.create(firstLine);
}

private static HttpHeaders findHeaders(BufferedReader br) throws IOException {
private static RequestHeaders findHeaders(BufferedReader br) throws IOException {
List<String> headers = new ArrayList<>();
String line = br.readLine();
while (!"".equals(line)) {
headers.add(line);
line = br.readLine();
}
return HttpHeaders.create(headers);
return RequestHeaders.create(headers);
}

private static MessageBody findBody(HttpHeaders headers, BufferedReader br) throws IOException {
private static MessageBody findBody(RequestHeaders headers, BufferedReader br) throws IOException {
String contentLength = headers.getHeader(HttpHeaderName.CONTENT_LENGTH.getName());
if (contentLength.isEmpty()) {
return MessageBody.empty();
Expand All @@ -64,11 +64,11 @@ private static MessageBody findBody(HttpHeaders headers, BufferedReader br) thro
}

public RequestUri getUri() {
return this.startLine.getUri();
return this.requestLine.getUri();
}

public HttpMethod getMethod() {
return this.startLine.getMethod();
return this.requestLine.getMethod();
}

public Cookies getCookies() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,29 @@
package org.apache.coyote.http11.common;
package org.apache.coyote.http11.common.request;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class HttpHeaders {
public class RequestHeaders {

private static final String DELIMITER = ": ";
private static final String EMPTY_STRING = "";

private Map<String, String> headers;

public HttpHeaders() {
headers = new LinkedHashMap<>();
}

private HttpHeaders(final Map<String, String> headers) {
private RequestHeaders(final Map<String, String> headers) {
this.headers = headers;
}

public static HttpHeaders create(final List<String> lines) {
public static RequestHeaders create(final List<String> lines) {
Map<String, String> headers = new LinkedHashMap<>();
for (String line : lines) {
String[] split = line.split(DELIMITER);
headers.put(split[0], split[1]);
}

return new HttpHeaders(headers);
}

public static HttpHeaders create(final Map<String, String> headers) {
return new HttpHeaders(new LinkedHashMap<>(headers));
}

public void addHeader(HttpHeaderName header, String value) {
headers.put(header.getName(), value);
return new RequestHeaders(headers);
}

public String getHeader(String name) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.apache.coyote.http11.common.request;

public class StartLine {
import org.apache.coyote.http11.common.HttpMethod;

public class RequestLine {
public static final String DELIMITER = " ";
public static final int METHOD_IDX = 0;
public static final int URI_IDX = 1;
Expand All @@ -9,13 +11,13 @@ public class StartLine {
private final RequestUri uri;
private final QueryParams params;

private StartLine(final HttpMethod method, final RequestUri uri, final QueryParams params) {
private RequestLine(final HttpMethod method, final RequestUri uri, final QueryParams params) {
this.method = method;
this.uri = uri;
this.params = params;
}

public static StartLine create(final String line) {
public static RequestLine create(final String line) {
String[] targets = line.split(DELIMITER);

HttpMethod method = HttpMethod.from(targets[METHOD_IDX]);
Expand All @@ -24,7 +26,7 @@ public static StartLine create(final String line) {
RequestUri uri = RequestUri.create(uriWithParams);
QueryParams params = QueryParams.create(uriWithParams);

return new StartLine(method, uri, params);
return new RequestLine(method, uri, params);
}

public RequestUri getUri() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,66 @@
package org.apache.coyote.http11.common.response;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.coyote.http11.common.ContentType;
import org.apache.coyote.http11.common.HttpHeaderName;
import org.apache.coyote.http11.common.HttpHeaders;
import org.apache.coyote.http11.common.HttpMethod;
import org.apache.coyote.http11.common.MessageBody;
import org.apache.coyote.http11.common.request.HttpMethod;
import org.apache.coyote.http11.servlet.Page;
import org.apache.coyote.http11.util.StaticFileLoader;

public class HttpResponse {

private final StatusLine statusLine;
private final HttpHeaders httpHeaders;
private final MessageBody messageBody;
private StatusLine statusLine;
private ResponseHeaders responseHeaders;
private MessageBody messageBody;

private HttpResponse(final StatusLine statusLine, final HttpHeaders httpHeaders, final MessageBody messageBody) {
private HttpResponse(final StatusLine statusLine, final ResponseHeaders responseHeaders,
final MessageBody messageBody) {
this.statusLine = statusLine;
this.httpHeaders = httpHeaders;
this.responseHeaders = responseHeaders;
this.messageBody = messageBody;
}

public static HttpResponse create(StatusCode code, HttpHeaders headers) {
return new HttpResponse(StatusLine.create(code), headers, MessageBody.empty());
public static HttpResponse create() {
return new HttpResponse(null, ResponseHeaders.create(), MessageBody.empty());
}

public static HttpResponse create(StatusCode code, HttpHeaders headers, String content) {
return new HttpResponse(StatusLine.create(code), headers, MessageBody.create(content));
public void setStatusCode(StatusCode code) {
statusLine = StatusLine.create(code);
}

public static HttpResponse createBadRequest() throws IOException {
String content = StaticFileLoader.load(Page.BAD_REQUEST.getUri());
public void setContentType(ContentType type) {
responseHeaders.addHeader(HttpHeaderName.CONTENT_TYPE, type.getDetail());
}

public void setContentLength(int length) {
responseHeaders.addHeader(HttpHeaderName.CONTENT_LENGTH, String.valueOf(length));
}
hanueleee marked this conversation as resolved.
Show resolved Hide resolved

HttpHeaders headers = new HttpHeaders();
headers.addHeader(HttpHeaderName.CONTENT_TYPE, ContentType.TEXT_HTML.getDetail());
headers.addHeader(HttpHeaderName.CONTENT_LENGTH, String.valueOf(content.getBytes().length));
public void setLocation(Page page) {
responseHeaders.addHeader(HttpHeaderName.LOCATION, page.getUri());
}

return HttpResponse.create(StatusCode.BAD_REQUEST, headers, content);
public void setCookie(String key, String value) {
responseHeaders.addHeader(HttpHeaderName.SET_COOKIE, key + "=" + value);
}

public static HttpResponse createMethodNotAllowed(List<HttpMethod> methods) {
public void setAllow(List<HttpMethod> methods) {
String allowedMethod = methods.stream()
.map(Enum::toString)
.collect(Collectors.joining(", "));

HttpHeaders headers = new HttpHeaders();
headers.addHeader(HttpHeaderName.ALLOW, allowedMethod);
return HttpResponse.create(StatusCode.METHOD_NOT_ALLOWED, headers);
responseHeaders.addHeader(HttpHeaderName.ALLOW, allowedMethod);
}

public void setBody(String content) {
messageBody = MessageBody.create(content);
}

public byte[] getBytes() {
String status = statusLine.toString();
String headers = httpHeaders.toString();
String headers = responseHeaders.toString();
String body = messageBody.getContent();
return String.join(System.lineSeparator(), status, headers, "", body)
.getBytes(StandardCharsets.UTF_8);
hanueleee marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Loading