HTTP/0.9 ~ HTTP/2.0

sycho·2023년 9월 14일
0

Network

목록 보기
2/9

HTTP는 웹에서 흔히 사용되는 server와 client 사이의 통신에 대한 protocol이다보니 자세히 알아볼 필요가 있다.

기본 정보

  • TCP/IP를 기반으로 하는, OSI의 응용 계층(application layer)에 해당하는 protocol이다.

  • application layer은 두 host가 어떻게 통신하는지를 정하는 protocol을 일컫는다. 여기서의 두 host는 server과 client다.

  • 인터넷 상에서 content를 어떻게 요청하고, 어떻게 형식으로 전달되는지를 정한다.

  • HTTP는 기본 TCP port가 80이고, HTTPS는 기본 TCP port가 443이다.

  • connectionless protocol이다.

  • stateless protocol이다.

HTTP/0.9

  • 최초의 HTTP다. 1991년도에 만들어졌다.

  • GET method만 있었다.

GET /index.html (request)
(response body)
(connection closed)
  • header이 존재 안한다.

  • respond 내용물은 무조건 HTML이어야 한다.

HTTP/1.0

  • 1996년도에 만들어졌다.

  • HTML 외의 다른 형식의 파일도 respond 내용물로 가능해졌다. (이미지, 비디오, txt 등)

  • 여러 method가 추가되었다. (POST, HEAD 등)

  • header이 추가되었다. request/respond에 대한 추가정보를 여기서 저장한다.

  • response에 status code가 추가되었다. request에 대한 결과가 어떤지를 알려준다. 한번쯤 봤을 404 오류도 이것에 해당된다.

  • character set를 지원하기 시작했다. character set이란 8진수를 character의 배열로 변환할 때 사용하는 인코딩이다. 즉 여러 종류의 character encoding이 가능해졌다고 생각하면 된다.

  • multi-part type이 등장했다. multi-part는 MIME(Multipurpose Internet Mail Extensions)의 타입 중 하나로 여러 형식의 메세지를 한번에 보내거나, 무언가가 첨부된 텍스트를 보낼때 사용된다.

  • authorization이 등장했다. client가 server에게 본인이 누군지를 인증할 때 사용하는 header이다.

  • caching이 등장했다. cpu cache와 유사하게, client가 무언가를 요청할 때 브라우저에 있는 private cache나 서버랑 별도인 다른 곳에 위치한 shared cache에서 요청한 정보가 있는지를 먼저 확인, 존재시 거기서 정보를 가져와 서버 부담을 줄이는 기능이다.

  • content encoding이 등장했다. response에 넣을메세지가 너무 크면 서버가 인코딩을 한후 무슨 인코딩을 했는지 Content-Encoding header을 넣어가지고 client가 나중에 이를 적용해 디코딩을 할 수 있도록 해주는 기능이다. 데이터 압축은 곧 전송 속도랑 직결되니 유용한 기능이다.

  • HTTP/1.0 request 예시. header을 통해 본인 정보를 집어넣었다. 대체로 다 알거고, Accept가 뭔지는 이 링크 참고

GET / HTTP/1.0
Host: cs.fyi
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
  • HTTP/1.0 response 예시. 서버 정보, 내용물 정보, request 결과 등이 적혀 있다.
HTTP/1.0 200 OK 
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 2023 15:55:28 GMT
Server: Apache 0.84

(response body)
(connection closed)
  • HTTP의 처음 HT는 HyperText라는 뜻을 가지는데, 이제 온갖 형식의 메세지를 첨부하는게 가능해서 사실 HyperMedia에서 발췌해 HMTP라 부르는게 더 적절하다...는 말이 있지만 그냥 HTTP로 표현이 굳어버렸다.
  • 많은 기능이 추가되었으나 단점이 한가지 있다. 바로 한번의 연결에 여러개의 request를 하는게 불가능하다. 이는 곧 request마다 새로운 TCP connection을 해야 한다는 것이다. 이는 곧 성능 저하로 이루어짐.

