Microsoft MVP성태의 닷넷 이야기
웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c [링크 복사], [링크+제목 복사]
조회: 1418
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

IIS의 HTTP/2 지원 여부 - h2, h2c

우선 h2, h2c에 대한 용어부터 정리해야겠습니다. ^^

글을 읽다 보면, 간혹 HTTP/1.1을 h1, HTTP/2.0을 h2로 표기하는 것을 보게 됩니다. 사실 이게 엄밀히 말해서, 그냥 줄여서 표현하기 위해 그런 것인지 공식적으로 저 명칭이 있는 것인지는 잘 모르겠습니다. 가령 HTTP/1.1 RFC 문서에서는,

Hypertext Transfer Protocol -- HTTP/1.1
; https://tools.ietf.org/html/rfc2616

"h1"이라는 단어 자체가 없습니다. 따라서, 아마도 문맥에 따라 h1을 기존의 HTTP/1.1로 이해하는 것이 맞을 수 있습니다. (혹시 이에 대한 이력을 알고 계신 분은 덧글 부탁드립니다. ^^)

그런데, h2의 경우에는 좀 다릅니다. HTTP/2 공식 문서에는,

Hypertext Transfer Protocol Version 2 (HTTP/2)
; https://tools.ietf.org/html/rfc7540
; https://httpwg.org/specs/rfc7540.html

분명히 버전 식별자로써 이에 대한 설명이 있습니다.

3.1.  HTTP/2 Version Identification

   The protocol defined in this document has two identifiers.

   o  The string "h2" identifies the protocol where HTTP/2 uses
      Transport Layer Security (TLS) [TLS12].  This identifier is used
      in the TLS application-layer protocol negotiation (ALPN) extension
      [TLS-ALPN] field and in any place where HTTP/2 over TLS is
      identified.

      The "h2" string is serialized into an ALPN protocol identifier as
      the two-octet sequence: 0x68, 0x32.

즉, (문맥에 따라 줄임말일 수 있지만) HTTP/2에 대한 줄임말로서의 "h2"가 아니라, TLS 통신과 함께 그것의 ALPN 확장이 쌍을 이뤄 사용하는 HTTP/2의 프로토콜 식별자입니다. 그리고, TLS를 사용하지 않는 일반 평문 통신에서 HTTP/2의 프로토콜 식별자를 의미하는 h2c가 있습니다. (h2c의 c는 cleartext를 의미합니다.)

   o  The string "h2c" identifies the protocol where HTTP/2 is run over
      cleartext TCP.  This identifier is used in the HTTP/1.1 Upgrade
      header field and in any place where HTTP/2 over TCP is identified.

      The "h2c" string is reserved from the ALPN identifier space but
      describes a protocol that does not use TLS.

즉, 간단하게 정리하면 h2는 https 위에서, h2c는 http 위에서 동작하는 HTTP/2.0에 대한 프로토콜 식별자인 것입니다.




h2, h2c를 이야기할 때 언급해야 할 것이 또 하나 있다면 바로 "협상"입니다. 웹 브라우저 입장에서는 서버 측에서 HTTP/2 프로토콜을 제공하지 않는다면 HTTP/1.1로도 통신이 가능하게 만들어야 하므로 서버가 HTTP/2를 구현하고 있는지 알아내는 과정이 필요합니다.

우선, h2의 경우에는 어차피 TLS 협상이 필요하기 때문에 이 과정에 얹어서 함께 진행되므로 별도의 협상 과정이 필요 없습니다. 반면, h2c의 경우에는 다릅니다. http:// 통신은 소켓 연결 후 곧바로 HTTP 헤더를 보내 통신을 게시하므로 처음부터 HTTP/2 통신을 진행할 수는 없고 일단 HTTP/1.1 요청을 보낸 후 서버의 응답 결과에 따라 이후 HTTP/2 통신을 게시합니다. 이에 대해서는 RFC7540 문서에서 명시하고 있는데, 우선 웹 브라우저는 다음의 요청을 서버에 보내고,

GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>

만약 서버가 HTTP/2를 지원하지 않는다면 응답 헤더에 "Upgrade" 헤더를 포함하지 않는 식으로 클라이언트에 GET 요청에 따른 리소스와 함께 응답합니다.

HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html

...

결국 HTTP/1.1의 요청과 응답으로 이뤄지기 때문에 기존 HTTP/1.1 통신의 입장에서는 협상에 따른 별도의 부하가 발생하는 것은 아닙니다.

반면, 만약 HTTP/2.0을 지원한다면 프로토콜 스위치를 위한 "Upgrade: h2c" 헤더를 함께 응답에 추가하고,

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

[ HTTP/2 connection ...]

이후부터는 자연스럽게 HTTP/2.0 규약에 맞게 통신을 지속합니다. 즉, 협상을 한다고 해도 첫 번째 요청에 대해서만 HTTP/1.1 통신을 하는 것일 뿐 이후의 통신 과정은 HTTP/2.0을 따르므로 마찬가지로 협상으로 인한 부하가 발생하는 것은 아닙니다.

또한, h2c 방식에서도 저렇게 협상을 하지 않고 곧바로 HTTP/2.0 규격으로 통신을 게시할 수 있습니다. (당연히, 이런 경우에는 HTTP/2.0을 지원하지 않는 서버와는 정상적인 통신을 하지 못합니다.)




자, 그럼 실제로 저 차이점들을 간단하게 curl.exe를 이용해 확인해 볼까요? ^^ (윈도우 사용자는 WSL2 환경의 리눅스에 있는 curl을 권장합니다.)

서버는 잘 알려진 nghttp2.org를 이용할 수 있으므로, 다음은 h2c + 협상을 이용해 HTTP/2 통신을 한 결과를 보여줍니다.

$ curl --http2 -I nghttp2.org
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

HTTP/2 200
date: Sat, 16 Jan 2021 06:42:43 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.002868
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

반면, 협상 없이 무조건 HTTP/2 프로토콜로 h2c 통신을 하려면 이렇게 옵션을 추가하면 됩니다.

$ curl --http2-prior-knowledge -I nghttp2.org
HTTP/2 200
date: Sat, 16 Jan 2021 06:42:56 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.00316
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

마지막으로, h2 통신을 실습해 보면,

$ curl --http2 -I https://nghttp2.org
HTTP/2 200
date: Sat, 16 Jan 2021 07:03:19 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.004217
strict-transport-security: max-age=31536000
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

// 어차피 TLS 협상이므로 굳이 --http2 옵션을 주지 않아도 https 접근 시에 h2를 설정하는 듯합니다.
$ curl -I https://nghttp2.org
HTTP/2 200
date: Sat, 16 Jan 2021 07:04:32 GMT
content-type: text/html
last-modified: Mon, 23 Nov 2020 15:07:46 GMT
etag: "5fbbd042-19d8"
accept-ranges: bytes
content-length: 6616
x-backend-header-rtt: 0.001008
strict-transport-security: max-age=31536000
server: nghttpx
via: 2 nghttpx
alt-svc: h3-29=":443"; ma=3600
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
x-content-type-options: nosniff

"https"로 인해 TLS 협상이 이뤄지고 결국 h2c 테스트의 --http2-prior-knowledge 옵션과 동일하게 별도의 "101 Switching Protocols" 과정 없이 진행된 것을 확인할 수 있습니다.




자, 길고 긴 서문을 지나서 이제야 제목에 맞는 글을 쓰게 되는군요. ^^

우선, 공식 문서를 보면,

HTTP/2 on IIS
; https://docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-10/http2-on-iis

Windows 10의 경우 1607 버전, Windows Server의 경우에는 2016 버전에 탑재된 IIS 10.0부터 HTTP/2를 지원하며, 이와 함께 다음의 제약이 있다고 합니다.

  • Windows authentication (NTLM/Kerberos/Negotiate) is not supported with HTTP/2. In this case IIS will fall back to HTTP/1.1.
  • Clear text - as mentioned above, IIS currently only supports HTTP/2 over TLS. Again, IIS will fall back to HTTP/1.1.
  • Bandwidth throttling - IIS has a feature to limit bandwidth (in Inetmgr, select the site, 'Limits' under Configure of the Action pane). This applies to HTTP/1.1 but is not enforced for HTTP/2 (will proceed with no errors or bandwidth limiting).

