-
Notifications
You must be signed in to change notification settings - Fork 388
[1단계 - Tomcat 구현하기] 알파카(최휘용) 미션 제출합니다. #568
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
Changes from all commits
fed02f6
7e91356
8312e6d
237423b
70957b9
b0368ea
982c7e0
6b580f6
6a2e8d5
e2d8592
2c666ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,20 @@ | ||
| package cache.com.example.etag; | ||
|
|
||
| import static cache.com.example.version.CacheBustingWebConfig.PREFIX_STATIC_RESOURCES; | ||
|
|
||
| import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.web.filter.ShallowEtagHeaderFilter; | ||
|
|
||
| @Configuration | ||
| public class EtagFilterConfiguration { | ||
|
|
||
| // @Bean | ||
| // public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() { | ||
| // return null; | ||
| // } | ||
| @Bean | ||
| public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() { | ||
| FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean = | ||
| new FilterRegistrationBean<>(new ShallowEtagHeaderFilter()); | ||
| filterRegistrationBean.addUrlPatterns("/etag/*", PREFIX_STATIC_RESOURCES + "/*"); | ||
| return filterRegistrationBean; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package com.techcourse.controller; | ||
|
|
||
| import com.techcourse.db.InMemoryUserRepository; | ||
| import org.apache.coyote.http11.HttpRequest; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class Controller { | ||
|
|
||
| private static final Logger LOGGER = LoggerFactory.getLogger(Controller.class); | ||
|
|
||
| public Controller() { | ||
| } | ||
|
|
||
| public String getLogin(HttpRequest request) { | ||
| String requestAccount = request.getQueryStringData("account"); | ||
| String requestPassword = request.getQueryStringData("password"); | ||
| InMemoryUserRepository.findByAccount(requestAccount) | ||
| .ifPresent(user -> { | ||
| if (user.checkPassword(requestPassword)) { | ||
| LOGGER.info(user.toString()); | ||
| } | ||
| }); | ||
| return "/login.html"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,34 @@ | ||
| package org.apache.coyote.http11; | ||
|
|
||
| import com.techcourse.exception.UncheckedServletException; | ||
| import java.io.BufferedReader; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.InputStreamReader; | ||
| import java.io.OutputStream; | ||
| import java.net.Socket; | ||
| import java.net.URISyntaxException; | ||
| import java.net.URL; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Paths; | ||
| import java.util.HashMap; | ||
| import java.util.LinkedHashMap; | ||
| import java.util.Map; | ||
| import java.util.stream.Stream; | ||
| import org.apache.coyote.Processor; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import java.io.IOException; | ||
| import java.net.Socket; | ||
|
|
||
| public class Http11Processor implements Runnable, Processor { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(Http11Processor.class); | ||
|
|
||
| private final Socket connection; | ||
| private final RequestMapper requestMapper; | ||
|
|
||
| public Http11Processor(final Socket connection) { | ||
| this.connection = connection; | ||
| this.requestMapper = new RequestMapper(); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -25,23 +38,97 @@ public void run() { | |
| } | ||
|
|
||
| @Override | ||
| public void process(final Socket connection) { | ||
| try (final var inputStream = connection.getInputStream(); | ||
| final var outputStream = connection.getOutputStream()) { | ||
|
|
||
| final var responseBody = "Hello world!"; | ||
| public void process(Socket connection) { | ||
| try (InputStream inputStream = connection.getInputStream(); | ||
| OutputStream outputStream = connection.getOutputStream()) { | ||
| HttpRequest request = parseInput(inputStream); | ||
|
|
||
| final var response = String.join("\r\n", | ||
| "HTTP/1.1 200 OK ", | ||
| "Content-Type: text/html;charset=utf-8 ", | ||
| "Content-Length: " + responseBody.getBytes().length + " ", | ||
| "", | ||
| responseBody); | ||
| String resourceName = requestMapper.requestMapping(request); | ||
| String responseBody = parseStartLine(resourceName); | ||
|
Comment on lines
+46
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 변수랑 메서드 이름이랑 잘 맞지 않는 것 같아요. requestMapper 가 requestMapping 을 한다는게 어떤 의미인지 알기 어렵네요. parseStartLine()의 결과가 responseBody인 부분도 마찬가지로 의아하네요. |
||
| String resourceExtension = getExtension(resourceName); | ||
|
|
||
| HttpResponse response = new HttpResponse(responseBody, resourceExtension); | ||
| outputStream.write(response.getBytes()); | ||
| outputStream.flush(); | ||
| } catch (IOException | UncheckedServletException e) { | ||
| } catch (IOException | UncheckedServletException | URISyntaxException e) { | ||
| log.error(e.getMessage(), e); | ||
| } | ||
| } | ||
|
|
||
| private HttpRequest parseInput(InputStream inputStream) throws IOException { | ||
| BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); | ||
| String tokens[] = bufferedReader.readLine() | ||
| .split(" "); | ||
| if (tokens.length != 3) { | ||
| throw new RuntimeException(); | ||
| } | ||
|
|
||
| String path = parsePath(tokens[1]); | ||
| Map<String, String> queryString = parseQueryString(tokens[1]); | ||
| Map<String, String> headers = parseHeaders(bufferedReader); | ||
| return new HttpRequest(tokens[0], path, queryString, tokens[2], headers); | ||
| } | ||
|
|
||
| private String parsePath(String token) { | ||
| int separatorIndex = token.indexOf('?'); | ||
| if (separatorIndex == -1) { | ||
| return token; | ||
| } | ||
| return token.substring(0, separatorIndex); | ||
| } | ||
|
|
||
| private Map<String, String> parseQueryString(String token) { | ||
| Map<String, String> queryString = new HashMap<>(); | ||
| int separatorIndex = token.indexOf('?'); | ||
| if (separatorIndex == -1) { | ||
| return queryString; | ||
| } | ||
| Stream.of(token.substring(separatorIndex + 1) | ||
| .split("&")) | ||
| .forEach(data -> parseData(data, queryString)); | ||
| return queryString; | ||
| } | ||
|
|
||
| private void parseData(String s, Map<String, String> queryString) { | ||
| String data[] = s.split("="); | ||
| if (data.length == 2) { | ||
| queryString.put(data[0], data[1]); | ||
| } | ||
| } | ||
|
|
||
| private String getExtension(String resourceName) { | ||
| int extensionIndex = resourceName.indexOf('.') + 1; | ||
| if (extensionIndex == 0) { | ||
| return "html"; | ||
| } | ||
| return resourceName.substring(extensionIndex); | ||
| } | ||
|
|
||
| private String parseStartLine(String resourceName) throws URISyntaxException, IOException { | ||
| URL resource = getClass().getClassLoader() | ||
| .getResource("static" + resourceName); | ||
|
|
||
| try { | ||
| return Files.readString(Paths.get(resource.toURI())); | ||
| } catch (IOException e) { | ||
| return "Hello world!"; | ||
| } | ||
| } | ||
|
|
||
| private Map<String, String> parseHeaders(BufferedReader bufferedReader) throws IOException { | ||
| String line = bufferedReader.readLine(); | ||
| Map<String, String> headers = new LinkedHashMap<>(); | ||
|
|
||
| while (!"".equals(line)) { | ||
| if (line == null) { | ||
| return headers; | ||
| } | ||
| int index = line.indexOf(':'); | ||
| String key = line.substring(0, index); | ||
| String value = line.substring(index + 2); | ||
| headers.put(key, value); | ||
| line = bufferedReader.readLine(); | ||
| } | ||
| return headers; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package org.apache.coyote.http11; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| public class HttpRequest { | ||
|
|
||
| private final String method; | ||
| private final String path; | ||
| private final Map<String, String> queryString; | ||
| private final String protocolVersion; | ||
| private final Map<String, String> headers; | ||
|
|
||
| public HttpRequest(String method, String path, Map<String, String> queryString, String protocolVersion, | ||
| Map<String, String> headers) { | ||
| this.method = method; | ||
| this.path = path; | ||
| this.queryString = queryString; | ||
| this.protocolVersion = protocolVersion; | ||
| this.headers = headers; | ||
| } | ||
|
|
||
| public String getQueryStringData(String input) { | ||
| return queryString.get(input); | ||
| } | ||
|
Comment on lines
+22
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 메서드 이름에 Data와 String이 둘 다 들어가는 부분이 어색하게 느껴지네요. 둘 중 하나만 들어가는건 어떤가요? |
||
|
|
||
| public String getPath() { | ||
| return this.path; | ||
| } | ||
|
|
||
| public String getMethod() { | ||
| return this.method; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional을 잘 이용한다면 깊이를 줄일 수 있을 것 같아요.