Three-way Handshake

  • TCP connection을 할 때마다 성능 저하로 이어지는 이유.

  • HTTP에서 이걸 하진 않는다. 하지만 HTTP 통신때 TCP 연결을 해야하므로 HTTP 통신 과정에 이 과정이 포함은 된다.

  • 위 과정을 대충 설명하면

  1. client가 SYN이라는 message를 랜덤한 숫자 x랑 함께 보냄
  2. server이 SYN ACK 이라는 message를 랜덤한 숫자 y와 x+1과 함께 보냄. x+1을 하는 이유는 client에게 본인이 잘 받았음을 표시하기 위해서다.
  3. client가 ACK이라는 message를 y+1과 함께 보냄. y+1을 보내는 이유는 server에게 본인이 잘 받았음을 표시하기 위해서다.
  • 이렇듯 한번의 연결마다 사실 여러번 와리가리를 한 다음에 데이터 전송이 이루어지는데, 기껏 연결하고 한번만 데이터 전송을 한 다음에 다시 TCP 연결을 하기에 성능이 안좋다고 하는 것이다.

시도한 해결법

  • Connection: keep-alive라는 header을 사용하면 server이 connection을 close하지 않는다.

  • 하지만 위 header을 지원한 server이나 사용한 client가 별로 없어서 그리 도움은 안되었다고 한다.

또다른 문제점

  • 앞에서 HTTP가 stateless protocol이라고 했는데, 이 때문에 연결이 계속 유지되었든 유지가 안되었든간에 요청마다 서버가 필요로 하는 정보를 집어 넣어야 했다. 서버가 정보를 저장해놓았다면 (stateful protocol) 이럴 필요가 없는데 그렇지 않다 보니 bandwidth 낭비가 발생.

HTTP/1.1

  • 1999년에 나왔다.

  • 새로운 HTTP method가 나왔다. PUT, PATCH, OPTIONS, DELETE

  • Host header의 Hostname Identification이 필수가 되었다.

  • 기본적으로 connection이 바로 종료가 되지 않도록 바꿔졌다. 대신 종료를 하고 싶을 때 header을 넣는걸로 바꿔졌다. (Connection: close) 한번만 request를 하고 종료를 할거면 첫 request에 이걸 넣으면 된다. 이걸 persistent connection이라고 한다.

  • Pipelining이 등장했다. 이제 request마다 server response를 기다려야 할 필요가 없고, response 오기 전에 request를 더 하는게 가능하다. server은 request의 순서에 맞게 respond를 해야 한다.

  • Pipelining과 persistent connection에서 client가 어디까지가 특정 request에 대한 respond고 그 이후가 다른 request의 respond인지를 header인 Content-Length를 가지고 파악한다.

  • 단 위 header을 통한 해결법은 특정 request에 대한 data의 길이가 고정된 경우에만 사용이 가능하다. 만약 dynamic할 경우, chunked encoding이라는 것을 사용해야 한다. 이건 Transfer-encoding header의 value중 하나로, dynamic data를 server이 respond로 보내게 된 경우 저 header을 추가한 다음, respond마다 data 끝에 data가 계속 이어지면 \r\n을 붙이고, 전송할 data가 더이상 없으면 length가 0인 chunk랑 함께 trailing header들을 전송한다. 그러면 client가 dynamic data에 대한 특정 request의 respond가 끝났음을 파악이 가능함.

  • digest authentication 등장. 기존 방식 대비 이 인증 방식의 좋은 점은

  1. plaintext가 통신 과정에 나돌아다니지 않는다. 기존 인증 방식은 비밀번호가 그대로(...) 통신 과정에 나돌아다녔는데 이제 그렇지 않는다.
  2. replay-attack 방지 가능. Nonce 덕분에 가능하다.
  • proxy authentication 등장.

  • Range request 등장. data의 일부분만 필요할 때 사용된다.

  • Content negotiation 등장. 사용자에게 적절한 content 표시 방식이 무엇인지를 server과 client가 서로 '의논'하는 기능이 등장.

  • Client cookie 등장. cookie는 보통 client가 누군지 기억하는데 사용된다.

  • 추가 caching, 추가 character set, 향상된 compression 지원, 새로운 status code 추가.

  • 그외에 뭔가 많이 추가

  • 얘는 처음에는 괜찮았으나 나중에 문제가 생겼는데, 바로 시간이 지나다보니 웹페이지들이 한번에 여러개의 연결을 열기 시작했다는 것이다. HTTP/1.1은 connection이 열리면 이를 원할 때까지 지속하는건 가능하고, pipelining도 있는데 굳이 이렇게 마구잡이로 connection을 연 이유는, head-of-line blocking 문제로 인해 느린 request들이 빨리 끝낼 수 있는 request들을 막기 시작해서 엄청 효과적이진 않았다. 당시 개발자들이 이를 우회하려고 온갖 기술들을 쓰기도 함.

