特定の顧客アプリケーションは、リクエストで複数のヘッダーを処理できません。また、同じヘッダー値を持つ重複ヘッダー、または要求内の同じ名前で異なる値を持つ複数のヘッダーの解析は、時間とネットワークリソースを消費します。ポリシー拡張機能を使用すると、これらのヘッダーを元の値を組み合わせた値を持つ単一のヘッダーに結合する関数を追加できます。たとえば、ヘッダー H1 と H2 の値を組み合わせます。
元のリクエスト:
GET /combine_headers HTTP/1.1
User-Agent: amigo unit test
Host: myhost
H2: h2val1
H1: abcd
Accept: \*/\*
H2: h2val2
Content-Length: 0
H2: h2val3
H1: 1234
変更されたリクエスト:
GET /combine_headers HTTP/1.1
User-Agent: amigo unit test
Host: myhost
H2: h2val1, h2val2, h2val3
H1: abcd, 1234
Accept: \*/\*
Content-Length: 0
一般に、このタイプの要求の変更は、ポリシー式を使用して、変更される要求の一部(ターゲット)と実行する変更(文字列ビルダー式)を描写します。ただし、ポリシー式には、任意の数のヘッダーを反復処理する機能はありません。
この問題を解決するには、ポリシー機能への拡張が必要です。これを行うには、COMBINE_HEADERSと呼ばれる拡張関数を定義します。この機能を使用すると、次の書き換えアクションを設定できます。
> add rewrite action combine_headers_act replace 'HTTP.REQ.FULL_HEADER.AFTER_STR("HTTP/1.1rn")' 'HTTP.REQ.FULL_HEADER.AFTER_STR("HTTP/1.1rn").COMBINE_HEADERS'
ここでは、書き換えターゲットは HTTP.REQ.FULL_HEADER.AFTER_STR (「HTTP/1.1rn」) です。FULL_HEADERにはHTTPリクエストの最初の行が含まれているため、AFTER_STR(「HTTP/1.1rn」)が必要です(例:GET /結合ヘッダー HTTP/1.1)。
文字列ビルダー式は HTTP.REQ.FULL_HEADER.AFTER_STR(「HTTP/1.1rn」).COMBINE_HEADERSです。ここで、ヘッダー(最初の行を引いたもの)は、ヘッダーの値を結合して返します。
COMBINE_HEADERS() のサンプル定義:
-- Extension function to combine multiple headers of the same name into one header.
function NSTEXT:COMBINE_HEADERS(): NSTEXT
local headers = {} -- headers
local combined_headers = {} -- headers with final combined values
-- Iterate over each header (format "name:valuer\r\n")
-- and build a list of values for each unique header name.
for name, value in string.gmatch(self, "([^:]+):([^\r\n]*)\r\n") do
if headers[name] then
local next_value_index = #(headers[name]) + 1
headers[name][next_value_index] = value
else
headers[name] = {name .. ":" .. value}
end
end
-- iterate over the headers and concat the values with separator ","
for name, values in pairs(headers) do
local next_header_index = #combined_headers + 1
combined_headers[next_header_index] = table.concat(values, ",")
end
-- Construct the result headers using table.concat()
local result_str = table.concat(combined_headers, "\r\n") .. "\r\n\r\n"
return result_str
end
上記のサンプルの行ごとの説明:
function NSTEXT:COMBINE_HEADERS(): NSTEXT
Defines the COMBINE_HEADERS extension function, with the text input into the function from the policy expression and a text return type to the policy expression.
local headers = {} -- headers
local combined_headers = {} -- headers with final combined values
Declares local variables headers and combined_headers and initialize these variables to empty tables. headers will be a table of arrays of strings, where each array holds one or more values for a header. combined_headers will be an array of strings, where each array element is a header with its combined values.
for name, value in string.gmatch(self, "([^:]+):([^\r\n]*)\r\n") do
. . .
end
この汎用的な for ループは、入力の各ヘッダーを解析します。イテレータは、組み込みのstring.gmatch()関数です。この関数は、検索する文字列と、文字列の一部を一致させるために使用するパターンの 2 つのパラメータを取ります。検索する文字列は、関数に入力されたヘッダーのテキストである暗黙のselfパラメータによって提供されます。
パターンは、正規表現(短い場合は正規表現)を使用して表現されます。この正規表現は、HTTP 標準では name: value rn として定義されている、各ヘッダーのヘッダー
名と**値に一致します。正規表現の括弧は抽出する一致する部分を指定するので、正規表現の回路図は(
match-name):(
match-value)rnです。
match-name パターンは、コロン以外のすべての文字と一致する必要があります。これは [\^: + (
:]以外の任意の文字、+ は 1 つ以上の繰り返し) と書かれています。同様に、
マッチ値パターンは \ r\ n 以外の任意の文字と一致する必要があるため、
以外の任意の文字に一致し、 はゼロ以上の繰り返しです) と書かれます。これにより、完全な正規表現(
+):(
*)\r\nになります。
for文は、string.gmatch()イテレータによって返された2つの一致に名前と値を設定するために、複数の割り当てを使用しています。これらは、forループの本体内でローカル変数として暗黙的に宣言されています。
if headers[name] then
local next_value_index = #(headers[name]) + 1
headers[name][next_value_index] = value
else
headers[name] = {name .. ":" .. value}
end
forループ内のこれらのステートメントは、ヘッダー名と値をヘッダーテーブルに入れます。ヘッダー名を初めて解析する場合 (たとえば、入力例では H2: h2val1)、名前のヘッダーエントリはなく、
nil です。
nilはfalseとして扱われるので、else節が実行されます。これは、name のヘッダエントリを 1 つの文字列値 name:value を持つ配列に設定します。
注意: else ループの配列コンストラクタは {
= name と同じです。「:」.. value}。配列の最初の要素を設定します。)最初の H2 ヘッダーには、headers
= {"H2:h2val1"}を設定します。
ヘッダーの後続のインスタンス(たとえば、入力例ではH2:h2val2)。headers
はnilではないので、then 節が実行されます。これは、headers
の配列値の中で次に使用可能なインデックスを決定し、そのインデックスにヘッダー値を置きます。2番目のH2ヘッダーについては、headers
={"H2:h2val1", "h2val2"}を設定します。
for name, values in pairs(headers) do
local next_header_index = #combined_headers + 1
combined_headers[next_header_index] = table.concat(values, ",")
end
元のヘッダーが解析され、ヘッダーテーブルが入力された後、このループは combined_headers 配列を構築します。これは、forループイテレータとしてpairs()関数を使用しています。
pairs()を呼び出すたびに、ヘッダーテーブル内の次のエントリの名前と値を返します。
次の行は、combined_headers 配列内の次に使用可能なインデックスを決定し、次の行は、結合されたヘッダーにその配列要素を設定します。組み込みの table.concat () 関数を使用します。この関数は、引数として文字列の配列と文字列をセパレータとして使用し、セパレータで区切られた配列文字列を連結した文字列を返します。
たとえば、値= {"H2:h2val1", "h2val2"}の場合、これは"H2:h2val1, h2val2"を生成します
local result_str = table.concat(combined_headers, "\r\n") .. "\r\n\r\n"
combined_headers配列が構築された後、要素を1つの文字列に連結し、HTTPヘッダーを終了する二重のrnを追加します。
return result_str
COMBINE_HEADERS 拡張関数の結果として文字列を返します。