Nginx

如何防止 HAProxy 丟棄帶有下劃線的 HTTP 標頭

  • June 14, 2017

我們有一個 API 後端伺服器,它需要某些包含下劃線的 HTTP 標頭。我知道這不是最佳做法,標題應該使用連字元,但我無法更改。

我們使用 nginx 作為代理伺服器,選項為underscores_in_headers on. 這會導致 nginx 不刪除這些標頭。

現在我們要切換到 HAProxy 並在配置更改之前作為 nginx 刪除帶有下劃線的標頭。有沒有辦法防止 HAProxy 刪除帶有下劃線的標題?

您是否實際測試過 HAProxy 會丟棄帶有下劃線的標頭?

從原始碼來看,它似乎沒有。在這個答案中,我將嘗試解釋:

  • 為什麼 HTTP 中允許標頭中的下劃線
  • 為什麼 Nginx 預設會丟棄它們
  • 為什麼我相信 HAProxy 不會這樣做。

HTTP/1.1 和 Nginx

根據RFC 7230 3.2.6_中的 HTTP/1.1 規範,標頭欄位中的下劃線 ( ) 沒有任何問題;這並不常見。

欄位值組件

大多數 HTTP 標頭欄位值是使用由空格或特定定界字元分隔的通用語法組件(令牌、引用字元串和註釋)定義的。分隔符是從一組不允許在標記 (DQUOTE(),/:;<=>?@[\]{}) 中使用的 US-ASCII 視覺字元中選擇的。

token         = 1*tchar

tchar         = "!" / "#" / "$" / "%" / "&" / "'" / "*"
              / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
              / DIGIT / ALPHA
              ; any VCHAR, except delimiters

Nginx 陷阱和常見錯誤:失去(消失)HTTP 標頭解釋了為什麼預設情況下它們仍被靜默丟棄:

如果你沒有顯式設置underscores_in_headers on;,NGINX 將默默地丟棄帶有下劃線的 HTTP 標頭(根據 HTTP 標準,這是完全有效的)。這樣做是為了防止在將標頭映射到 CGI 變數時出現歧義,因為在該過程中,破折號和下劃線都映射到下劃線。


HAProxy

不幸的是,HAProxy 沒有這樣的設置。如果您搜尋underscoreHAProxy配置手冊,它只會在環境變數節點名稱(如 DNS 名稱)、代理名稱ACL 名稱的上下文中提及。HTTP 請求章節中沒有提到。

如果 HAProxy 確實刪除了帶有下劃線的標頭,那麼您無法從配置中做任何事情,您必須堅持使用 Nginx 或修改 HAProxy 的原始碼。

但是,我試圖找到 HAProxy 將標頭放在哪裡,但無法從proto_http.c’s 函式void capture_headers()void http_msg_analyzer().

此外,proto_http.c按類型列出所有 ASCII 字元,(),/:;<=>?@[\]{}並列為HTTP_FLG_SEP而下劃線列為普通標記:

495 /* It is about twice as fast on recent architectures to lookup a byte in a
496  * table than to perform a boolean AND or OR between two tests. Refer to
497  * RFC2616/RFC5234/RFC7230 for those chars. A token is any ASCII char that is
498  * neither a separator nor a CTL char. An http ver_token is any ASCII which can
499  * be found in an HTTP version, which includes 'H', 'T', 'P', '/', '.' and any
500  * digit. Note: please do not overwrite values in assignment since gcc-2.95
501  * will not handle them correctly. It's worth noting that chars 128..255 are
502  * nothing, not even control chars.
503  */
504 const unsigned char http_char_classes[256] = {
505     [  0] = HTTP_FLG_CTL,

545     ['('] = HTTP_FLG_SEP,
546     [')'] = HTTP_FLG_SEP,
547     ['*'] = HTTP_FLG_TOK,
548     ['+'] = HTTP_FLG_TOK,
549     [','] = HTTP_FLG_SEP,
550     ['-'] = HTTP_FLG_TOK,
551     ['.'] = HTTP_FLG_TOK | HTTP_FLG_VER,

570     ['A'] = HTTP_FLG_TOK,
571     ['B'] = HTTP_FLG_TOK,
572     ['C'] = HTTP_FLG_TOK,

600     ['_'] = HTTP_FLG_TOK,

這裡,_只是一個普通的HTTP_FLG_TOK,就像A,BC; 它不應該引起任何特別的事情。

引用自:https://serverfault.com/questions/855720