-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from sanhee/header-and-body
Header와 Body 구현
- Loading branch information
Showing
9 changed files
with
420 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package webserver; | ||
|
||
import java.nio.charset.Charset; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
public class Body { | ||
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8; | ||
|
||
private byte[] data; | ||
|
||
private Body(byte[] data) { | ||
this.data = data; | ||
} | ||
|
||
public static Body create(String bodyText) { | ||
return new Body(bodyText.getBytes(DEFAULT_ENCODING)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package webserver; | ||
|
||
import util.HttpRequestUtils; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
|
||
public abstract class Header { | ||
protected static final String PROTOCOL_VERSION_KEY = "protocolVersion"; | ||
|
||
protected Map<String, String> statusLineAttributes; | ||
private Map<String, String> attributes; | ||
|
||
public Header(Map<String, String> attributes) { | ||
this.attributes = attributes; | ||
this.statusLineAttributes = new HashMap<>(); | ||
} | ||
|
||
public static Header of(String headerText, String type) { | ||
Map<String, String> attributes = attributeFrom(headerText); | ||
|
||
String[] splittedHeaderTexts = headerText.split(System.lineSeparator()); | ||
String[] statusLine = splittedHeaderTexts[0].split(" "); | ||
|
||
Header header = of(attributes, type); | ||
header.putStatusLine(statusLine); | ||
|
||
return header; | ||
} | ||
|
||
private static Header of(Map<String, String> attributes, String type) { | ||
switch (type) { | ||
case "request": | ||
return new RequestHeader(attributes); | ||
case "response": | ||
return new ResponseHeader(attributes); | ||
default: | ||
throw new IllegalStateException("Unexpected value: " + type); | ||
} | ||
} | ||
|
||
private static Map<String, String> attributeFrom(String headerText) { | ||
Map<String, String> attributes = new LinkedHashMap<>(); | ||
|
||
String[] splittedHeaderTexts = headerText.split(System.lineSeparator()); | ||
for (String splittedHeaderText : splittedHeaderTexts) { | ||
HttpRequestUtils.Pair pair = HttpRequestUtils.parseHeader(splittedHeaderText); | ||
|
||
if (pair != null) { | ||
attributes.put(pair.getKey(), pair.getValue()); | ||
} | ||
} | ||
|
||
return attributes; | ||
} | ||
|
||
protected abstract void putStatusLine(String[] statusLine); | ||
|
||
public Map<String, String> getAttributes() { | ||
return attributes; | ||
} | ||
|
||
public Map<String, String> getStatusLineAttributes() { | ||
return statusLineAttributes; | ||
} | ||
|
||
public byte[] toByte() { | ||
StringBuilder sb = new StringBuilder(); | ||
|
||
sb.append(statusLine()).append(System.lineSeparator()); | ||
|
||
for (Map.Entry<String, String> entry : getAttributes().entrySet()) { | ||
sb.append(entry.getKey() + ": " + entry.getValue() + System.lineSeparator()); | ||
} | ||
|
||
sb.append(System.lineSeparator()); | ||
|
||
return sb.toString().getBytes(StandardCharsets.UTF_8); | ||
} | ||
|
||
protected abstract String statusLine(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package webserver; | ||
|
||
import java.util.Map; | ||
|
||
public class RequestHeader extends Header { | ||
private static final String METHOD_KEY = "method"; | ||
private static final String PATH_KEY = "path"; | ||
|
||
public RequestHeader(Map<String, String> attributes) { | ||
super(attributes); | ||
} | ||
|
||
@Override | ||
protected void putStatusLine(String[] statusLine) { | ||
statusLineAttributes.put(METHOD_KEY, statusLine[0]); | ||
statusLineAttributes.put(PATH_KEY, statusLine[1]); | ||
statusLineAttributes.put(PROTOCOL_VERSION_KEY, statusLine[2]); | ||
} | ||
|
||
@Override | ||
protected String statusLine() { | ||
return statusLineAttributes.get(METHOD_KEY) + " " + statusLineAttributes.get(PATH_KEY) + " " + statusLineAttributes.get(PROTOCOL_VERSION_KEY); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package webserver; | ||
|
||
import java.util.Map; | ||
|
||
public class ResponseHeader extends Header { | ||
private static final String STATUS_CODE_KEY = "statusCode"; | ||
private static final String STATUS_TEXT_KEY = "statusText"; | ||
|
||
public ResponseHeader(Map<String, String> attributes) { | ||
super(attributes); | ||
} | ||
|
||
@Override | ||
protected void putStatusLine(String[] statusLine) { | ||
statusLineAttributes.put(PROTOCOL_VERSION_KEY, statusLine[0]); | ||
statusLineAttributes.put(STATUS_CODE_KEY, statusLine[1]); | ||
statusLineAttributes.put(STATUS_TEXT_KEY, statusLine[2]); | ||
} | ||
|
||
@Override | ||
protected String statusLine() { | ||
return statusLineAttributes.get(PROTOCOL_VERSION_KEY) + " " + statusLineAttributes.get(STATUS_CODE_KEY) + " " + statusLineAttributes.get(STATUS_TEXT_KEY); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package webserver; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
class BodyTest { | ||
|
||
@Test | ||
void init() { | ||
String data = "Hello World"; | ||
Body expected = Body.create(data); | ||
|
||
Body body = Body.create(data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package webserver; | ||
|
||
class HeaderTest { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package webserver; | ||
|
||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
import java.util.stream.Stream; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertAll; | ||
|
||
class RequestHeaderTest { | ||
|
||
@ParameterizedTest | ||
@MethodSource | ||
void getAttributes(String headerText, Map<String, String> expectedAttributes) { | ||
assertThat(Header.of(headerText, "request").getAttributes()) | ||
.isEqualTo(expectedAttributes); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
static Stream<Arguments> getAttributes() { | ||
return Stream.of( | ||
Arguments.of("GET / HTTP/1.1" + System.lineSeparator() + | ||
"Host: localhost:8080" + System.lineSeparator() + | ||
"Connection: keep-alive" + System.lineSeparator() + | ||
"Cache-Control: max-age=0" + System.lineSeparator() + | ||
"sec-ch-ua: \"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"" + System.lineSeparator() + | ||
"sec-ch-ua-mobile: ?0" + System.lineSeparator() + | ||
"Upgrade-Insecure-Requests: 1" + System.lineSeparator() + | ||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" + System.lineSeparator() + | ||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" + System.lineSeparator() + | ||
"Sec-Fetch-Site: none" + System.lineSeparator() + | ||
"Sec-Fetch-Mode: navigate" + System.lineSeparator() + | ||
"Sec-Fetch-User: ?1" + System.lineSeparator() + | ||
"Sec-Fetch-Dest: document" + System.lineSeparator() + | ||
"Accept-Encoding: gzip, deflate, br" + System.lineSeparator() + | ||
"Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7" + System.lineSeparator() + | ||
"Cookie: Idea-1c77831=5ced54c8-cabd-4355-ae5a-97b17f9d7443" + System.lineSeparator() + | ||
System.lineSeparator(), | ||
new LinkedHashMap() {{ | ||
put("Host", "localhost:8080"); | ||
put("Connection", "keep-alive"); | ||
put("Cache-Control", "max-age=0"); | ||
put("sec-ch-ua", "\"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\""); | ||
put("sec-ch-ua-mobile", "?0"); | ||
put("Upgrade-Insecure-Requests", "1"); | ||
put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36"); | ||
put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"); | ||
put("Sec-Fetch-Site", "none"); | ||
put("Sec-Fetch-Mode", "navigate"); | ||
put("Sec-Fetch-User", "?1"); | ||
put("Sec-Fetch-Dest", "document"); | ||
put("Accept-Encoding", "gzip, deflate, br"); | ||
put("Accept-Language", "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7"); | ||
put("Cookie", "Idea-1c77831=5ced54c8-cabd-4355-ae5a-97b17f9d7443"); | ||
}} | ||
) | ||
); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource | ||
void getStatusLineAttributes(String headerText, Map<String, String> expectedAttributes) { | ||
assertThat(Header.of(headerText, "request").getStatusLineAttributes()) | ||
.isEqualTo(expectedAttributes); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
static Stream<Arguments> getStatusLineAttributes() { | ||
return Stream.of( | ||
Arguments.of("GET / HTTP/1.1" + System.lineSeparator() + | ||
"Host: localhost:8080" + System.lineSeparator() + | ||
"Connection: keep-alive" + System.lineSeparator() + | ||
"Cache-Control: max-age=0" + System.lineSeparator() + | ||
"sec-ch-ua: \"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"" + System.lineSeparator() + | ||
"sec-ch-ua-mobile: ?0" + System.lineSeparator() + | ||
"Upgrade-Insecure-Requests: 1" + System.lineSeparator() + | ||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" + System.lineSeparator() + | ||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" + System.lineSeparator() + | ||
"Sec-Fetch-Site: none" + System.lineSeparator() + | ||
"Sec-Fetch-Mode: navigate" + System.lineSeparator() + | ||
"Sec-Fetch-User: ?1" + System.lineSeparator() + | ||
"Sec-Fetch-Dest: document" + System.lineSeparator() + | ||
"Accept-Encoding: gzip, deflate, br" + System.lineSeparator() + | ||
"Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7" + System.lineSeparator() + | ||
"Cookie: Idea-1c77831=5ced54c8-cabd-4355-ae5a-97b17f9d7443" + System.lineSeparator() + | ||
System.lineSeparator(), | ||
new HashMap() {{ | ||
put("method", "GET"); | ||
put("path", "/"); | ||
put("protocolVersion", "HTTP/1.1"); | ||
}} | ||
) | ||
); | ||
} | ||
|
||
@ParameterizedTest | ||
@MethodSource | ||
void toByte(String headerText, byte[] expectedHeaderByte) { | ||
byte[] headerByte = Header.of(headerText, "request").toByte(); | ||
|
||
assertAll( | ||
() -> assertThat(headerByte).isEqualTo(expectedHeaderByte), | ||
() -> assertThat(new String(headerByte)).isEqualTo(new String(expectedHeaderByte)) | ||
); | ||
|
||
} | ||
|
||
@SuppressWarnings("unused") | ||
static Stream<Arguments> toByte() { | ||
return Stream.of( | ||
Arguments.of( | ||
"GET / HTTP/1.1" + System.lineSeparator() + | ||
"Host: localhost:8080" + System.lineSeparator() + | ||
"Connection: keep-alive" + System.lineSeparator() + | ||
"Cache-Control: max-age=0" + System.lineSeparator() + | ||
"sec-ch-ua: \"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"" + System.lineSeparator() + | ||
"sec-ch-ua-mobile: ?0" + System.lineSeparator() + | ||
"Upgrade-Insecure-Requests: 1" + System.lineSeparator() + | ||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" + System.lineSeparator() + | ||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" + System.lineSeparator() + | ||
"Sec-Fetch-Site: none" + System.lineSeparator() + | ||
"Sec-Fetch-Mode: navigate" + System.lineSeparator() + | ||
"Sec-Fetch-User: ?1" + System.lineSeparator() + | ||
"Sec-Fetch-Dest: document" + System.lineSeparator() + | ||
"Accept-Encoding: gzip, deflate, br" + System.lineSeparator() + | ||
"Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7" + System.lineSeparator() + | ||
"Cookie: Idea-1c77831=5ced54c8-cabd-4355-ae5a-97b17f9d7443" + System.lineSeparator() + | ||
System.lineSeparator(), | ||
("GET / HTTP/1.1" + System.lineSeparator() + | ||
"Host: localhost:8080" + System.lineSeparator() + | ||
"Connection: keep-alive" + System.lineSeparator() + | ||
"Cache-Control: max-age=0" + System.lineSeparator() + | ||
"sec-ch-ua: \"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"" + System.lineSeparator() + | ||
"sec-ch-ua-mobile: ?0" + System.lineSeparator() + | ||
"Upgrade-Insecure-Requests: 1" + System.lineSeparator() + | ||
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" + System.lineSeparator() + | ||
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" + System.lineSeparator() + | ||
"Sec-Fetch-Site: none" + System.lineSeparator() + | ||
"Sec-Fetch-Mode: navigate" + System.lineSeparator() + | ||
"Sec-Fetch-User: ?1" + System.lineSeparator() + | ||
"Sec-Fetch-Dest: document" + System.lineSeparator() + | ||
"Accept-Encoding: gzip, deflate, br" + System.lineSeparator() + | ||
"Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7" + System.lineSeparator() + | ||
"Cookie: Idea-1c77831=5ced54c8-cabd-4355-ae5a-97b17f9d7443" + System.lineSeparator() + | ||
System.lineSeparator()).getBytes(StandardCharsets.UTF_8) | ||
) | ||
); | ||
} | ||
} |
Oops, something went wrong.