QUIC 傳輸協議具有HTTP 傳輸所需的幾個特性,例如stream multiplexing、每個流的流控制和低延遲連接建立。本文檔描述了HTTP 語義在QUIC 上的映射。本文還介紹了QUIC 包含的HTTP/2 功能,並描述瞭如何將HTTP/2 擴展移植到HTTP/3。
簡介HTTP語義([HTTP])在互聯網上廣泛應用於各種服務。這些語義最常用於HTTP/1.1和HTTP/2。 HTTP/1.1被用於各種傳輸和會話層,而HTTP/2主要用於TCP上的TLS。 HTTP/3在一個新的傳輸協議上支持相同的語義:QUIC。
1.1 HTTP的早期版本HTTP/1.1 ([HTTP/1.1])使用空格分隔的文本字段來傳遞HTTP消息。雖然這些交換是人類可讀的,但使用空格進行消息格式化會導致解析複雜性和對變體行為的過度容忍。
由於HTTP/1.1不包括多路復用層,因此通常使用多個TCP 連接來並行處理請求。然而,這對擁塞控制(congestion control)和網絡效率有負面影響,因為TCP 不跨多個連接共享擁塞控制。
HTTP/2 引入了一個二進制幀和多路復用層,在不修改傳輸層的情況下改善了延遲。然而,由於HTTP/2的多路復用的並行特性對TCP的丟失恢復機制是不可見的,因此丟失或重新排序的數據包會導致所有活動事務都經歷停頓,無論該事務是否直接受到丟失數據包的影響。
1.2 委託給QUICQUIC 傳輸協議結合了stream multiplexing和每個流的流控制,類似於HTTP/2幀層提供的。通過提供流級別的可靠性和整個連接的擁塞控制,與TCP映射相比,QUIC有能力提高HTTP的性能。 QUIC還在傳輸層合併了TLS 1.3 ([TLS]),提供了與在TCP上運行TLS相當的機密性和完整性,並改善了TCP快速打開([TFO])的連接設置延遲。
本文定義了HTTP/3:HTTP 語義在QUIC 傳輸協議上的映射,大量借鑒了HTTP/2 的設計。 HTTP/3 依賴於QUIC 來提供數據的機密性和完整性保護;對等認證;可靠、有序、按流交付。在將流生命週期和流控制問題委託給QUIC 時,每個流都使用類似於HTTP/2 幀的二進制幀。 QUIC 包含一些HTTP/2 功能,而其他功能則在QUIC 之上實現。
2.HTTP/3協議概述HTTP/3使用QUIC傳輸協議和類似於HTTP/2的內部幀層為HTTP語義提供了傳輸。
一旦客戶端知道某個終端存在HTTP/3 服務器,它就會打開一個QUIC 連接。 QUIC 提供協議協商、基於流的多路復用和流控制。
在每個流中,HTTP/3 通信的基本單位是一個幀。每種幀類型都有不同的用途。例如,HEADERS 和DATA 幀構成了HTTP 請求和響應的基礎)。適用於整個連接的幀在專用控制流上傳輸。
請求的多路復用是使用QUIC流抽象來執行的,這在[QUIC- transport]的第2節中描述。每個請求-響應對使用一個QUIC流。流之間是相互獨立的,所以一個流被阻止或丟失不會影響其他流的進程。
服務器推送是HTTP/2中引入的一種交互方案,它允許服務器在客戶端發出指定請求之前向客戶端推送一個請求-響應交換。這就權衡了網絡使用和潛在的延遲增益。一些HTTP/3幀被用來管理服務器推送,例如PUSH_PROMISE,MAX_PUSH_ID和CANCEL_PUSH。
與HTTP/2 一樣,請求和響應字段被壓縮以進行傳輸。因為HPACK ([HPACK]) 依賴於壓縮字段部分的順序傳輸(QUIC 不提供保證),所以HTTP/3 用QPACK ([QPACK]) 替換了HPACK。 QPACK 使用單獨的單向流來修改和跟踪字段表狀態,而編碼字段部分引用表的狀態而不修改它。
3.連接設置和管理3.1 發現HTTP/3終端HTTP依賴權威的概念響應:在給定目標資源在響應消息由源服務器發起(或在其方向)時的狀態的情況下,該響應已被確定為對該請求最合適的響應在目標URI 中標識。
“https”方案將授權與擁有證書相關聯,客戶端認為該證書對於由URI 的授權組件標識的主機是可信賴的。在TLS 握手中接收到服務器證書後,客戶端必須驗證證書是否與URI的源服務器匹配。如果證書無法針對URI 的源服務器進行驗證,則客戶端不得認為服務器對該源具有權威性。
客戶端可以嘗試通過將主機標識符解析為IP 地址來嘗試訪問具有“https”URI 的資源,在指定端口上建立到該地址的QUIC 連接(包括如上所述的服務器證書驗證),並通過該安全連接向服務器發送以URI為目標的HTTP/3請求消息。除非使用其他機制來選擇HTTP/3,否則在TLS 握手期間在應用層協議協商擴展中使用令牌“h3”。
連接問題(例如,阻止UDP)可能導致無法建立一個QUIC連接;在這種情況下,客戶端應該嘗試使用基於TCP 的HTTP 版本。
服務器可以在任何UDP 端口上提供HTTP/3;替代服務廣告始終包含明確地端口,並且URI 包含與方案關聯的明確地端口或默認端口。
3.1.1HTTP替代服務HTTP 源可以使用“h3”ALPN 令牌通過Alt-Svc HTTP 響應頭字段或HTTP/2 ALTSVC 幀([ALTSVC]) 通告等效HTTP/3 終端的可用性。
例如,在HTTP響應中,通過包含以下標頭字段,可以表明HTTP/3在UDP端口50781上相同主機名是可用的:
Alt-Svc: h3=':50781'
在接收到表示HTTP/3支持的Alt-Svc記錄時,客戶端可以嘗試建立到指定主機和端口的QUIC連接;如果連接成功,客戶端可以使用本文檔中描述的映射發送HTTP請求。
3.1.2其他方案儘管HTTP獨立於傳輸協議,但“HTTP”方案將權限與在權限組件中標識的任何主機的指定端口上接收TCP連接的能力相關聯。由於HTTP/3不使用TCP,所以HTTP/3不能用於直接訪問由“HTTP”URI標識的資源的權威服務器。然而,諸如[ALTSVC]這樣的協議擴展允許授權服務器識別其他同樣具有授權且可能通過HTTP/3可訪問的服務。
當向方案不是“https”的源發起請求之前,客戶端必須確保服務器願意為該方案提供服務。對於方案為“http”的源,我們會在之後介紹實現此目的的實驗方法。
3.2 建立連接HTTP/3依賴於QUIC版本1作為底層傳輸,未來的規範可能會定義使用HTTP/3 的其他QUIC 傳輸版本。
QUIC 版本1 使用TLS 版本1.3 或更高版本作為其握手協議。 HTTP/3 客戶端必須支持在TLS 握手期間向服務器指示目標主機的機制。如果服務器由域名([DNS-TERMS]) 標識,則客戶端必鬚髮送服務器名稱指示(SNI; [RFC6066]) TLS 擴展,除非有另一種機制來指示使用的目標主機。
在建立連接期間,通過在TLS握手中選擇ALPN令牌“h3”來表示對HTTP/3的支持。對其他應用層協議的支持可以在相同的握手中提供。
雖然與核心QUIC 協議有關的連接級別選項是在初始加密握手中設置的,但特定於HTTP/3 的設置在SETTINGS 幀中傳遞。在建立了QUIC連接之後,每個終端必鬚髮送一個SETTINGS幀作為它們各自的HTTP控制流的初始幀。
3.3 連接重用HTTP/3連接是跨多個請求的持久連接。為了獲得最佳性能,客戶端在確定不再需要與服務器進行進一步通信之前(例如,當用戶導航離開某個特定的網頁時)不會關閉連接,或者直到服務器關閉連接。
一旦存在到服務器終端的連接,該連接可以被重用於具有多個不同URI 權限組件的請求。要使用一個現有的連接到一個新的源,客戶端必須驗證服務器為新的源服務器提供的證書。這意味著客戶端將需要保留服務器證書和驗證該證書所需的任何額外信息,否則客戶端將無法為其他源重用連接。
如果證書由於任何原因對於新源不可接受,則不得重用連接,並且應該為新源建立新連接。如果證書無法驗證的原因可能適用於已經與連接關聯的其他來源,客戶端應該重新驗證這些來源的服務器證書。例如,如果由於證書已過期或被吊銷而導致證書驗證失敗,則這可能用於使該證書用於建立權限的所有其他來源無效。
客戶端不應打開多個到給定IP 地址和UDP 端口的HTTP/3 連接,其中IP 地址和端口可能來自URI、選定的替代服務([ALTSVC])、配置的代理或名稱解析其中任何一個。客戶端可以使用不同的傳輸或TLS 配置打開到相同IP 地址和UDP 端口的多個HTTP/3 連接,但應避免使用相同配置創建多個連接。
服務器應盡可能長時間地保持打開的HTTP/3 連接,但在必要時允許終止空閒連接。當任何一個終端選擇關閉HTTP/3連接時,終止的終端應該首先發送一個GOAWAY 幀,以便兩個終端能夠可靠地確定之前發送的幀是否已經被處理並完成或終止任何必要的剩餘任務。
如果服務器不希望客戶端重用HTTP/3連接,它可以發送一個421(錯誤定向請求)狀狀態代碼來響應請求來表明它對請求不具有權威性。
4.在HTTP/3中表達HTTP語義4.1HTTP 消息幀客戶端在請求流上發送HTTP 請求,請求流是客戶端發起的雙向QUIC 流。客戶端必須在給定的流上只發送一個請求。服務器在與請求相同的流上發送零個或多個臨時HTTP響應,然後是一個最終HTTP響應,詳細信息如下。
推送響應在服務器發起的單向QUIC流上發送,服務器以與標準響應相同的方式發送零個或多個臨時HTTP響應,然後是一個最終HTTP響應。在給定的流中,收到多個請求或在最終HTTP 響應之後收到額外的HTTP 響應必須被視為格式錯誤。
一個HTTP消息(請求或響應)包括:
標頭部分,包括消息控制數據,作為單個標頭幀發送;
可選地,如果內容存在,則以一系列數據幀的形式發送;
可選地,尾部部分(如果存在)作為單個HEADERS 幀發送。
接收到無效的幀序列必須被視為H3_FRAME_UNEXPECTED 類型的連接錯誤。特別是,任何HEADERS 幀之前的DATA 幀,或尾部HEADERS 幀之後的HEADERS 或DATA 幀,都被認為是無效的。其他幀類型,尤其是未知幀類型,可能會根據它們自己的規則被允許。
服務器可以在響應消息的幀之前、之後或與響應消息的幀交錯發送一個或多個PUSH_PROMISE 幀。這些PUSH_PROMISE 幀不是響應的一部分。 push stream上不允許使用PUSH_PROMISE 幀;包含PUSH_PROMISE 幀的推送響應必須被視為H3_FRAME_UNEXPECTED 類型的連接錯誤。
HEADERS 和PUSH_PROMISE 幀可能會引用對QPACK 動態表的更新。雖然這些更新不是消息交換的直接部分,但必須先接收和處理它們,然後才能使用消息。
傳輸編碼沒有為HTTP/3定義;Transfer-Encoding標頭字段絕對不能被使用。
當且僅當一個或多個臨時響應在對同一請求的最終響應之前,響應可能包含多個消息。臨時響應不包含內容或預告片部分。
HTTP 請求/響應交換完全使用客戶端發起的雙向QUIC 流。發送請求後,客戶端必須關閉要發送的流。除非使用CONNECT 方法,否則客戶端不得依賴於接收到對其請求的響應來進行流關閉。發送最終響應後,服務器必須關閉要發送的流。此時,QUIC 流已完全關閉。
當流關閉時,這表示最終HTTP消息的結束。因為有些消息很大或沒有綁定,所以一旦接收到足夠的消息以進行處理,終端就應該開始處理部分HTTP消息。如果客戶端發起的流終止時沒有足夠的HTTP消息來提供完整的響應,服務器應該以錯誤碼H3_REQUEST_INCOMPLETE終止其響應流。
如果響應不依賴於尚未發送和接收的請求的任何部分,服務器可以在客戶端發送整個請求之前發送一個完整的響應。當服務器不需要接收請求的剩餘部分時,它可以中止讀取請求流,發送一個完整的響應,並關閉流的發送部分。當請求客戶端停止發送請求流時,應該使用錯誤碼H3_NO_ERROR。客戶絕對不能因為他們的請求被突然終止而刪除完整的回复,儘管客戶總是可以根據自己的判斷刪除其他原因的回复。如果服務器發送了部分或完整的響應,但沒有終止讀取請求,客戶端應該繼續發送請求的內容,並正常關閉流。
4.1.1取消和拒絕請求一旦請求流被打開,請求可以被任何一個終端取消。如果對響應不再感興趣,客戶端會取消請求;如果服務器無法或選擇不響應請求,則會取消請求。如果可能,建議服務器發送一個帶有適當狀態碼的HTTP響應,而不是取消它已經開始處理的請求。
實現應該通過突然終止流中仍然打開的任何方向來取消請求。為此,實現重置流的發送部分,併中止流的接收部分的讀取。
當服務器取消請求而不執行任何應用程序處理時,該請求被認為是“被拒絕”的。服務器應該中止包含錯誤代碼H3_REQUEST_REJECTED的響應流。在這種情況下,“已處理”意味著流中的一些數據被傳遞到軟件的較高層,該軟件可能因此採取了一些操作。客戶端可以將被服務器拒絕的請求當作從未發送過,從而允許它們稍後重試。
對於部分或全部處理的請求,服務器不得使用H3_REQUEST_REJECTED 錯誤代碼。當服務器在部分處理後放棄響應時,它應該以錯誤代碼H3_REQUEST_CANCELLED 中止其響應流。
客戶端應該使用錯誤代碼H3_REQUEST_CANCELLED來取消請求。在接收到此錯誤碼後,如果沒有執行任何處理,服務器可能會使用錯誤碼H3_REQUEST_REJECTED突然終止響應。客戶端絕對不能使用H3_REQUEST_REJECTED錯誤碼,除非服務端使用此錯誤碼請求關閉請求流。
如果在收到完整響應後取消流,客戶端可以忽略取消並使用響應。但是,如果在收到部分響應後取消流,則不應使用響應。只有GET、PUT 或DELETE 等冪等操作可以安全地重試;客戶端不應該使用非冪等方法自動重試請求,除非它有某種方法可以知道請求語義是獨立於方法的冪等,或者有某種方法可以檢測到原始請求從未被應用。
4.1.2 格式錯誤的請求和響應格式錯誤的請求或響應是一個有效的幀序列,但由於以下原因而無效:禁止字段或偽標頭字段的存在;
沒有強制性的偽標頭字段;
偽標頭字段的無效值;
字段後的偽標頭字段;
無效的HTTP 消息序列;
包含大寫字段名稱;
在字段名稱或值中包含無效字符。
如果一個請求或響應被定義為包含content - length標頭字段,如果content - length標頭字段的值不等於接收到的數據幀長度之和,則該請求或響應是不規範的。一個被定義為永遠沒有內容的響應,即使有content - length,也可以有一個非零的content - length標頭字段,即使數據幀中沒有包含任何內容。
處理HTTP 請求或響應的中介(即任何不充當隧道的中介)不得轉發格式錯誤的請求或響應。檢測到的格式錯誤的請求或響應必須被視為H3_MESSAGE_ERROR 類型的流錯誤。
對於格式錯誤的請求,服務器可以在關閉或重置流之前發送一個指示錯誤的HTTP 響應。客戶端不得接受格式錯誤的響應。請注意,這些要求旨在防止針對HTTP 的幾種常見攻擊;它們是故意嚴格的,因為允許可能暴露這些漏洞的實現。
4.2 HTTP字段HTTP消息以一系列項值對的形式攜帶元數據,稱為“HTTP字段”。與HTTP/2類似,HTTP/3還有一些額外的注意事項,包括字段名、連接標頭字段和偽標頭字段中的字符的使用。
字段名是包含ASCII字符子集的字符串。字段名中的字符必須在編碼之前轉換為小寫。字段名稱中包含大寫字符的請求或響應必須被視為格式不正確。
HTTP/3 不使用Connection 頭字段來指示特定於連接的字段;在此協議中,特定於連接的元數據通過其他方式傳送。終端絕對不能生成包含連接特定字段的HTTP/3字段部分;任何包含連接特定字段的消息都必須被視為格式錯誤。
唯一的例外是TE標頭字段,它可能出現在HTTP/3請求標頭中;如果是,它不能包含除“trailers”之外的任何值。
將HTTP/1.x 消息轉換為HTTP/3 的中介必須刪除連接特定的標頭字段,否則它們的消息將被其他HTTP/3 終端視為格式錯誤。
4.2.1 字段壓縮(field compression)[QPACK]描述了HPACK的一個變體,它使編碼器能夠控制由壓縮引起的標頭阻止的數量。這允許編碼器平衡壓縮效率和延遲。 HTTP/3 使用QPACK 來壓縮頭部和尾部部分,包括出現在標頭部分的控制數據。
為了提高壓縮效率,在壓縮之前,Cookie 標頭字段([COOKIES])可以拆分為單獨的字段行,每行包含一個或多個cookie 對。如果一個解壓縮的字段部分包含多個cookie字段行,則在傳遞到HTTP/2 或HTTP/3 以外的上下文之前,必須使用“;”的兩字節分隔符(ASCII0x3b,0x20)將它們連接成單個字節字符串,例如HTTP/1.1 連接,或通用HTTP 服務器應用程序。
4.2.2 標頭大小限制HTTP/3實現可能會對單個HTTP消息接受的消息標頭的最大大小施加限制。如果服務器接收到的標頭區域比它願意處理的更大,它可以發送一個HTTP 431(請求標頭字段太大)狀態碼([RFC6585])。客戶端可以刪除它無法處理的響應。字段列表的大小是根據未壓縮的字段大小計算的,包括名稱和值的長度(以字節為單位),外加每個字段的32字節開銷。
如果一個實現希望將此限制通知其對等方,則可以在SETTINGS_MAX_FIELD_SECTION_SIZE 參數中將其作為字節數傳送。接收到此參數的實現不應該發送超過指示大小的HTTP 消息標頭,因為對等方可能會拒絕處理它。但是,HTTP 消息在到達源服務器之前可以經過一個或多個中介。因為這個限制是由處理消息的每個實現單獨應用的,所以不能保證低於這個限制的消息被接受。
4.3. HTTP控制數據與HTTP/2類似,HTTP/3使用了一系列偽標頭字段,其中字段名以字符(ASCII0x3a)開頭。這些偽標頭字段傳遞消息控制數據。
偽標頭字段不是HTTP字段。終端絕對不能生成除本文檔中定義的那些以外的偽標頭字段。然而,延期可以協商修改此限制。
偽標頭字段僅在定義它們的上下文中有效。為請求定義的偽標頭字段絕對不能出現在響應中;為響應定義的偽標頭字段絕對不能出現在請求中。偽標頭字段絕對不能出現在尾部部分。終端必須將包含未定義或無效偽標頭字段的請求或響應視為格式錯誤。
所有的偽標頭字段必須出現在普通標頭字段之前的標頭部分。任何包含出現在普通標頭字段之後的標頭部分中的偽標頭字段的請求或響應都必須被視為格式錯誤。
4.3.1. 請求偽標頭字段為請求定義了以下偽標頭字段:
':method':包含HTTP方法;
':scheme':包含目標URI的方案部分。
:scheme偽標頭不局限於具有“http”和“https”方案的URI。代理或網關可以轉換非HTTP方案的請求,使HTTP 能夠與非HTTP 服務進行交互。
':authority':包含目標URI的權限部分,權限不得包含方案“http”或“https”的URI 的已棄用userinfo 子組件。
為確保HTTP/1.1 請求行可以準確再現,當從具有特定方法形式的請求目標的HTTP/1.1 請求轉換時,必須省略此偽標頭字段。直接生成HTTP/3 請求的客戶端應該使用:authority 偽標頭字段而不是Host 標頭字段。如果請求中沒有Host字段,則將HTTP/3 請求轉換為HTTP/1.1 的中介必須通過複製:authority 偽標頭字段的值來創建Host字段。
':path':包含目標URI的路徑和查詢部分後跟“查詢”結果。
對於“http”或“https”URI,此偽頭字段不得為空;不包含路徑組件的“http”或“https”URI 必須包含值/(ASCII0x2f)。不包含路徑組件的OPTIONS 請求包含:path 偽標頭字段的值* (ASCII0x2a)。
所有HTTP/3 請求必須只包含一個:method、scheme 和:path 偽標頭字段的值,除非請求是CONNECT 請求。
如果:scheme 偽標頭字段標識了具有強制權限組件(包括“http”和“https”)的方案,則請求必須包含:authority 偽標頭字段或Host 標頭字段。如果這些字段存在,則它們不得為空。如果兩個字段都存在,它們必須包含相同的值。如果該方案沒有強制授權組件並且在請求目標中沒有提供任何內容,則請求不得包含:authority 偽標頭或Host 標頭字段。
如果一個HTTP請求省略了強制的偽標頭字段或者包含了這些偽標頭字段的無效值,那麼這個請求就是不規範的。
HTTP/3沒有定義攜帶HTTP/1.1請求行中包含的版本標識符的方法。 HTTP/3請求隱含的協議版本是“3.0”。
4.3.2. 響應偽標頭字段對於響應,定義了一個帶有HTTP 狀態代碼的“:status”偽標頭字段。這個偽標頭字段必須包含在所有響應中,否則,響應格式錯誤。
HTTP/3沒有定義一種方式來攜帶包含在HTTP/1.1狀態行中的版本或原因短語。 HTTP/3響應隱含的協議版本是“3.0”。
4.4. 連接方法CONNECT 方法請求接收方建立一條到請求目標標識的目標源服務器的隧道,它主要與HTTP 代理一起使用,以與源服務器建立TLS 會話,以便與“https”資源進行交互。
在HTTP/1.x 中,CONNECT 用於將整個HTTP 連接轉換為到遠程主機的隧道。在HTTP/2 和HTTP/3 中,CONNECT 方法用於在單個流上建立隧道。
CONNECT請求構造如下:
:method 偽標頭字段設置為“CONNECT”;
:scheme 和:path 偽標頭字段被省略;
:authority 偽標頭字段包含要連接的主機和端口,相當於CONNECT 請求的請求目標的權限形式。
請求流在請求結束時保持打開狀態,以攜帶要傳輸的數據。不符合這些限制的CONNECT請求是不正確的。
支持CONNECT 的代理與:authority 偽標頭字段中標識的服務器建立TCP 連接([RFC0793])。一旦成功建立此連接,代理就會向客戶端發送一個包含2xx 系列狀態代碼的HEADERS 幀。
流上的所有數據幀都對應於TCP連接上發送或接收的數據。客戶端發送的任何數據幀的有效載荷都由代理傳輸給TCP服務器,從TCP服務器接收到的數據被代理打包成數據幀。請注意,不能保證TCP 段的大小和數量可預測地映射到HTTP DATA 或QUIC STREAM 幀的大小和數量。
C
Recommended Comments