Microsoft MVP성태의 닷넷 이야기
웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c [링크 복사], [링크+제목 복사]
조회: 11025
글쓴 사람
정성태 (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)
13398정성태8/3/20234135스크립트: 55. 파이썬 - pyodbc를 이용한 SQL Server 연결 사용법
13397정성태7/23/20233642닷넷: 2134. C# - 문자열 연결 시 string.Create를 이용한 GC 할당 최소화
13396정성태7/22/20233341스크립트: 54. 파이썬 pystack 소개 - 메모리 덤프로부터 콜 스택 열거
13395정성태7/20/20233311개발 환경 구성: 685. 로컬에서 개발 중인 ASP.NET Core/5+ 웹 사이트에 대해 localhost 이외의 호스트 이름으로 접근하는 방법
13394정성태7/16/20233254오류 유형: 873. Oracle.ManagedDataAccess.Client - 쿼리 수행 시 System.InvalidOperationException
13393정성태7/16/20233420닷넷: 2133. C# - Oracle 데이터베이스의 Sleep 쿼리 실행하는 방법
13392정성태7/16/20233297오류 유형: 872. Oracle - ORA-01031: insufficient privileges
13391정성태7/14/20233368닷넷: 2132. C# - sealed 클래스의 메서드를 callback 호출했을 때 인라인 처리가 될까요?
13390정성태7/12/20233339스크립트: 53. 파이썬 - localhost 호출 시의 hang 현상
13389정성태7/5/20233322개발 환경 구성: 684. IIS Express로 호스팅하는 웹을 WSL 환경에서 접근하는 방법
13388정성태7/3/20233512오류 유형: 871. 윈도우 탐색기에서 열리지 않는 zip 파일 - The Compressed (zipped) Folder '[...].zip' is invalid. [1]파일 다운로드1
13387정성태6/28/20233531오류 유형: 870. _mysql - Commands out of sync; you can't run this command now
13386정성태6/27/20233601Linux: 61. docker - 원격 제어를 위한 TCP 바인딩 추가
13385정성태6/27/20233817Linux: 60. Linux - 외부에서의 접속을 허용하기 위한 TCP 포트 여는 방법
13384정성태6/26/20233565.NET Framework: 2131. C# - Source Generator로 해결하는 enum 박싱 문제파일 다운로드1
13383정성태6/26/20233313개발 환경 구성: 683. GPU 런타임을 사용하는 Colab 노트북 설정
13382정성태6/25/20233356.NET Framework: 2130. C# - Win32 API를 이용한 윈도우 계정 정보 (예: 마지막 로그온 시간)파일 다운로드1
13381정성태6/25/20233741오류 유형: 869. Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
13380정성태6/24/20233195스크립트: 52. 파이썬 3.x에서의 동적 함수 추가
13379정성태6/23/20233209스크립트: 51. 파이썬 2.x에서의 동적 함수 추가
13378정성태6/22/20233094오류 유형: 868. docker - build 시 "CANCELED ..." 뜨는 문제
13377정성태6/22/20236892오류 유형: 867. 파이썬 mysqlclient 2.2.x 설치 시 "Specify MYSQLCLIENT_CFLAGS and MYSQLCLIENT_LDFLAGS env vars manually" 오류
13376정성태6/21/20233283.NET Framework: 2129. C# - Polly를 이용한 클라이언트 측의 요청 재시도파일 다운로드1
13375정성태6/20/20232984스크립트: 50. Transformers (신경망 언어모델 라이브러리) 강좌 - 2장 코드 실행 결과
13374정성태6/20/20233110오류 유형: 866. 파이썬 - <class 'AttributeError'> module 'flask.json' has no attribute 'JSONEncoder'
13373정성태6/19/20234398오류 유형: 865. 파이썬 - pymssql 설치 관련 오류 정리
1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...