음... h2c 방식은 지원하지 않는다는 건데, 그래도 최신 버전인 Windows 10의 20H2 업데이트(버전 19042)에 있는 IIS는 뭔가 달라질 수도 있으니 nghttp2.org에 했던 것과 유사하게 테스트를 해보겠습니다. 우선 가장 궁금한 h2c, 즉 평문으로 HTTP/2.0 통신이 가능한지 이렇게 명령을 내리면,

/*
IIS 서버 IP: 210.91.106.100
*/

$ curl --http2-prior-knowledge -I http://210.91.106.100
curl: (16) Error in the HTTP2 framing layer

지원을 안 하는군요. ^^ 그래도 --http2 옵션을 지정하면 협상을 진행하기 때문에 HTTP/1.1로 통신이 진행됩니다.

$ curl --http2 -I http://210.91.106.100
HTTP/1.1 200 OK
Content-Length: 696
Content-Type: text/html
Last-Modified: Fri, 12 Jun 2020 04:28:37 GMT
Accept-Ranges: bytes
ETag: "38365f17140d61:0"
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Sat, 16 Jan 2021 08:08:27 GMT

물론, (문서에 명시했으므로 당연하겠지만) h2 방식은 지원합니다.

/*
https 인증서: 테스트 인증서를 사용했으므로 curl에 -k 옵션 추가
*/

$ curl --http2 -k -I https://210.91.106.100
HTTP/2 200
content-length: 696
content-type: text/html
last-modified: Fri, 12 Jun 2020 04:28:37 GMT
accept-ranges: bytes
etag: "38365f17140d61:0"
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET
date: Sat, 16 Jan 2021 08:06:54 GMT

$ curl -k -I https://210.91.106.100
HTTP/2 200
content-length: 696
content-type: text/html
last-modified: Fri, 12 Jun 2020 04:28:37 GMT
accept-ranges: bytes
etag: "38365f17140d61:0"
server: Microsoft-IIS/10.0
x-powered-by: ASP.NET
date: Sat, 16 Jan 2021 08:06:58 GMT




참고로 아래의 글에 나온,

I get the message: "Cant connect securely to this page. This might be because the site uses outdated or unsafe TLS security settings.
; https://docs.microsoft.com/en-us/windows-server/manage/windows-admin-center/support/troubleshooting#i-get-the-message-cant-connect-securely-to-this-page-this-might-be-because-the-site-uses-outdated-or-unsafe-tls-security-settings

EnableHttp2Tls REG_DWORD 0
EnableHttp2Cleartext REG_DWORD 0

EnableHttp2Cleartext를 1로 설정해봤으나, h2c는 여전히 안 됩니다. 일단, 공식 문서 상으로 h2c에 대한 언급이 없으니 IIS에서는 안 되는 게 맞습니다. ^^

그 외에, 간혹 보면 HTTP/2를 활성화하기 위해 DuoEnabled 레지스트리 키를 설정하라는 글이 나오는데,

Microsoft IIS 10.0 ? Installing HTTP/2 on IIS 10.0
; https://devopspoints.com/microsoft-iis-10-0-installing-http-2-on-iis-10-0-999.html

이것은 Windows 10 CTP 버전에 한해서이고, 현재의 버전에서는 해당 레지스트리 설정이 아무런 역할을 하지 않습니다.




Windows 10 사용자의 경우, (Windows 10 1803 빌드부터 기본 포함되어 있기도 한) curl.exe를 사용해 --http2 옵션을 테스트하면 다음과 같은 오류가 발생합니다.

C:\temp> curl --http2 -I https://nghttp2.org
curl: (1) Unsupported protocol

C:\temp> curl --version
curl 7.55.1 (Windows) libcurl/7.55.1 WinSSL
Release-Date: 2017-11-14, security patched: 2019-11-05
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile SSPI Kerberos SPNEGO NTLM SSL

이에 대해서는 이미 알려져 있는데,

Curl shipped with Windows does not support HTTP2 #3141
; https://github.com/microsoft/WSL/issues/3141

