RFC 7540에 기반한 HTTP/2 통신을 Python 코드로 구현
즉 어느 한쪽만 HTTP/2를 지원한다면 해당 통신은 HTTP1.1 등, 구버전의 프로토콜로 fall-back 될 수밖에 없다. 어느 브라우져가 현재 HTTP/2를 지원하고 있는지는 http://caniuse.com/#search=http%2F2 에서 확인할 수 있다.
서버 쪽 지원 사항을 포함하여 확인할 수 있는 곳은 https://github.com/http2/http2-spec/wiki/Implementations 이다. 두 개의 페이지에서 알 수 있듯이 상위 버전의 클라이언트(주로 웹 브라우져)와 최신 웹 서버 (apache, Nginx 등)등은 HTTP/2를 지원하고 있다.
특정 웹 서비스가 HTTP/2를 지원하는지, HTTP1.1만을 지원하는지 해당 서비스를 사용하려는 클라이언트에서 빠르게 판단이 되어야 Client-Server간 통신 프로토콜을 어떤 버전으로 할 지 정할 수 있다. 이 부분에 대한 기술적 스펙은 HTTP/2 RFC의 3장에 나와있다. - https://tools.ietf.org/html/rfc7540#section-3
지원 여부의 확인을 위해 HTTP/2에서는 'h2c' 와 'h2' 라는 indicator를 사용한다. h2c는 HTTP 통신, h2는 HTTPS 통신을 각각 의미한다.
첫 GET 요청은 HTTP1.1 버전으로 시작하되 Connection, Upgrade, HTTP2-Settings 요청 헤더를 사용하여, 클라이언트는 HTTP/2를 지원하고 있으므로 서버또한 HTTP/2 프로토콜를 사용할 수 있도록 요청한다.
GET / HTTP/1.1
Host: server.example.com
① Connection: Upgrade, HTTP2-Settings
② Upgrade: h2c -> HTTP용 indicator 값을 사용
③ HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
①, ② 값은 고정이며, ③ 값은 SETTINGS frame 설정값에 따라 달라질 수 있으며 base64url 방식으로 인코딩된 값이 1개만 설정 되어야 한다.
만약, 서버가 HTTP/2를 지원한다면 다음과 같은 101 응답을 내려준다.
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection ... -> 이후 부터는 HTTP/2 통신
101 응답이후에는 HTTP/2 방식으로 통신이 시작되며 GET 요청한 주소의 200 OK 응답을 다시 받게 된다. 서버가 HTTP/2 를 지원하지 않는다면, Connection 및 Upgrade 요청 헤더는 무시되며, HTTP1.1 기반으로 GET 요청한 주소의 200 혹은 302/301/404 응답을 받게 될 것이고 클라이언트는 서버가 HTTP/2를 지원하지 않는다는 정보를 취득하고 이하 통신 부터는 모두 HTTP1.1 기반의 통신을 진행한다.
Connection, Upgrade 헤더를 통해 프로토콜 교체를 요청하는 클라이언트 방식은 HTTP/2 이전에도 HTTP1.1 방식의 연결에서 WebSocket 등으로 사용중인 프로토콜을 변경하고 싶을때 사용하던 방식과 동일하다.
HTTP/2 환경에서의 HTTPS 통신은 TLS기반의 ALPN(Application-Layer Protocol Negotiation)을 사용한다. ALPN은 SNI와 같은 TLS Extension 중에 하나이며, ALPN에 대한 자세한 내용은 별도의 포스트에서 소개하겠지만 요약하자면 OSI 7 레이어중, 최상단인 Application Layer상에서 사용할 프로토콜을 클라이언트-서버가 협상(negotiation)하고 결정하는 방식이다. - http://www.rfc-editor.org/info/rfc7301 , 여기서의 Application Layer는 결국 HTTP(S)이고, 'h2' 라는 indicator를 클라이언트가 TLS 통신으로 서버에 보내어 서버가 accept하는 방식을 사용하는 것이다.
위의 RFC 내용을 기반으로 특정 도메인을 매개변수로 하여 HTTP/2 지원 여부를 확인하는 코드를 Python으로 개발한 코드는 아래와 같다.
위의 코드를 개발할때 사용한 test case는 HTTP와 HTTPS 통신을 모두 HTTP/2 지원하는 경우, HTTPS만 HTTP/2를 지원하는 경우, 두 가지 모두 HTTP1.1만 지원하는 경우 등으로 나누어 진행하였으며, 잘 알려진 도메인으로 테스트 한 결과는 다음과 같다.
<HTTP와 HTTPS 통신을 모두 HTTP/2 지원>
$ python h2check.py nghttp2.org
This domain supports HTTP/2 with h2c - HTTP
This domain supports HTTP/2 with h2 - HTTPS
<HTTPS만 HTTP/2를 지원하는 경우>
$ python h2check.py www.facebook.com
This domain does not support HTTP/2 with h2c - HTTP
This domain supports HTTP/2 with h2 - HTTPS
<두 가지 모두 HTTP1.1만 지원하는 경우>
$ python h2check.py www.nike.com
This domain does not support HTTP/2 with h2c - HTTP
This domain does not support HTTP/2 with h2 - HTTPS but http/1.1
개발 참고 자료:
https://tools.ietf.org/html/rfc7301#section-3.2
https://docs.python.org/3/library/ssl.html
소스 코드: