# 강남_P_Day16 리뷰 레포트 ### 참석자 - 고승빈, 김재호, 김웅기, 나영균 ## 1. 코드 동작 이해 ``` - 가장 많은 체크포인트를 구현한 사람의 코드의 동작 원리를 이해하는 과정에서 발생한 건설적인 대화를 기록, 정리합니다. ``` - URL 문자열을 URL 객체에 넣어 parse된 데이터를 프로퍼티로 유지한다. - URL객체를 Request객체로 넣어 ip address를 DNS를 통해 얻어낸다. 비동기로 이루어져 비동기 제어가 필요하다. - Request객체는 ip address와 URL의 port정보를 가지고 net모듈의 createConnection 메소드를 통해 socket을 생성한다. - socket은 write 메소드를 통해 Http Request헤더를 보낸다. - server가 보내는 data를 data 이벤트를 통해 Response객체의 Buffer에 저장한다. - Response 객체는 자체 메소드를 통해 Response resource를 관리한다. - Response 가 모든 정보가 들어왔는지는 socket의 end를 이용해 확인하고 실질적으로 자원이 모두 온 경우, end Event 발생한다. - 모든 자원이 들어온 경우 end에서 시간을 초기화하여 시간이 3초가 지난 경우 강제로 close 한다. ## 2. 코드 동작 개선 ### 고승빈 #### 코드 동작 개선 - 까다로운 URL 정규 표현식을 적용하지 못하며, 조건문을 이용해 각 컴포넌트를 추출하였다. => URL를 정규 표현식으로 이용한다면, 예외적인 조건도 쉽게 이용할 수 있고 원하는 문자열을 추출할 수 있을 것으로 보인다. #### 스스로 확인할 사항 * URL 구성 요소에 대해 학습한다. URL은 네트워크 공간에서의 Resource를 식별하는 URI 방식 중 하나이다. URL은 Scheme, User, Password, Host, Port, Path, QueryString으로 구성된다. Scheme에 따라 각 컴포넌트에 적용되는 규격이 달라진다. 해당 각각의 규격은 [RFC 1738](https://tools.ietf.org/html/rfc1738) 에서 참고가 가능하다. * 다양한 URL 케이스를 어떻게 처리하는지 확인한 방법을 정리한다. 정규 표현식을 이용해 URL 케이스를 다룰 수 있다. HTTP 프로토콜 경우에는 아래와 같은 정리할 수 있다. > http://<host>:<port>/<path>?<searchpart> - 공통 규격 ``` genericurl = scheme ":" schemepart ; Specific predefined schemes are defined here; new schemes ; may be registered with IANA url = httpurl | ftpurl | newsurl | nntpurl | telneturl | gopherurl | waisurl | mailtourl | fileurl | prosperourl | otherurl ; new schemes follow the general syntax otherurl = genericurl ; the scheme is in lower case; interpreters should use case-ignore scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] schemepart = *xchar | ip-schemepart ; URL schemeparts for ip based protocols: ip-schemepart = "//" login [ "/" urlpath ] login = [ user [ ":" password ] "@" ] hostport hostport = host [ ":" port ] host = hostname | hostnumber hostname = *[ domainlabel "." ] toplabel domainlabel = alphadigit | alphadigit *[ alphadigit | "-" ] alphadigit toplabel = alpha | alpha *[ alphadigit | "-" ] alphadigit alphadigit = alpha | digit hostnumber = digits "." digits "." digits "." digits port = digits user = *[ uchar | ";" | "?" | "&" | "=" ] password = *[ uchar | ";" | "?" | "&" | "=" ] urlpath = *xchar ; depends on protocol see section 3.1 ``` - HTTP 규격 ``` httpurl = "http://" hostport [ "/" hpath [ "?" search ]] hpath = hsegment *[ "/" hsegment ] hsegment = *[ uchar | ";" | ":" | "@" | "&" | "=" ] search = *[ uchar | ";" | ":" | "@" | "&" | "=" ] ``` * HTTP Request 종류와 HTTP Response 종류에 대해 학습하고 정리한다. --- ### 김재호 #### 코드 동작 개선 - 정규식으로 인한 String 분석이 잘 되지 않는다. 정규식을 분석하여 어디 부분의 정규식이 제대로 작성되지 않는지 알아보아야 한다. - response 완료 후 3초후 프로그램 종료하는 기능이 누락되었다. - Http 보안에 따라 분석이 달리 동작해야 하지만 그런 부분이 부족 #### 스스로 확인할 사항 * URL 구성 요소에 대해 학습한다. `<스킴>://<사용자이름>:<비밀번호>@<호스트>:<포트>/<경로>?<질의>#<프레그먼트>` 출처 : [victolee - URI, URL 구조](https://victorydntmd.tistory.com/287) * 다양한 URL 케이스를 어떻게 처리하는지 확인한 방법을 정리한다. - URL Case를 정규식으로 처리 ``` lex ; The generic form of a URL is: genericurl = scheme ":" schemepart ; Specific predefined schemes are defined here; new schemes ; may be registered with IANA url = httpurl | ftpurl | newsurl | nntpurl | telneturl | gopherurl | waisurl | mailtourl | fileurl | prosperourl | otherurl ; new schemes follow the general syntax otherurl = genericurl ; the scheme is in lower case; interpreters should use case-ignore scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] schemepart = *xchar | ip-schemepart ; URL schemeparts for ip based protocols: ip-schemepart = "//" login [ "/" urlpath ] login = [ user [ ":" password ] "@" ] hostport hostport = host [ ":" port ] host = hostname | hostnumber hostname = *[ domainlabel "." ] toplabel domainlabel = alphadigit | alphadigit *[ alphadigit | "-" ] alphadigit toplabel = alpha | alpha *[ alphadigit | "-" ] alphadigit alphadigit = alpha | digit hostnumber = digits "." digits "." digits "." digits port = digits user = *[ uchar | ";" | "?" | "&" | "=" ] password = *[ uchar | ";" | "?" | "&" | "=" ] urlpath = *xchar ; depends on protocol see section 3.1 ; The predefined schemes: ; FTP (see also RFC959) ftpurl = "ftp://" login [ "/" fpath [ ";type=" ftptype ]] fpath = fsegment *[ "/" fsegment ] fsegment = *[ uchar | "?" | ":" | "@" | "&" | "=" ] ftptype = "A" | "I" | "D" | "a" | "i" | "d" ; FILE fileurl = "file://" [ host | "localhost" ] "/" fpath ; HTTP httpurl = "http://" hostport [ "/" hpath [ "?" search ]] hpath = hsegment *[ "/" hsegment ] hsegment = *[ uchar | ";" | ":" | "@" | "&" | "=" ] search = *[ uchar | ";" | ":" | "@" | "&" | "=" ] ; GOPHER (see also RFC1436) gopherurl = "gopher://" hostport [ / [ gtype [ selector [ "%09" search [ "%09" gopher+_string ] ] ] ] ] gtype = xchar selector = *xchar gopher+_string = *xchar ; MAILTO (see also RFC822) mailtourl = "mailto:" encoded822addr encoded822addr = 1*xchar ; further defined in RFC822 ; NEWS (see also RFC1036) newsurl = "news:" grouppart grouppart = "*" | group | article group = alpha *[ alpha | digit | "-" | "." | "+" | "_" ] article = 1*[ uchar | ";" | "/" | "?" | ":" | "&" | "=" ] "@" host ; NNTP (see also RFC977) nntpurl = "nntp://" hostport "/" group [ "/" digits ] ; TELNET telneturl = "telnet://" login [ "/" ] ; WAIS (see also RFC1625) waisurl = waisdatabase | waisindex | waisdoc waisdatabase = "wais://" hostport "/" database waisindex = "wais://" hostport "/" database "?" search waisdoc = "wais://" hostport "/" database "/" wtype "/" wpath database = *uchar wtype = *uchar wpath = *uchar ; PROSPERO prosperourl = "prospero://" hostport "/" ppath *[ fieldspec ] ppath = psegment *[ "/" psegment ] psegment = *[ uchar | "?" | ":" | "@" | "&" | "=" ] fieldspec = ";" fieldname "=" fieldvalue fieldname = *[ uchar | "?" | ":" | "@" | "&" ] fieldvalue = *[ uchar | "?" | ":" | "@" | "&" ] ; Miscellaneous definitions lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" hialpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" alpha = lowalpha | hialpha digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" safe = "$" | "-" | "_" | "." | "+" extra = "!" | "*" | "'" | "(" | ")" | "," national = "{" | "}" | "|" | "\" | "^" | "~" | "[" | "]" punctuation = "<" | ">" | "#" | "%" reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" escape = "%" hex hex unreserved = alpha | digit | safe | extra uchar = unreserved | escape xchar = unreserved | reserved | escape digits = 1*digit ``` 출처 : [BNF 문법](https://tools.ietf.org/html/rfc1738) * HTTP Request 종류와 HTTP Response 종류에 대해 학습하고 정리한다. - Http Request Method 1. GET : Request Body가 없으며 요청받은 URI의 정보를 검색하여 응답 2. POST : 요청된 resource를 create 한다. 3. PUT : 요청된 resource를 update 한다. 4. DELETE : 요청된 resource delete 한다. - Http Response Method 1. 1xx : 조건부 응답으로 요청을 받았으며 작업을 계속 진행 2. 2xx : Client가 요청한 동작을 수신하여 이해했고 성공적으로 처리 3. 3xx : 경고, Client는 Request를 마치기 위해 추가 동작이 필요 4. 4xx : 오류, Client에 요류 발생 5. 5xx : 오류, Server가 유효한 요청을 수행하지 못함 이외에도 HEAD, PATCH, CONNECT, TRACE, OPTIONS 등이 존재한다. 출처 : [WIKI - HTTP Status Code](https://ko.wikipedia.org/wiki/HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C) --- ### 김웅기 #### 코드 동작 개선 - url객체 비교를 거의 if else로 다 처리했는데, 조금 더 논리적으로 구현했으면 좋았을 것 같다. - 실제 동작은 하지 않더라도 좀 더 다양한 종류의 요청을 보낼 수 있도록 작업하는 것이 좋았을 것 같다. #### 스스로 확인할 사항 * URL 구성 요소에 대해 학습한다. - URI 는 Uniform Resource Identifier 의 약자로 인터넷상 표현할 수 있는 모든 리소스를 이야기 하며, URL은 Uniform Resource Locator 의 약자로 URI에서 네트워크상 경로를 이야기 한다. ![](https://t1.daumcdn.net/cfile/tistory/255D3F4755AF337B1B) [참고](https://whitesal.com/article/article_view.php?no=3787&mode=3) * 다양한 URL 케이스를 어떻게 처리하는지 확인한 방법을 정리한다. - URL의 각 요소마다 들어갈 수 없는 문자들이 조금씩 다르므로 정규식을 통해 프로토콜, 호스트, 포트, 경로, 쿼리, 앵커 등으로 정리하고 별도로 확인해준다. * HTTP Request 종류와 HTTP Response 종류에 대해 학습하고 정리한다. - Request 종류 - GET : URL이 가진 정보를 검색하기 위해 서버에 요청 - POST : POST 요청 방식은 요청 URI(URL)에 폼 입력을 처리하기 위해 구성한 서버 측 스크립트(ASP, PHP, JSP 등) 혹은 CGI 프로그램으로 구성되고 Form Action과 함께 전송되는데, 이때 헤더 정보에 포함되지 않고 데이터 부분에 요청 정보가 들어가게 된다. - HEAD : HEAD 요청 방식은 GET과 유사한 방식이나 웹 서버에서 헤더 정보 이외에는 어떤 데이터도 보내지 않는다. - OPTIONS : 해당 메소드를 통해 시스템에서 지원되는 메소드 종류를 확인할 수 있다. - PUT : POST와 유사한 전송 구조를 가지기 때문에 헤더 이외에 메시지(데이터)가 함께 전송된다. 원격지 서버에 지정한 콘텐츠를 저장하기 위해 사용되며 홈페이지 변조에 많이 악용되고 있다. - DELETE : 원격지 웹 서버에 파일을 삭제하기 위해 사용되며 PUT과는 반대 개념의 메소드이다. - TRACE : 원격지 서버에 Loopback(루프백) 메시지를 호출하기 위해 사용된다. - CONNECT : 웹 서버에 프락시 기능을 요청할 때 사용된다. - [출처](https://gyrfalcon.tistory.com/entry/HTTP-응답-코드-종류-HTTP-메소드-종류) - RESPONSE 종류 - 1xx (조건부 응답) - 2xx (성공) - 3xx (리다이렉션 완료) - 4xx (요청 오류) - 5xx (서버 오류) --- ### 나영균 #### 코드 동작 개선 - URL의 비교 로직에서 path Array에 대하여 array 레벨의 비교 로직이 필요하다. - parse된 url에 대하여 각각에 대한 에러처리 로직을 구현해야 한다. - string -> buffer가 아니라 처음부터 buffer로 구현해야 한다. #### 스스로 확인할 사항 - URL 구성 요소에 대해 학습한다. - Scheme - 사용할 프로토콜을 말하며, 리소스에 어떻게 요청, 접근할 것인지를 명시합니다. - User and password - 어떤 서버들은 자신이 가지고 있는 데이터에 접근하기 위해서 사용자의 이름과 비밀번호를 요구합니다. - Host and Port - 하나의 Host( 컴퓨터 )에는 여러 개의 Process( 프로그램 )이 각각의 Socket( 소켓 )을 사용하여 데이터 통신을 하고 있기 때문에, 각각의 소켓을 구분할 필요가 있습니다.이 때 소켓을 구분하는 역할을 하는 것이 Port( 포트 )입니다. HTTP 프로토콜에서 포트 번호를 명시하지 않으면, 80번 포트를 기본 값으로 사용합니다. ( Well-known port - 링크 ) ex) http://www.google.com:80 - Path - 호스트에서 제공하는 자원의 경로를 의미합니다. ex) https://movie.naver.com/movie/running/current.nhn - Query - Query String( 쿼리 스트링 )이라고도 합니다.클라이언트가 자원을 GET 방식으로 요청할 때, 필요한 데이터를 함께 넘겨 줄 목적으로 사용합니다. ex) http://localhost:3000/index?id=3&page=1 - 프래그먼트 - HTML에는 각각의 요소에 id 속성을 부여할 수 있는데요, URL에 프래그먼트를 전달하면 페이지가 해당 id가 있는 곳으로 스크롤이 이동하게 됩니다. ex) http://victorydntmd.tistory.com/287#bottom - 다양한 URL 케이스를 어떻게 처리하는지 확인한 방법을 정리한다. - Regex 이용하기 ```javascript const regex = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/, const urlString = "http://user_name:pass-word@boostcamp.connect-foundation.or.kr:2019/first/second/last?query=ab&param=12"; const parsedUrl = regex.exec(urlString); this.url = parsedUrl[0]; const scheme = parsedUrl[1] || ""; const username = parsedUrl[4] || ""; const password = parsedUrl[5] || ""; const host = parsedUrl[6] || ""; const port = parsedUrl[7]; const pathname = parsedUrl[9] || ""; const querystring = parsedUrl[12] || ""; const fragment = parsedUrl[13] || ""; ``` - 각각의 파트로 분리 한 후, 각각의 파트에 대하여 예외처리를 실시한다. - 위와 관계없이 모듈이용의 예 ```javascript const urlString = "http://www.example.com/some/path?name=value#anchor"; // Browser const url = document.createElement('a'); url.href = urlString; // Node const url = new URL(urlString); url.protocol; //(http:) url.hostname; //(www.example.com) url.pathname; //(/some/path) url.search; // (?name=value) url.hash; //(#anchor) ``` - HTTP Request 종류와 HTTP Response 종류에 대해 학습하고 정리한다. - Http Request 종류 simple 버전 - GET : Request Body가 없으며 요청받은 URI의 정보를 검색하여 응답 - POST : 요청된 resource를 create 한다. - PUT : 요청된 resource를 update 한다. - DELETE : 요청된 resource delete 한다. - Http Response 종류 simple 버전 - 1xx : 조건부 응답으로 요청을 받았으며 작업을 계속 진행 - 2xx : Client가 요청한 동작을 수신하여 이해했고 성공적으로 처리 - 3xx : 경고, Client는 Request를 마치기 위해 추가 동작이 필요 - 4xx : 오류, Client에 요류 발생 - 5xx : 오류, Server가 유효한 요청을 수행하지 못함 ## 3. Consideration ``` - 학습정리의 `다같이 확인할 사항`에 대해 충분히 토의하고 그 과정을 일목요연하게 정리합니다. ``` ### 다같이 확인할 사항 * 웹 브라우저가 동작하는 과정을 개발자 화면에서 확인하고 학습한다. - 네이게이션에 url을 입력하면 브라우저가 입력 받은 값을 파싱하여, 검색어인지 url인지를 체크한다. - url인 경우 사이트의 콘텐츠를 가져오기 위해 UI 스레드가 네트워크 호출을 시작한다.(request) 로딩 스피너가 탭의 모서리에 표시되고, 네트워크 스레드는 요청에 대한 DNS Lookup 및 TLS 연결 설정과 같은 적절한 프로토콜을 거쳐 요청을 처리한다. - 이때 네트워크 스레드가 HTTP 301과 같은 서버 리디렉션 헤더를 수신할 수도 있다. 그런 경우에는 네트워크 스레드가 UI 스레드와 통신해 서버가 리디렉션을 요청했다는 것을 알린다. 그런 다음 새로운 URL 요청이 시작된다. - 응답 본문인 페이로드가 들어오기 시작하면 네트워크 스레드는 필요에 따라 스트림의 처음 몇 바이트를 확인한다. 페이로드가 어떤 형식의 데이터인지는 응답 헤더의 Content-Type 헤더가 알려 주지만 정보가 없거나 잘못된 정보가 있을 수 있다. 그래서 이때 MIME 스니핑을 실행해 데이터의 실제 형식을 알아낸다. 응답이 HTML이라면 데이터를 렌더러 프로세스로 전달한다. 다른 파일 형식이라면 다운로드 매니저에 데이터를 전달. - 렌더러는 전달받은 HTML을 분석하여 DOM을 구축하고, 하위 리소스를 로딩한다. - CSS파일을 분석하여 스타일을 계산하고 레이아웃을 만들어서 요소를 배치한다. [참고 : 최신 브라우저의 내부 살펴보기 2 - 내비게이션 과정에서 일어나는 일](https://d2.naver.com/helloworld/9274593) * 리눅스/유닉스 환경에서 wget 이나 curl 명령 사용방식에 대해 학습한다. * wget이란 Internet의 file을 다운로드 받는 Linux 명령어 중의 하나. 조금 더 구체적으로 살펴보면 HTTP 통신 또는 FTP 통신을 사용해 Server에서 파일 또는 Contents를 다운로드할 때 사용하는 software. * wget의 특징은 크롤링 기능이다. 여러 파일을 한 번에 다운로드 하거나 웹 페이지의 링크를 순회하며 여러 Contents를 자동으로 다운로드할 수 있습니다 * curl 명령어는 http message를 Shell 상에서 request를 보내서 test할 수 있는 명령어. http를 이용하여 경로의 데이터를 가져온다. * restful API의 개발 시 Test하는데 유용하며, GET/POST/PUT/DELETE의 CRUD를 쉽게 확인할 수 있다. * 브라우저가 처리하는 과정을 WireShark 같은 네트워크 패킷 분석 도구를 통해서 확인한다. - <p><img src="https://cdn.clien.net/web/api/file/F01/8064140/14cf7cd31cc850.png?w=780&h=30000&gif=true" width="400px"/></p> - Http 요청 패킷 - <p><img src="https://cdn.clien.net/web/api/file/F01/8064163/14d02a06156f16.png?w=780&h=30000&gif=true" width="400px"/></p> - Http 응답 패킷 - 3 way handshake - A클라이언트는 B서버에 접속을 요청하는 SYN 패킷을 보낸다. 이때 A클라이언트는 SYN 을 보내고 SYN/ACK 응답을 기다리는SYN_SENT 상태가 되는 것이다. - B서버는 SYN요청을 받고 A클라이언트에게 요청을 수락한다는 ACK 와 SYN flag 가 설정된 패킷을 발송하고 A가 다시 ACK으로 응답하기를 기다린다. 이때 B서버는 SYN_RECEIVED 상태가 된다. - A클라이언트는 B서버에게 ACK을 보내고 이후로부터는 연결이 이루어지고 데이터가 오가게 되는것이다. 이때의 B서버 상태가 ESTABLISHED 이다. - handshake 데이터의 전송이 이루어진다. - 클라이언트가 연결을 종료하겠다는 FIN플래그를 전송한다. - 서버는 일단 확인메시지를 보내고 자신의 통신이 끝날때까지 기다리는데 이 상태가 TIME_WAIT상태다. - 서버가 통신이 끝났으면 연결이 종료되었다고 클라이언트에게 FIN플래그를 전송한다. - 클라이언트는 확인했다는 메시지를 보낸다. * WireShark 도구가 동작하는 원리에 대해 학습한다. - 무차별 모드 : 일반적으로 NIC는 자신과 다른 MAC address의 Frame을 무시한다. 무차별 모드는 수신한 Frame이 자신과 상관 없는 MAC address 갖아도 모두 수신하는 모드이다. - 라우터로 부터 패킷이 자신의 네트워크로 라우팅되면 모든 노드에 브로드 캐스트를 하게 된다. 또한, WireShark는 무차별 모드로 자신의 컴퓨터로 들어오는 모든 Frame을 캡쳐하여 실시간으로 패킷 정보를 노출시켜준다. 따라서 WireShark의 패킷 캡쳐 원리는 패킷 스니핑으로 볼 수 있다. ![](https://miro.medium.com/max/1400/1*t-JwqBmYtztX8bbnDcXjwA.png) - 만약 HTTPS 패킷을 분석하다면, 암호화된 패킷을 복호할 Key 설정해야 한다. - 와이어샤크는 tcpdump와 매우 비슷하지만 그래픽 프론트엔드에 정렬, 필터링 옵션이 몇 가지 추가된 점이 다르다. [WireShark 참고](https://ko.wikipedia.org/wiki/%EC%99%80%EC%9D%B4%EC%96%B4%EC%83%A4%ED%81%AC)