forked from softeerbootcamp4th/be-was-2024
-
Notifications
You must be signed in to change notification settings - Fork 0
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 #1 from eckrin/week3/feature1
remote 커밋내역 머지
- Loading branch information
Showing
55 changed files
with
2,534 additions
and
210 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,49 @@ | ||
package common; | ||
|
||
import file.ViewFile; | ||
import web.HttpRequest; | ||
|
||
import java.io.BufferedOutputStream; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.util.UUID; | ||
|
||
/** | ||
* 파일 저장, 확장자 추출, 파일 생성 등을 담당하는 유틸리티 클래스 | ||
*/ | ||
public class FileUtils { | ||
|
||
public static final String STATIC_DIR_PATH = "./src/main/resources/static"; | ||
public static final String MY_ARTICLE_PATH = "/eckrin/"; | ||
|
||
public static String getStaticFilePath(String path) { | ||
return STATIC_DIR_PATH+path; | ||
} | ||
|
||
public static String getExtensionFromPath(String path) { | ||
return path.split("\\.")[1]; | ||
} | ||
|
||
public static String getImageExtensionFromPath(String body) { | ||
String[] bodySplit = body.split("image/"); | ||
if(bodySplit.length>=2) return bodySplit[1]; | ||
else return null; | ||
} | ||
|
||
public static ViewFile makeFileFromRequest(HttpRequest request) { | ||
String filePath = request.getPath(); | ||
String extension = FileUtils.getExtensionFromPath(filePath); | ||
|
||
return new ViewFile(filePath, extension); | ||
} | ||
|
||
public static String saveFile(byte[] data, String extension) { | ||
String fileName = UUID.randomUUID()+"."+extension; | ||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(STATIC_DIR_PATH+ MY_ARTICLE_PATH+fileName))) { | ||
bos.write(data); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
return fileName; | ||
} | ||
} |
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,27 @@ | ||
package common; | ||
|
||
import model.User; | ||
|
||
import java.util.Collection; | ||
|
||
/** | ||
* User 리스트를 Json으로 반환하기 위한 빌더 클래스 | ||
*/ | ||
public class JsonBuilder { | ||
|
||
public static String buildJsonResponse(Collection<User> users) { | ||
StringBuilder jsonResponse = new StringBuilder("["); | ||
for (User user : users) { | ||
jsonResponse.append("{") | ||
.append("\"userId\":\"").append(user.getUserId()).append("\",") | ||
.append("\"name\":\"").append(user.getName()).append("\",") | ||
.append("\"password\":\"").append(user.getPassword()).append("\"") | ||
.append("},"); | ||
} | ||
if (jsonResponse.length() > 1) { | ||
jsonResponse.setLength(jsonResponse.length() - 1); // 마지막 쉼표 제거 | ||
} | ||
jsonResponse.append("]"); | ||
return jsonResponse.toString(); | ||
} | ||
} |
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,161 @@ | ||
package common; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import web.HeaderKey; | ||
import web.HttpMethod; | ||
import web.HttpRequest; | ||
import web.MIME; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.LinkedList; | ||
import java.util.Map; | ||
|
||
/** | ||
* Request를 파싱하여 Request Line, Header, Body를 추출하는 클래스 | ||
* Header와 Body는 \r\n\r\n으로 구분하며, 헤더의 Content-Length값에 따라서 Body를 읽는다. | ||
*/ | ||
public class RequestUtils { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(RequestUtils.class); | ||
|
||
/** | ||
* InputStream에서 Request를 String형태로 읽어온 후, HttpRequest를 만들어 반환한다. | ||
* body는 byte[]형태로 받아온다. | ||
*/ | ||
public static HttpRequest parseHttpRequest(InputStream in) throws IOException { | ||
final int TMP_BUFFER_SIZE = 1024; | ||
|
||
int ch; | ||
StringBuffer sb = new StringBuffer(); | ||
int contentLength = 0; | ||
byte[] body = null; | ||
|
||
// Request Line부터 Body 전까지 읽는다 | ||
// Request Line과 Body 사이에는 '\r\n'이 두번 오게 된다. | ||
boolean lastWasCR = false; | ||
boolean lastWasLF = false; | ||
while((ch = in.read())!=-1) { | ||
sb.append((char) ch); | ||
|
||
if(ch=='\r') { | ||
lastWasCR = true; | ||
} else if (ch=='\n') { | ||
if(lastWasCR && lastWasLF) { | ||
break; | ||
} | ||
lastWasLF = true; | ||
} else { | ||
lastWasCR = false; | ||
lastWasLF = false; | ||
} | ||
} | ||
|
||
// Content-Length 헤더 찾기 | ||
String header = sb.toString(); | ||
String[] headerLines = header.split("\r\n"); | ||
for(String line: headerLines) { | ||
if(line.toLowerCase().startsWith(HeaderKey.CONTENT_LENGTH.getKey())) { | ||
contentLength = Integer.parseInt(line.split(":")[1].trim()); | ||
break; | ||
} | ||
} | ||
logger.debug("{}", sb); | ||
|
||
StringBuffer sbb = new StringBuffer(); | ||
// Content-Length가 0보다 크다면 body까지 읽어서 로그에 출력한다. | ||
if (contentLength > 0) { | ||
body = new byte[contentLength]; | ||
int bytesRead = 0; | ||
int offset = 0; | ||
|
||
while (bytesRead < contentLength) { | ||
int bytesToRead = Math.min(TMP_BUFFER_SIZE, contentLength - bytesRead); | ||
int readSize = in.read(body, offset, bytesToRead); | ||
|
||
if (readSize == -1) { | ||
throw new IOException("Unexpected end of input stream while reading body"); | ||
} | ||
|
||
bytesRead += readSize; | ||
offset += readSize; | ||
} | ||
|
||
sbb.append(new String(body)).append("\n"); | ||
} | ||
|
||
// logger.debug("{}", sbb); | ||
|
||
return parseRequest(sb.toString(), body); | ||
} | ||
|
||
/** | ||
* request로 들어온 HTTP 요청을 한줄씩 파싱하여 적절한 HttpRequest 객체를 생성 | ||
* @param request Request Line과 Header | ||
* @param body request body (byte[]) | ||
* @return HttpRequest | ||
*/ | ||
private static HttpRequest parseRequest(String request, byte[] body) { | ||
HttpMethod method; | ||
String path, contentType = MIME.UNKNOWN.getType(); | ||
LinkedList<String> accept = new LinkedList<>(); | ||
int contentLength = 0; | ||
Map<String, String> cookie = new HashMap<>(); | ||
|
||
String[] requestLine = request.split("\n"); | ||
|
||
// Request Line | ||
String[] line_1 = requestLine[0].split(" "); | ||
method = HttpMethod.valueOf(line_1[0]); | ||
path = line_1[1]; | ||
|
||
// Header | ||
for(int i=1; i<requestLine.length; i++) { | ||
if(requestLine[i].split(":").length==1) continue; | ||
String[] line_N = requestLine[i].split(":"); | ||
String key = line_N[0].trim(); | ||
String value = line_N[1].trim(); | ||
|
||
// Accept헤더 MimeType 설정 | ||
if(key.equalsIgnoreCase(HeaderKey.ACCEPT.getKey())) { | ||
String[] acceptLine = value.split(";"); | ||
String[] mimeType = acceptLine[0].split(","); | ||
accept.addAll(Arrays.asList(mimeType)); | ||
} else if(key.equalsIgnoreCase(HeaderKey.CONTENT_LENGTH.getKey())) { | ||
contentLength = Integer.parseInt(value); | ||
} else if(key.equalsIgnoreCase(HeaderKey.CONTENT_TYPE.getKey())) { | ||
contentType = value; | ||
} else if(key.equalsIgnoreCase(HeaderKey.COOKIE.getKey())) { | ||
String[] cookies = value.split(";"); | ||
for(String c: cookies) { | ||
String cookieName = c.split("=")[0].trim(); | ||
String cookieId = c.split("=")[1].trim(); | ||
cookie.put(cookieName, cookieId); | ||
} | ||
} | ||
} | ||
|
||
return new HttpRequest.HttpRequestBuilder() | ||
.method(method) | ||
.path(path) | ||
.accept(accept) | ||
.contentLength(contentLength) | ||
.contentType(contentType) | ||
.cookie(cookie) | ||
.body(body) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Multipart 파일의 Body 구분자를 추출하기 위한 메서드 | ||
* @param contentType Request 헤더의 Content-Type | ||
* @return Body Delimiter | ||
*/ | ||
public static String getBoundaryKey(String contentType) { | ||
return contentType.split("boundary=")[1]; | ||
} | ||
} | ||
|
Oops, something went wrong.