-
Notifications
You must be signed in to change notification settings - Fork 90
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단계 - HTTP 웹서버 구현 미션 제출합니다. #191
base: parkdoowon
Are you sure you want to change the base?
Changes from all commits
3be38af
8a18e29
8b36735
849c287
dcd59ce
4487ef2
bd2af82
14dbb9a
2212f14
6db7ebd
6f33086
779c10a
1c7184d
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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package dto; | ||
|
||
import java.util.List; | ||
|
||
import model.User; | ||
|
||
public class Users { | ||
private List<User> users; | ||
|
||
public Users(List<User> users) { | ||
this.users = users; | ||
} | ||
|
||
public List<User> getUsers() { | ||
return users; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package webserver; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class HttpCookie { | ||
private static final String COOKIE_DELIMITER = "; "; | ||
private static final String VALUE_DELIMITER = "="; | ||
|
||
private final Map<String, String> cookies; | ||
|
||
public HttpCookie(String allCookies) { | ||
Map<String, String> cookies = new HashMap<>(); | ||
for (String cookie : allCookies.split(COOKIE_DELIMITER)) { | ||
String[] cookieSet = cookie.split(VALUE_DELIMITER); | ||
cookies.put(cookieSet[0], cookieSet[1]); | ||
} | ||
this.cookies = cookies; | ||
} | ||
|
||
public String getCookie(String cookieName) { | ||
return cookies.get(cookieName); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package webserver; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
public class HttpSession { | ||
private final String id; | ||
private final Map<String, Object> attributes = new HashMap<>(); | ||
|
||
public HttpSession(String id) { | ||
this.id = id; | ||
} | ||
|
||
public String getId() { | ||
return this.id; | ||
} | ||
|
||
public void setAttribute(String name, Object value) { | ||
this.attributes.put(name, value); | ||
} | ||
|
||
public Object getAttribute(String name) { | ||
return this.attributes.get(name); | ||
} | ||
|
||
public void removeAttribute(String name) { | ||
this.attributes.remove(name); | ||
} | ||
|
||
public void invalidate() { | ||
this.attributes.clear(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package webserver; | ||
|
||
import java.util.Arrays; | ||
|
||
public enum LoginStatus { | ||
SUCCESS("/index.html", true), | ||
FAIL("/user/login_failed.html", false); | ||
|
||
private final String redirectUrl; | ||
private final boolean validated; | ||
|
||
LoginStatus(String redirectUrl, boolean validated) { | ||
this.redirectUrl = redirectUrl; | ||
this.validated = validated; | ||
} | ||
|
||
public static LoginStatus of(boolean validated) { | ||
return Arrays.stream(LoginStatus.values()) | ||
.filter(loginStatus -> loginStatus.validated == validated) | ||
.findFirst() | ||
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 로그인 상태입니다.")); | ||
} | ||
|
||
public String getRedirectUrl() { | ||
return redirectUrl; | ||
} | ||
|
||
public boolean isValidated() { | ||
return validated; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package webserver; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.UUID; | ||
|
||
public class SessionStorage { | ||
private static final Map<String, HttpSession> sessions = new HashMap<>(); | ||
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. 웹서버는 멀티스레드로 동작하는데 static 타입의 필드를 접근시 Thread Safe 할까요? 🤔 |
||
|
||
public static HttpSession getSession(String id) { | ||
if (Objects.isNull(id)) { | ||
id = UUID.randomUUID().toString(); | ||
} | ||
if (!sessions.containsKey(id)) { | ||
sessions.put(id, new HttpSession(id)); | ||
} | ||
return sessions.get(id); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package webserver.handler; | ||
|
||
import java.io.DataOutputStream; | ||
import java.io.IOException; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
|
||
import db.DataBase; | ||
import model.User; | ||
import utils.ExtractUtils; | ||
import webserver.HttpCookie; | ||
import webserver.HttpRequest; | ||
import webserver.HttpResponse; | ||
import webserver.HttpSession; | ||
import webserver.LoginStatus; | ||
import webserver.SessionStorage; | ||
|
||
public class LoginHandler extends Handler { | ||
private static final String USER_LOGIN_URL = "/user/login"; | ||
|
||
@Override | ||
public void handleRequest(HttpRequest httpRequest, DataOutputStream dos) throws IOException { | ||
Map<String, String> loginInfo = ExtractUtils.parseRequestBody(httpRequest.getBody()); | ||
String userId = loginInfo.get("userId"); | ||
String password = loginInfo.get("password"); | ||
User user = Optional.ofNullable(DataBase.findUserById(userId)) | ||
.orElseThrow(() -> new IllegalArgumentException("해당 유저가 없습니다.")); | ||
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. 로그인 실패시 |
||
LoginStatus loginStatus = LoginStatus.of(user.validatePassword(password)); | ||
HttpCookie httpCookie = new HttpCookie(httpRequest.getHeader("Cookie")); | ||
HttpSession httpSession = SessionStorage.getSession(httpCookie.getCookie("sessionId")); | ||
httpSession.setAttribute("logined", true); | ||
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. 미션 요구사항은 cookie에다 logind 값을 지정하도록 되어있는데 세션에 담은 이유가 있나요? |
||
|
||
HttpResponse.responseLogin302Header(dos, loginStatus, httpSession, logger); | ||
} | ||
|
||
@Override | ||
public boolean canHandle(String url) { | ||
return USER_LOGIN_URL.equals(url); | ||
} | ||
} |
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.
단순히 값들을 삭제할 뿐만 아니라 invalidated 된 Session은 사용 할 수 없는 것으로 알고 있어요.
혹시 모르니 조금 더 찾아보세요! :)
https://love2taeyeon.tistory.com/entry/invalidate%EC%9D%80-%EC%84%B8%EC%85%98%EC%9D%84-%EC%86%8C%EB%A9%B8%EC%8B%9C%ED%82%A4%EB%8A%94-%EA%B2%83%EC%9D%B4-%EC%95%84%EB%8B%88%EB%9D%BC-%EB%AC%B4%ED%9A%A8%ED%99%94-%EC%8B%9C%ED%82%AC%EB%BF%90%EC%9D%B4%EB%8B%A4