SPDY

  • 2009년에 구글서 개발

  • 더 빠르게, 더 보안상 안전하게

  • HTTP/2에 영향을 많이 줌

  • HTTP를 대체하려고 했던건 아니고 HTTP request가 transport layer에 도달하기 전에 modify하는 translation layer에 위치하기 위한 녀석이었다.

  • 구글은 이걸로 HTTP를 대체하려던게 아니었다보니 HTTP/2가 나오자 SPDY 지원을 바로 멈췄다.

HTTP/2

  • 2015년에 등장

Binary protocol

  • 이제 text 기반이 아닌 binary 기반 protocol이 되었다. 덕분에 parsing이 쉬워짐.

  • HTTP/1.2라고 이름을 짓지 않은 이유도 이렇게 binary 기반 protocol로 역변해서 그렇다.

  • Frame과 Stream이라는 개념을 가지고 data를 전달한다.

  • 모든 HTTP message는 하나 이상의 frame으로 이루어진다. header은 HEADERS frame에, data는 DATA frame에 저장된다. 그 외에도 congestion control 용도의 frame 등 여러 frame이 존재한다.

  • HTTP/2부터 모든 HTTP request, response에 대해 고유의 stream ID가 이제 부여된다. 그리고 이 request, response들은 여러개의 frame으로 쪼개지게 된다.

  • 동일 stream ID의 frame들을 모아서 stream이라고 하며, 모든 freme은 본인이 해당되는 stream 판별을 위해 stream ID를 저장한다.

  • request stream의 stream ID는 무조건 홀수, respond stream의 stream ID는 무조건 짝수다.

  • 앞에 여러개의 frame이 존재한다고 했는데, 그 중 RST_STREAM은 특정 stream을 중간에 abort하는데 사용된다. 이것의 장점은 특정 요청을 연결을 끊지 않으면서 중간에 멈추고 새로운 요청을 할 수 있다는 것이다. 왜냐하면 RST_STREAM은 연결 종료까지 유도하진 않거든요. 그래서 다시 연결을 구성하는데 생기는 latency를 방지하는게 가능하다. 게다가 연결을 끊질 않으니 다른 request, 즉 stream을 중단시킬 필요도 없다.

Multiplexing

  • 이제 Multiplexing이라는 것을 지원한다. 이제 하나의 연결에서 동시에 여러개의 request 전달이 가능하다. 이 request들에 대한 response는 특정 순서로 와야 할 필요가 없다. 즉 asynchronous.

  • 이는 앞에 소개한 head-of-line 문제를 해결해준다. 오래 걸리는 request에 대해 다른 request가 기다릴 필요가 없고 그냥 동일 연결에서 request를 또 해버리면 된다.

  • 위의 stream/frame 구조의 등장으로 자연스럽게 가능해진 기능이다.

Header Compression

  • HPACK이라는 모듈로 header을 압축하는게 가능해졌다.

  • host가 매번 필요로 하면서 동일한 내용을 담고 있는 header들(ex. cookie)이 message에 매번 추가되면서 bandwidth가 낭비 -> latency가 늘어나는 것을 방지하기 위해서다.

  • 기본적으로 허프만 코드을 기반으로 header을 인코딩한다.

  • dynamic header table과 static header table을 client/server 측에서 운용한다.

  • 전송시 static header table에 있는 header-value 조합이 들어있으면 해당 key-value가 들어있는 static header table의 index로 바꾸고 전송한다.

  • 전송시 static header table에 없는 header-value 조합이 등장시 허프만 코드로 인코딩 후 dynamic header table에 저장한다. index도 받게 된다.

  • 전송시 static header table에는 없지만 dynamic header table에 있는 header-value 조합이 등장시 dynamic header table상의 index로 바꾸고 전송한다.

  • 수신자도 처음 보는 key-header 조합 발견시 dynamic header table에 저장하며, 대신 index가 오면 본인 table에 있는 key-header 조합에서 적절한 value를 찾는다. connection마다 저 table들을 서로 저장한다고 생각하면 된다.

  • 이 때문에 HTTP를 더이상 stateless라고 부르기가 애매해졌다.

관련 링크
관련 링크2

Server Push

  • server이 하나의 request에 대해 여러개의 response를 전달하는게 가능해졌다. 이러면 다른 request를 client가 추가로 해서 시간이 낭비되는 것을 막는게 가능.

  • PUSH_PROMISE라는 frame을 활용해서 특정 내용물 전달을 약속, 관련된 stream에서 그 내용물의 전달이 이루어지는데 이것을 client가 사용할지 안할지는 알아서 하면 된다.

