Software /
code /
prosody
Changeset
13124:f15e23840780
util.http: Implement parser for RFC 7239 Forwarded header
Standardized and structured replacement for the X-Forwarded-For,
X-Forwarded-Proto set of headers.
Notably, this allows per-hop protocol information, unlike
X-Forwarded-Proto which is always a single value for some reason.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sat, 03 Jun 2023 16:15:52 +0200 |
parents | 13123:dee26e4cfb2b |
children | 13125:90394be5e6a5 |
files | doc/doap.xml spec/util_http_spec.lua util/http.lua |
diffstat | 3 files changed, 55 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/doap.xml Thu Jun 01 14:33:57 2023 +0200 +++ b/doc/doap.xml Sat Jun 03 16:15:52 2023 +0200 @@ -56,6 +56,7 @@ <implements rdf:resource="https://www.rfc-editor.org/info/rfc6455"/> <implements rdf:resource="https://www.rfc-editor.org/info/rfc6901"/> <implements rdf:resource="https://www.rfc-editor.org/info/rfc7233"/> + <implements rdf:resource="https://www.rfc-editor.org/info/rfc7239"/> <implements rdf:resource="https://www.rfc-editor.org/info/rfc7301"/> <implements rdf:resource="https://www.rfc-editor.org/info/rfc7395"/> <implements rdf:resource="https://www.rfc-editor.org/info/rfc7590"/>
--- a/spec/util_http_spec.lua Thu Jun 01 14:33:57 2023 +0200 +++ b/spec/util_http_spec.lua Sat Jun 03 16:15:52 2023 +0200 @@ -108,4 +108,25 @@ assert.is_(http.contains_token("fo o", "foo")); end); end); + +do + describe("parse_forwarded", function() + it("works", function() + assert.same({ { ["for"] = "[2001:db8:cafe::17]:4711" } }, http.parse_forwarded('For="[2001:db8:cafe::17]:4711"'), "case insensitive"); + + assert.same({ { ["for"] = "192.0.2.60"; proto = "http"; by = "203.0.113.43" } }, http.parse_forwarded('for=192.0.2.60;proto=http;by=203.0.113.43'), + "separated by semicolon"); + + assert.same({ { ["for"] = "192.0.2.43" }; { ["for"] = "198.51.100.17" } }, http.parse_forwarded('for=192.0.2.43, for=198.51.100.17'), + "Values from multiple proxy servers can be appended using a comma"); + + end) + it("rejects quoted quotes", function () + assert.falsy(http.parse_forwarded('foo="bar\"bar'), "quoted quotes"); + end) + pending("deals with quoted quotes", function () + assert.same({ { foo = 'bar"baz' } }, http.parse_forwarded('foo="bar\"bar'), "quoted quotes"); + end) + end) +end end);
--- a/util/http.lua Thu Jun 01 14:33:57 2023 +0200 +++ b/util/http.lua Sat Jun 03 16:15:52 2023 +0200 @@ -69,9 +69,42 @@ return path; end +--- Parse the RFC 7239 Forwarded header into array of key-value pairs. +local function parse_forwarded(forwarded) + if type(forwarded) ~= "string" then + return nil; + end + + local fwd = {}; -- array + local cur = {}; -- map, to which we add the next key-value pair + for key, quoted, value, delim in forwarded:gmatch("(%w+)%s*=%s*(\"?)([^,;\"]+)%2%s*(.?)") do + -- FIXME quoted quotes like "foo\"bar" + -- unlikely when only dealing with IP addresses + if quoted == '"' then + value = value:gsub("\\(.)", "%1"); + end + + cur[key:lower()] = value; + if delim == "" or delim == "," then + t_insert(fwd, cur) + if delim == "" then + -- end of the string + break; + end + cur = {}; + elseif delim ~= ";" then + -- misparsed + return false; + end + end + + return fwd; +end + return { urlencode = urlencode, urldecode = urldecode; formencode = formencode, formdecode = formdecode; contains_token = contains_token; normalize_path = normalize_path; + parse_forwarded = parse_forwarded; };