"curl --version"의 출력 결과에 "nghttp2" 문구가 있는 버전을 사용해야 합니다. 따라서 별도로 다른 도구와 설치된 curl.exe를 사용하거나, (약간 불안하지만 지원이 되도록 빌드한) 바이너리를 다운로드하거나, 또는 직접 빌드하거나 셋 중 하나를 선택하면 됩니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]


donaricano-btn



[최초 등록일: ]
[최종 수정일: 1/20/2021

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 쓴 사람
 



2021-01-22 07시31분
정성태

[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
12839정성태9/15/2021218.NET Framework: 1118. C# 10 - (17) 제네릭 타입의 특성 적용파일 다운로드1
12838정성태9/13/2021215.NET Framework: 1117. C# - Task에 전달한 Action, Func 유형에 따라 달라지는 async/await 비동기 처리 [2]파일 다운로드1
12837정성태9/11/2021118VC++: 151. Golang - fmt.Errorf, errors.Is, errors.As 설명
12836정성태9/10/202183Linux: 45. 리눅스 - 실행 중인 다른 프로그램의 출력을 확인하는 방법
12835정성태9/7/2021158.NET Framework: 1116. C# 10 - (16) CallerArgumentExpression 특성 추가파일 다운로드1
12834정성태9/7/202176오류 유형: 762. Visual Studio 2019 Build Tools - 'C:\Program' is not recognized as an internal or external command, operable program or batch file.
12833정성태9/6/2021123VC++: 150. Golang - TCP client/server echo 예제 코드파일 다운로드1
12832정성태9/6/202180VC++: 149. Golang - 인터페이스 포인터가 의미 있을까요?
12831정성태9/6/2021110VC++: 148. Golang - 채널에 따른 다중 작업 처리파일 다운로드1
12830정성태9/6/202171오류 유형: 761. Internet Explorer에서 파일 다운로드 시 "Your current security settings do not allow this file to be downloaded." 오류
12829정성태9/5/2021202.NET Framework: 1115. C# 10 - (15) 구조체 타입에 기본 생성자 정의 가능파일 다운로드1
12828정성태9/4/2021192.NET Framework: 1114. C# 10 - (14) 단일 파일 내에 적용되는 namespace 선언파일 다운로드1
12827정성태9/4/2021112스크립트: 27. 파이썬 - 웹 페이지 데이터 수집을 위한 scrapy Crawler 사용법 요약
12826정성태9/3/2021168.NET Framework: 1113. C# 10 - (13) 문자열 보간 성능 개선파일 다운로드1
12825정성태9/3/202169개발 환경 구성: 603. GoLand - WSL 환경과 연동
12824정성태9/2/2021142오류 유형: 760. 파이썬 tensorflow - Dst tensor is not initialized. 오류 메시지
12823정성태9/2/2021164스크립트: 26. 파이썬 - PyCharm을 이용한 fork 디버그 방법
12822정성태9/1/202197오류 유형: 759. 파이썬 tensorflow - ValueError: Shapes (...) and (...) are incompatible
12821정성태9/1/2021150.NET Framework: 1112. C# - .NET 6부터 공개된 ISpanFormattable 사용법
12820정성태9/1/202187VC++: 147. Golang - try/catch에 대응하는 panic/recover파일 다운로드1
12819정성태8/31/2021182.NET Framework: 1111. C# - FormattableString 타입
12818정성태8/31/2021118Windows: 198. 윈도우 - 작업 관리자에서 (tensorflow 등으로 인한) GPU 연산 부하 보는 방법
12817정성태8/31/202176스크립트: 25. 파이썬 - 윈도우 환경에서 directml을 이용한 tensorflow의 AMD GPU 사용 방법
12816정성태8/30/2021320스크립트: 24. 파이썬 - tensorflow 2.6 NVidia GPU 사용 방법 [2]
12815정성태8/30/2021199개발 환경 구성: 602. WSL 2 - docker-desktop-data, docker-desktop (%LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx) 파일을 다른 디렉터리로 옮기는 방법
[1]  2  3  4  5  6  7  8  9  10  11  12  13  14  15  ...