Microsoft MVP성태의 닷넷 이야기
웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c [링크 복사], [링크+제목 복사]
조회: 11044
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 4개 있습니다.)
웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c
; https://www.sysnet.pe.kr/2/0/12495

.NET Framework: 1014. ASP.NET Core(Kestrel)의 HTTP/2 지원 여부
; https://www.sysnet.pe.kr/2/0/12500

.NET Framework: 1015. .NET 5부터 HTTP/1.1, 2.0 선택을 위한 HttpVersionPolicy 동작 방식
; https://www.sysnet.pe.kr/2/0/12501

.NET Framework: 1016. .NET Core HttpClient의 HTTP/2 지원
; https://www.sysnet.pe.kr/2/0/12502




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://learn.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://learn.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를 사용하거나, (약간 불안하지만 지원이 되도록 빌드한) 바이너리를 다운로드하거나, 또는 직접 빌드하거나 셋 중 하나를 선택하면 됩니다.




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

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/28/2023]

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)
13347정성태5/10/20233933.NET Framework: 2118. C# - Semantic Kernel의 Prompt chaining 예제파일 다운로드1
13346정성태5/10/20233780오류 유형: 858. RDP 원격 환경과 로컬 PC 간의 Ctrl+C, Ctrl+V 복사가 안 되는 문제
13345정성태5/9/20235063.NET Framework: 2117. C# - (OpenAI 기반의) Microsoft Semantic Kernel을 이용한 자연어 처리 [1]파일 다운로드1
13344정성태5/9/20236328.NET Framework: 2116. C# - OpenAI API 사용 - 지원 모델 목록 [1]파일 다운로드1
13343정성태5/9/20234200디버깅 기술: 192. Windbg - Hyper-V VM으로 이더넷 원격 디버깅 연결하는 방법
13342정성태5/8/20234124.NET Framework: 2115. System.Text.Json의 역직렬화 시 필드/속성 주의
13341정성태5/8/20233912닷넷: 2114. C# 12 - 모든 형식의 별칭(Using aliases for any type)
13340정성태5/8/20233931오류 유형: 857. Microsoft.Data.SqlClient.SqlException - 0x80131904
13339정성태5/6/20234620닷넷: 2113. C# 12 - 기본 생성자(Primary Constructors)
13338정성태5/6/20234109닷넷: 2112. C# 12 - 기본 람다 매개 변수파일 다운로드1
13337정성태5/5/20234629Linux: 59. dockerfile - docker exec로 container에 접속 시 자동으로 실행되는 코드 적용
13336정성태5/4/20234391.NET Framework: 2111. C# - 바이너리 출력 디렉터리와 연관된 csproj 설정
13335정성태4/30/20234514.NET Framework: 2110. C# - FFmpeg.AutoGen 라이브러리를 이용한 기본 프로젝트 구성 - Windows Forms파일 다운로드1
13334정성태4/29/20234166Windows: 250. Win32 C/C++ - Modal 메시지 루프 내에서 SetWindowsHookEx를 이용한 Thread 메시지 처리 방법
13333정성태4/28/20233626Windows: 249. Win32 C/C++ - 대화창 템플릿을 런타임에 코딩해서 사용파일 다운로드1
13332정성태4/27/20233721Windows: 248. Win32 C/C++ - 대화창을 위한 메시지 루프 사용자 정의파일 다운로드1
13331정성태4/27/20233744오류 유형: 856. dockerfile - 구 버전의 .NET Core 이미지 사용 시 apt update 오류
13330정성태4/26/20233414Windows: 247. Win32 C/C++ - CS_GLOBALCLASS 설명
13329정성태4/24/20233622Windows: 246. Win32 C/C++ - 직접 띄운 대화창 템플릿을 위한 Modal 메시지 루프 생성파일 다운로드1
13328정성태4/19/20233260VS.NET IDE: 184. Visual Studio - Fine Code Coverage에서 동작하지 않는 Fake/Shim 테스트
13327정성태4/19/20233686VS.NET IDE: 183. C# - .NET Core/5+ 환경에서 Fakes를 이용한 단위 테스트 방법
13326정성태4/18/20235058.NET Framework: 2109. C# - 닷넷 응용 프로그램에서 SQLite 사용 (System.Data.SQLite) [1]파일 다운로드1
13325정성태4/18/20234406스크립트: 48. 파이썬 - PostgreSQL의 with 문을 사용한 경우 연결 개체 누수
13324정성태4/17/20234238.NET Framework: 2108. C# - Octave의 "save -binary ..."로 생성한 바이너리 파일 분석파일 다운로드1
13323정성태4/16/20234140개발 환경 구성: 677. Octave에서 Excel read/write를 위한 io 패키지 설치
13322정성태4/15/20234941VS.NET IDE: 182. Visual Studio - 32비트로만 빌드된 ActiveX와 작업해야 한다면?
1  2  3  4  5  6  7  8  9  10  [11]  12  13  14  15  ...