Skip to content

Commit

Permalink
[1-2단계 톰캣 구현하기] 감자(김주하) 미션 제출합니다. (#509)
Browse files Browse the repository at this point in the history
* feat: 요청 URI 추출 기능 구현

* feat: HTTP 요청 라인 추출 기능 구현

* feat: HTTP 응답 객체 추가

* feat: HTTP 요청 객체 추가

* feat: 정적 파일 반환 및 login 기능 구현

* refactor: HttpRequest 객체에 헤더와 본문 필드 추가

* feat: 사용자 가입 기능 구현

* fix: remove implementation logback-classic on gradle (#501)

* feat: 로그인 기능에 세션 추가

* fix: add threads min-spare configuration on properties (#502)

* fix: 요청 쿠키 null 처리 추가

* feat: SessionGenerator 추가

* test: 정적 파일 반환 및 로그인 테스트

* test: Query String 파싱 테스트

* test: register 테스트

* refactor: 쿠키 파싱 로직 수정

* feat: 학습 테스트 작성

---------

Co-authored-by: Gyeongho Yang <[email protected]>
  • Loading branch information
khabh and geoje authored Sep 6, 2024
1 parent 0b698a2 commit 728632e
Show file tree
Hide file tree
Showing 34 changed files with 1,092 additions and 80 deletions.
1 change: 0 additions & 1 deletion study/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'ch.qos.logback:logback-classic:1.5.7'
implementation 'org.apache.commons:commons-lang3:3.14.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'
implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1'
Expand Down
6 changes: 3 additions & 3 deletions study/src/main/java/cache/com/example/GreetingController.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class GreetingController {

@GetMapping("/")
public String index() {
return "index";
return "index.html";
}

/**
Expand All @@ -25,12 +25,12 @@ public String cacheControl(final HttpServletResponse response) {
.cachePrivate()
.getHeaderValue();
response.addHeader(HttpHeaders.CACHE_CONTROL, cacheControl);
return "index";
return "index.html";
}

@GetMapping("/etag")
public String etag() {
return "index";
return "index.html";
}

@GetMapping("/resource-versioning")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package cache.com.example.cachecontrol;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.WebContentInterceptor;

@Configuration
public class CacheWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(final InterceptorRegistry registry) {
CacheControl cacheControl = CacheControl.noCache().cachePrivate();
WebContentInterceptor webContentInterceptor = new WebContentInterceptor();
webContentInterceptor.addCacheMapping(cacheControl, "/**");
registry.addInterceptor(webContentInterceptor);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package cache.com.example.etag;

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");
filterRegistrationBean.addUrlPatterns("/resources/*");
return filterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cache.com.example.version;

import java.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

Expand All @@ -20,6 +22,7 @@ public CacheBustingWebConfig(ResourceVersion version) {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**")
.addResourceLocations("classpath:/static/");
.addResourceLocations("classpath:/static/")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic());
}
}
4 changes: 4 additions & 0 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ server:
accept-count: 1
max-connections: 1
threads:
min-spare: 2
max: 2
compression:
enabled: true
min-response-size: 10
10 changes: 10 additions & 0 deletions study/src/main/resources/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html lang="ko">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
Hello, World!
</body>
</html>
16 changes: 10 additions & 6 deletions study/src/test/java/study/FileTest.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package study;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -28,7 +31,7 @@ class FileTest {
final String fileName = "nextstep.txt";

// todo
final String actual = "";
final String actual = getClass().getClassLoader().getResource(fileName).getPath();

assertThat(actual).endsWith(fileName);
}
Expand All @@ -40,14 +43,15 @@ class FileTest {
* File, Files 클래스를 사용하여 파일의 내용을 읽어보자.
*/
@Test
void 파일의_내용을_읽는다() {
void 파일의_내용을_읽는다() throws IOException {
final String fileName = "nextstep.txt";
final URL url = getClass().getClassLoader().getResource(fileName);

// todo
final Path path = null;
final Path path = new File(url.getFile()).toPath();

// todo
final List<String> actual = Collections.emptyList();
final List<String> actual = Files.readAllLines(path);

assertThat(actual).containsOnly("nextstep");
}
Expand Down
21 changes: 16 additions & 5 deletions study/src/test/java/study/IOStreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class OutputStream_학습_테스트 {
* todo
* OutputStream 객체의 write 메서드를 사용해서 테스트를 통과시킨다
*/
outputStream.write(bytes);

final String actual = outputStream.toString();

Expand All @@ -78,6 +79,7 @@ class OutputStream_학습_테스트 {
* flush를 사용해서 테스트를 통과시킨다.
* ByteArrayOutputStream과 어떤 차이가 있을까?
*/
outputStream.flush();

verify(outputStream, atLeastOnce()).flush();
outputStream.close();
Expand All @@ -96,6 +98,8 @@ class OutputStream_학습_테스트 {
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
try (outputStream) {
}

verify(outputStream, atLeastOnce()).close();
}
Expand Down Expand Up @@ -128,7 +132,7 @@ class InputStream_학습_테스트 {
* todo
* inputStream에서 바이트로 반환한 값을 문자열로 어떻게 바꿀까?
*/
final String actual = "";
final String actual = new String(inputStream.readAllBytes());

assertThat(actual).isEqualTo("🤩");
assertThat(inputStream.read()).isEqualTo(-1);
Expand All @@ -148,6 +152,8 @@ class InputStream_학습_테스트 {
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
try (inputStream) {
}

verify(inputStream, atLeastOnce()).close();
}
Expand All @@ -169,12 +175,12 @@ class FilterStream_학습_테스트 {
* 버퍼 크기를 지정하지 않으면 버퍼의 기본 사이즈는 얼마일까?
*/
@Test
void 필터인_BufferedInputStream를_사용해보자() {
void 필터인_BufferedInputStream를_사용해보자() throws IOException {
final String text = "필터에 연결해보자.";
final InputStream inputStream = new ByteArrayInputStream(text.getBytes());
final InputStream bufferedInputStream = null;
final InputStream bufferedInputStream = new BufferedInputStream(inputStream);

final byte[] actual = new byte[0];
final byte[] actual = bufferedInputStream.readAllBytes();

assertThat(bufferedInputStream).isInstanceOf(FilterInputStream.class);
assertThat(actual).isEqualTo("필터에 연결해보자.".getBytes());
Expand All @@ -197,15 +203,20 @@ class InputStreamReader_학습_테스트 {
* 필터인 BufferedReader를 사용하면 readLine 메서드를 사용해서 문자열(String)을 한 줄 씩 읽어올 수 있다.
*/
@Test
void BufferedReader를_사용하여_문자열을_읽어온다() {
void BufferedReader를_사용하여_문자열을_읽어온다() throws IOException {
final String emoji = String.join("\r\n",
"😀😃😄😁😆😅😂🤣🥲☺️😊",
"😇🙂🙃😉😌😍🥰😘😗😙😚",
"😋😛😝😜🤪🤨🧐🤓😎🥸🤩",
"");
final InputStream inputStream = new ByteArrayInputStream(emoji.getBytes());
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

final StringBuilder actual = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
actual.append(line).append("\r\n");
}

assertThat(actual).hasToString(emoji);
}
Expand Down
1 change: 1 addition & 0 deletions tomcat/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {
testImplementation 'org.mockito:mockito-core:5.12.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
}

test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@ public static Optional<User> findByAccount(String account) {
return Optional.ofNullable(database.get(account));
}

public static void delete(User user) {
database.remove(user.getAccount());
}

private InMemoryUserRepository() {}
}
22 changes: 22 additions & 0 deletions tomcat/src/main/java/com/techcourse/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ public class User {
private final String email;

public User(Long id, String account, String password, String email) {
validateAccount(account);
validatePassword(password);
validateEmail(email);

this.id = id;
this.account = account;
this.password = password;
Expand All @@ -18,6 +22,24 @@ public User(String account, String password, String email) {
this(null, account, password, email);
}

private void validateAccount(String account) {
if (account == null || account.isBlank()) {
throw new IllegalArgumentException("account는 비어 있을 수 없습니다.");
}
}

private void validatePassword(String password) {
if (password == null || password.isBlank()) {
throw new IllegalArgumentException("password는 비어 있을 수 없습니다.");
}
}

private void validateEmail(String email) {
if (email == null || email.isBlank()) {
throw new IllegalArgumentException("email은 비어 있을 수 없습니다.");
}
}

public boolean checkPassword(String password) {
return this.password.equals(password);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.apache.catalina.connector;

import org.apache.catalina.session.UuidSessionGenerator;
import org.apache.coyote.http11.Http11Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -66,7 +67,7 @@ private void process(final Socket connection) {
if (connection == null) {
return;
}
var processor = new Http11Processor(connection);
var processor = new Http11Processor(connection, new UuidSessionGenerator());
new Thread(processor).start();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
package org.apache.catalina;

import jakarta.servlet.http.HttpSession;
package org.apache.catalina.session;

import java.io.IOException;

Expand Down Expand Up @@ -29,7 +27,7 @@ public interface Manager {
*
* @param session Session to be added
*/
void add(HttpSession session);
void add(Session session);

/**
* Return the active Session, associated with this Manager, with the
Expand All @@ -45,12 +43,12 @@ public interface Manager {
* @return the request session or {@code null} if a session with the
* requested ID could not be found
*/
HttpSession findSession(String id) throws IOException;
Session findSession(String id);

/**
* Remove this Session from the active Sessions for this Manager.
*
* @param session Session to be removed
*/
void remove(HttpSession session);
void remove(Session session);
}
38 changes: 38 additions & 0 deletions tomcat/src/main/java/org/apache/catalina/session/Session.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.apache.catalina.session;

import java.util.HashMap;
import java.util.Map;

public class Session {

private final String id;
private final Map<String, Object> values = new HashMap<>();

public Session(String id) {
this.id = id;
}

public boolean contains(String name) {
return getAttribute(name) != null;
}

public Object getAttribute(String name) {
return values.get(name);
}

public void setAttribute(String name, Object value) {
values.put(name, value);
}

public void removeAttribute(String name) {
values.remove(name);
}

public void invalidate() {
values.clear();
}

public String getId() {
return id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.apache.catalina.session;

@FunctionalInterface
public interface SessionGenerator {
Session create();
}
Loading

0 comments on commit 728632e

Please sign in to comment.