diff options
| author | Caleb Maclennan <caleb@alerque.com> | 2026-08-31 11:03:24 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-31 11:03:24 +0300 |
| commit | 5afe174eeffc7f3e3b9ef80b5871237620c68415 (patch) | |
| tree | 85c8bb14a445823dc7a683a53394901523f5f16b /src/headers.lua | |
| parent | b836466de5a78e9b4f29ca6c85a2bdecd7c69da9 (diff) | |
| parent | 3dd5fb0468977c6626fe4a0ea7b95222f14da09f (diff) | |
| download | luasocket-5afe174eeffc7f3e3b9ef80b5871237620c68415.tar.gz luasocket-5afe174eeffc7f3e3b9ef80b5871237620c68415.tar.bz2 luasocket-5afe174eeffc7f3e3b9ef80b5871237620c68415.zip | |
Merge pull request #470 from lunarmodules/header-canon
feat(headers): dynamically create cononicalized headers
Diffstat (limited to 'src/headers.lua')
| -rw-r--r-- | src/headers.lua | 148 |
1 files changed, 54 insertions, 94 deletions
diff --git a/src/headers.lua b/src/headers.lua index 1eb8223..004ef37 100644 --- a/src/headers.lua +++ b/src/headers.lua | |||
| @@ -7,98 +7,58 @@ local socket = require("socket") | |||
| 7 | socket.headers = {} | 7 | socket.headers = {} |
| 8 | local _M = socket.headers | 8 | local _M = socket.headers |
| 9 | 9 | ||
| 10 | _M.canonic = { | 10 | -- capitalizes the first letter of each hyphen-separated word, lowercases |
| 11 | ["accept"] = "Accept", | 11 | -- the rest (e.g. "x-request-id" -> "X-Request-Id") |
| 12 | ["accept-charset"] = "Accept-Charset", | 12 | local function titlecase(header) |
| 13 | ["accept-encoding"] = "Accept-Encoding", | 13 | return (header:gsub("(%a)([%w]*)", function(a, b) return a:upper()..b:lower() end)) |
| 14 | ["accept-language"] = "Accept-Language", | 14 | end |
| 15 | ["accept-ranges"] = "Accept-Ranges", | ||
| 16 | ["action"] = "Action", | ||
| 17 | ["alternate-recipient"] = "Alternate-Recipient", | ||
| 18 | ["age"] = "Age", | ||
| 19 | ["allow"] = "Allow", | ||
| 20 | ["arrival-date"] = "Arrival-Date", | ||
| 21 | ["authorization"] = "Authorization", | ||
| 22 | ["bcc"] = "Bcc", | ||
| 23 | ["cache-control"] = "Cache-Control", | ||
| 24 | ["cc"] = "Cc", | ||
| 25 | ["comments"] = "Comments", | ||
| 26 | ["connection"] = "Connection", | ||
| 27 | ["content-description"] = "Content-Description", | ||
| 28 | ["content-disposition"] = "Content-Disposition", | ||
| 29 | ["content-encoding"] = "Content-Encoding", | ||
| 30 | ["content-id"] = "Content-ID", | ||
| 31 | ["content-language"] = "Content-Language", | ||
| 32 | ["content-length"] = "Content-Length", | ||
| 33 | ["content-location"] = "Content-Location", | ||
| 34 | ["content-md5"] = "Content-MD5", | ||
| 35 | ["content-range"] = "Content-Range", | ||
| 36 | ["content-transfer-encoding"] = "Content-Transfer-Encoding", | ||
| 37 | ["content-type"] = "Content-Type", | ||
| 38 | ["cookie"] = "Cookie", | ||
| 39 | ["date"] = "Date", | ||
| 40 | ["diagnostic-code"] = "Diagnostic-Code", | ||
| 41 | ["dsn-gateway"] = "DSN-Gateway", | ||
| 42 | ["etag"] = "ETag", | ||
| 43 | ["expect"] = "Expect", | ||
| 44 | ["expires"] = "Expires", | ||
| 45 | ["final-log-id"] = "Final-Log-ID", | ||
| 46 | ["final-recipient"] = "Final-Recipient", | ||
| 47 | ["from"] = "From", | ||
| 48 | ["host"] = "Host", | ||
| 49 | ["if-match"] = "If-Match", | ||
| 50 | ["if-modified-since"] = "If-Modified-Since", | ||
| 51 | ["if-none-match"] = "If-None-Match", | ||
| 52 | ["if-range"] = "If-Range", | ||
| 53 | ["if-unmodified-since"] = "If-Unmodified-Since", | ||
| 54 | ["in-reply-to"] = "In-Reply-To", | ||
| 55 | ["keywords"] = "Keywords", | ||
| 56 | ["last-attempt-date"] = "Last-Attempt-Date", | ||
| 57 | ["last-modified"] = "Last-Modified", | ||
| 58 | ["location"] = "Location", | ||
| 59 | ["max-forwards"] = "Max-Forwards", | ||
| 60 | ["message-id"] = "Message-ID", | ||
| 61 | ["mime-version"] = "MIME-Version", | ||
| 62 | ["original-envelope-id"] = "Original-Envelope-ID", | ||
| 63 | ["original-recipient"] = "Original-Recipient", | ||
| 64 | ["pragma"] = "Pragma", | ||
| 65 | ["proxy-authenticate"] = "Proxy-Authenticate", | ||
| 66 | ["proxy-authorization"] = "Proxy-Authorization", | ||
| 67 | ["range"] = "Range", | ||
| 68 | ["received"] = "Received", | ||
| 69 | ["received-from-mta"] = "Received-From-MTA", | ||
| 70 | ["references"] = "References", | ||
| 71 | ["referer"] = "Referer", | ||
| 72 | ["remote-mta"] = "Remote-MTA", | ||
| 73 | ["reply-to"] = "Reply-To", | ||
| 74 | ["reporting-mta"] = "Reporting-MTA", | ||
| 75 | ["resent-bcc"] = "Resent-Bcc", | ||
| 76 | ["resent-cc"] = "Resent-Cc", | ||
| 77 | ["resent-date"] = "Resent-Date", | ||
| 78 | ["resent-from"] = "Resent-From", | ||
| 79 | ["resent-message-id"] = "Resent-Message-ID", | ||
| 80 | ["resent-reply-to"] = "Resent-Reply-To", | ||
| 81 | ["resent-sender"] = "Resent-Sender", | ||
| 82 | ["resent-to"] = "Resent-To", | ||
| 83 | ["retry-after"] = "Retry-After", | ||
| 84 | ["return-path"] = "Return-Path", | ||
| 85 | ["sender"] = "Sender", | ||
| 86 | ["server"] = "Server", | ||
| 87 | ["smtp-remote-recipient"] = "SMTP-Remote-Recipient", | ||
| 88 | ["status"] = "Status", | ||
| 89 | ["subject"] = "Subject", | ||
| 90 | ["te"] = "TE", | ||
| 91 | ["to"] = "To", | ||
| 92 | ["trailer"] = "Trailer", | ||
| 93 | ["transfer-encoding"] = "Transfer-Encoding", | ||
| 94 | ["upgrade"] = "Upgrade", | ||
| 95 | ["user-agent"] = "User-Agent", | ||
| 96 | ["vary"] = "Vary", | ||
| 97 | ["via"] = "Via", | ||
| 98 | ["warning"] = "Warning", | ||
| 99 | ["will-retry-until"] = "Will-Retry-Until", | ||
| 100 | ["www-authenticate"] = "WWW-Authenticate", | ||
| 101 | ["x-mailer"] = "X-Mailer", | ||
| 102 | } | ||
| 103 | 15 | ||
| 104 | return _M \ No newline at end of file | 16 | _M.canonic = {} |
| 17 | |||
| 18 | setmetatable(_M.canonic, { | ||
| 19 | __index = function(t, key) | ||
| 20 | if type(key) ~= "string" then | ||
| 21 | return nil | ||
| 22 | end | ||
| 23 | |||
| 24 | local lower = key:lower() | ||
| 25 | local v = rawget(t, lower) | ||
| 26 | if v then | ||
| 27 | return v | ||
| 28 | end | ||
| 29 | |||
| 30 | v = titlecase(lower) | ||
| 31 | rawset(t, lower, v) | ||
| 32 | return v | ||
| 33 | end | ||
| 34 | }) | ||
| 35 | |||
| 36 | -- adds a header with a given canonical capitalization, e.g. for headers | ||
| 37 | -- whose capitalization titlecase(header) would not reproduce correctly | ||
| 38 | function _M.setcanonic(header) | ||
| 39 | if type(header) ~= "string" then | ||
| 40 | error("header must be a string", 2) | ||
| 41 | end | ||
| 42 | _M.canonic[header:lower()] = header | ||
| 43 | end | ||
| 44 | |||
| 45 | -- headers whose canonical capitalization titlecase() does not reproduce | ||
| 46 | -- (acronyms and other irregular capitalization). Anything not listed here | ||
| 47 | -- is generated and cached on first lookup by the __index above. | ||
| 48 | _M.setcanonic("Content-ID") | ||
| 49 | _M.setcanonic("Content-MD5") | ||
| 50 | _M.setcanonic("DSN-Gateway") | ||
| 51 | _M.setcanonic("ETag") | ||
| 52 | _M.setcanonic("Final-Log-ID") | ||
| 53 | _M.setcanonic("Message-ID") | ||
| 54 | _M.setcanonic("MIME-Version") | ||
| 55 | _M.setcanonic("Original-Envelope-ID") | ||
| 56 | _M.setcanonic("Received-From-MTA") | ||
| 57 | _M.setcanonic("Remote-MTA") | ||
| 58 | _M.setcanonic("Reporting-MTA") | ||
| 59 | _M.setcanonic("Resent-Message-ID") | ||
| 60 | _M.setcanonic("SMTP-Remote-Recipient") | ||
| 61 | _M.setcanonic("TE") | ||
| 62 | _M.setcanonic("WWW-Authenticate") | ||
| 63 | |||
| 64 | return _M | ||