Request Prioritization

  • client가 stream을 열 때 priority를 HEADERS frame에 넣는 형식으로 사용.

  • 중간에 PRIORITY frame을 활용해 priority를 바꾸는 것도 가능.

  • server은 이 priority를 기반으로 얼마나 해당 request에 대해 resource를 할당할지를 결정한다.

Security

  • 이전에 잠시 언급한 TLS를 의무화할지 안할지에 대해 말이 많았다.

  • 결국 의무로 하지 않도록 결정됨.

  • 다만 일부가 HTTP/2에 TLS 적용을 하지 않으면 HTTP/2를 사용 안하겠다고 해서 반쯤 의무화가 됨.

  • 사용할거면 TLS 1.2 이상을 사용해야 하고, 최소 keysize도 정해져있고, epehemeral key가 꼭 필요하다.

HTTP/2 request 양식

  • HTTP 버전, 요청 URL, HTTP method, HTTP request header이 필수로 들어간다.

  • HTTP body가 추가적으로 들어가기도 한다.

HTTP method

  • HTTP request가 예상하는 action들

  • 겁나 많지만 그 중 GETPOST가 자주 쓰이는 녀석들 중 하나...로 꼽을 수 있다.

  • GET은 요청 URL 관련 정보를 달라고 한다.

  • POST는 서버에게 특정 정보를 전달할 때 사용된다.

HTTP body

  • 아까 선택적으로 HTTP body가 request에 들어간다고 했는데, POST같은 method에서 전달하려는 정보 등이 들어가는 것이다.

HTTP/2 response 양식

  • HTTP status code, HTTP response header이 필수로 들어간다.

  • HTTP body가 추가적으로 들어가기도 한다.

HTTP status code

  • 404와 같은, 앞에 잠시 언급되었던 코드들로 HTTP request에 대한 결과를 알려줌.

  • 3자리이며, 크게 5부류로 나뉘어진다.

  • 1xx : 정보 부류. 예를들어 100은 서버측에서 client에게 다음 요청을 보내도 상관 없다는 것을 알린다.

  • 2xx : 성공 부류. 예를들어 200은 서버측에서 client에게 request가 성공적이었다는 것을 알린다.

  • 3xx : redirect 부류 (재요청 부류). 예를들어 300은 서버측에서 client에게 가능한 응답이 여러개임을 알려준다.

  • 4xx : client 측 오류 부류. 예를들어 404의 경우 서버가 request에서 요청한 resource를 찾지 못해서 client가 잘못된 요청을 하고 있을거라는 걸 알리는 코드다.

  • 5xx : server 측 오류 부류. 예를들어 500의 경우 서버 내부에서 뭔가 심각한 오류가 있었다는 것을 알리는 코드다.

HTTP body

  • 여기서의 body는 대체로 request에서 요청한 내용물이 들어간다. 실패한 경우 등의 이유로 body가 비어져있을 수도 있다.

HTTP/2와 DDoS

  • 원래는 TCP connection을 열고 request 하나 처리하고 종료를 했기에 server 입장에서 DDoS 걱정을 할 필요가 없었다.

  • 하지만 HTTP/1.1부터 persistent connection이 가능해지기 시작했고, HTTP/2부터는 header compression에 사용하는 table 때문에 stateless라고 보기도 힘들어서 DDoS에 취약해졌다.

Proxy Server

  • 웹 브라우저 (client)랑 웹 서버 (server) 사이에 있는 application layer 상에서 동작하고 있는 컴퓨터/머신들을 일컫는 말이다.

  • 사실 이보다 하위 계층에서 동작하는 컴퓨터/머신들도 있고 이들도 성능에 큰 영향을 줄 수 있으나, 여기선 proxy에 대해서만 얘기해보겠다.

  • 이들은 request를 받았을 때 아무 조작도 안하고 그냥 다시 전송할 수도 있고 (transparent) 그 request에 무슨 조작을 하고 다시 전송을 할 수도 있다. (non-transparent)

  • 대표적인 proxy의 역할은 data caching. 뿐만 아니라 자녀 보호 등을 구현할 때 쓰이는 filtering, 동일한 곳에서 운영하는 여러 서버에 적절하게 일을 배분하는 load balancing, 특정 자원에 접근을 허용할지 안할지 판별하는 authentication (앞의 proxy authentication도 이것의 일종이다.), 단순 기록을 하는 logging 등을 할 수도 있다.

참고 자료
http in depth
cloudflare - what is http?
mozilla - An overview of HTTP

profile
임베디드 시스템 개발자. 관심 분야 : Embed/System/Architecture/Web/AI

0개의 댓글