🐳chore(库):增加库
parent
381114ead4
commit
4cb90fbc60
@ -0,0 +1,45 @@
|
|||||||
|
-- IPv4
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local DIGIT = core.DIGIT
|
||||||
|
|
||||||
|
local dec_octet = (
|
||||||
|
P"1" * DIGIT * DIGIT
|
||||||
|
+ P"2" * (R"04"*DIGIT + P"5"*R"05")
|
||||||
|
+ DIGIT * DIGIT^-1
|
||||||
|
) / tonumber
|
||||||
|
|
||||||
|
local IPv4_methods = {}
|
||||||
|
local IPv4_mt = {
|
||||||
|
__name = "lpeg_patterns.IPv4";
|
||||||
|
__index = IPv4_methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
local function new_IPv4 ( o1 , o2 , o3 , o4 )
|
||||||
|
return setmetatable({o1, o2, o3, o4}, IPv4_mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IPv4_methods:unpack()
|
||||||
|
return self[1], self[2], self[3], self[4]
|
||||||
|
end
|
||||||
|
|
||||||
|
function IPv4_methods:binary()
|
||||||
|
return string.char(self:unpack())
|
||||||
|
end
|
||||||
|
|
||||||
|
function IPv4_mt:__tostring ( )
|
||||||
|
return string.format("%d.%d.%d.%d", self:unpack())
|
||||||
|
end
|
||||||
|
|
||||||
|
local IPv4address = Cg ( dec_octet * P"." * dec_octet * P"." * dec_octet * P"." * dec_octet ) / new_IPv4
|
||||||
|
|
||||||
|
return {
|
||||||
|
IPv4_methods = IPv4_methods;
|
||||||
|
IPv4_mt = IPv4_mt;
|
||||||
|
IPv4address = IPv4address;
|
||||||
|
}
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
-- IPv6
|
||||||
|
|
||||||
|
local unpack = table.unpack or unpack -- luacheck: ignore 113 143
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local P = lpeg.P
|
||||||
|
local V = lpeg.V
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local HEXDIG = core.HEXDIG
|
||||||
|
|
||||||
|
local IPv4address = require "lpeg_patterns.IPv4".IPv4address
|
||||||
|
|
||||||
|
local IPv6_methods = {}
|
||||||
|
local IPv6_mt = {
|
||||||
|
__name = "lpeg_patterns.IPv6";
|
||||||
|
__index = IPv6_methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
local function new_IPv6(o1, o2, o3, o4, o5, o6, o7, o8, zoneid)
|
||||||
|
return setmetatable({
|
||||||
|
o1, o2, o3, o4, o5, o6, o7, o8,
|
||||||
|
zoneid = zoneid;
|
||||||
|
}, IPv6_mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function IPv6_methods:unpack()
|
||||||
|
return self[1], self[2], self[3], self[4], self[5], self[6], self[7], self[8], self.zoneid
|
||||||
|
end
|
||||||
|
|
||||||
|
function IPv6_methods:binary()
|
||||||
|
local t = {}
|
||||||
|
for i=1, 8 do
|
||||||
|
local lo = self[i] % 256
|
||||||
|
t[i*2-1] = (self[i] - lo) / 256
|
||||||
|
t[i*2] = lo
|
||||||
|
end
|
||||||
|
-- TODO: append zoneid.
|
||||||
|
-- In a struct sockaddr_in6 it is the numeric index of the scope, so need to lookup?
|
||||||
|
return string.char(unpack(t, 1, 16))
|
||||||
|
end
|
||||||
|
|
||||||
|
function IPv6_methods:setzoneid(zoneid)
|
||||||
|
self.zoneid = zoneid
|
||||||
|
end
|
||||||
|
|
||||||
|
function IPv6_mt:__tostring()
|
||||||
|
local fmt_str
|
||||||
|
if self.zoneid then
|
||||||
|
fmt_str = "%x:%x:%x:%x:%x:%x:%x:%x%%%s"
|
||||||
|
else
|
||||||
|
fmt_str = "%x:%x:%x:%x:%x:%x:%x:%x"
|
||||||
|
end
|
||||||
|
return string.format(fmt_str, self:unpack())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- RFC 3986 Section 3.2.2
|
||||||
|
-- This is written as a grammar to reduce memory usage
|
||||||
|
local raw_IPv6address = Cg(P{
|
||||||
|
h16 = HEXDIG * HEXDIG^-3 / util.read_hex;
|
||||||
|
h16c = V"h16" * P":";
|
||||||
|
ls32 = ( V"h16c" * V"h16" ) + IPv4address / function ( ipv4 )
|
||||||
|
local o1, o2, o3, o4 = ipv4:unpack()
|
||||||
|
return o1*2^8 + o2 , o3*2^8 + o4
|
||||||
|
end;
|
||||||
|
|
||||||
|
mh16c_1 = V"h16c";
|
||||||
|
mh16c_2 = V"h16c" * V"h16c";
|
||||||
|
mh16c_3 = V"h16c" * V"h16c" * V"h16c";
|
||||||
|
mh16c_4 = V"h16c" * V"h16c" * V"h16c" * V"h16c";
|
||||||
|
mh16c_5 = V"h16c" * V"h16c" * V"h16c" * V"h16c" * V"h16c";
|
||||||
|
mh16c_6 = V"h16c" * V"h16c" * V"h16c" * V"h16c" * V"h16c" * V"h16c";
|
||||||
|
|
||||||
|
mcc_1 = P"::" * Cc(0);
|
||||||
|
mcc_2 = P"::" * Cc(0, 0);
|
||||||
|
mcc_3 = P"::" * Cc(0, 0, 0);
|
||||||
|
mcc_4 = P"::" * Cc(0, 0, 0, 0);
|
||||||
|
mcc_5 = P"::" * Cc(0, 0, 0, 0, 0);
|
||||||
|
mcc_6 = P"::" * Cc(0, 0, 0, 0, 0, 0);
|
||||||
|
mcc_7 = P"::" * Cc(0, 0, 0, 0, 0, 0, 0);
|
||||||
|
mcc_8 = P"::" * Cc(0, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
mh16_1 = V"h16";
|
||||||
|
mh16_2 = V"mh16c_1" * V"h16";
|
||||||
|
mh16_3 = V"mh16c_2" * V"h16";
|
||||||
|
mh16_4 = V"mh16c_3" * V"h16";
|
||||||
|
mh16_5 = V"mh16c_4" * V"h16";
|
||||||
|
mh16_6 = V"mh16c_5" * V"h16";
|
||||||
|
mh16_7 = V"mh16c_6" * V"h16";
|
||||||
|
|
||||||
|
V"mh16c_6" * V"ls32"
|
||||||
|
+ V"mcc_1" * V"mh16c_5" * V"ls32"
|
||||||
|
+ V"mcc_2" * V"mh16c_4" * V"ls32"
|
||||||
|
+ V"h16" * V"mcc_1" * V"mh16c_4" * V"ls32"
|
||||||
|
+ V"mcc_3" * V"mh16c_3" * V"ls32"
|
||||||
|
+ V"h16" * V"mcc_2" * V"mh16c_3" * V"ls32"
|
||||||
|
+ V"mh16_2" * V"mcc_1" * V"mh16c_3" * V"ls32"
|
||||||
|
+ V"mcc_4" * V"mh16c_2" * V"ls32"
|
||||||
|
+ V"h16" * V"mcc_3" * V"mh16c_2" * V"ls32"
|
||||||
|
+ V"mh16_2" * V"mcc_2" * V"mh16c_2" * V"ls32"
|
||||||
|
+ V"mh16_3" * V"mcc_1" * V"mh16c_2" * V"ls32"
|
||||||
|
+ V"mcc_5" * V"h16c" * V"ls32"
|
||||||
|
+ V"h16" * V"mcc_4" * V"h16c" * V"ls32"
|
||||||
|
+ V"mh16_2" * V"mcc_3" * V"h16c" * V"ls32"
|
||||||
|
+ V"mh16_3" * V"mcc_2" * V"h16c" * V"ls32"
|
||||||
|
+ V"mh16_4" * V"mcc_1" * V"h16c" * V"ls32"
|
||||||
|
+ V"mcc_6" * V"ls32"
|
||||||
|
+ V"h16" * V"mcc_5" * V"ls32"
|
||||||
|
+ V"mh16_2" * V"mcc_4" * V"ls32"
|
||||||
|
+ V"mh16_3" * V"mcc_3" * V"ls32"
|
||||||
|
+ V"mh16_4" * V"mcc_2" * V"ls32"
|
||||||
|
+ V"mh16_5" * V"mcc_1" * V"ls32"
|
||||||
|
+ V"mcc_7" * V"h16"
|
||||||
|
+ V"h16" * V"mcc_6" * V"h16"
|
||||||
|
+ V"mh16_2" * V"mcc_5" * V"h16"
|
||||||
|
+ V"mh16_3" * V"mcc_4" * V"h16"
|
||||||
|
+ V"mh16_4" * V"mcc_3" * V"h16"
|
||||||
|
+ V"mh16_5" * V"mcc_2" * V"h16"
|
||||||
|
+ V"mh16_6" * V"mcc_1" * V"h16"
|
||||||
|
+ V"mcc_8"
|
||||||
|
+ V"mh16_1" * V"mcc_7"
|
||||||
|
+ V"mh16_2" * V"mcc_6"
|
||||||
|
+ V"mh16_3" * V"mcc_5"
|
||||||
|
+ V"mh16_4" * V"mcc_4"
|
||||||
|
+ V"mh16_5" * V"mcc_3"
|
||||||
|
+ V"mh16_6" * V"mcc_2"
|
||||||
|
+ V"mh16_7" * V"mcc_1"
|
||||||
|
})
|
||||||
|
|
||||||
|
local IPv6address = raw_IPv6address / new_IPv6
|
||||||
|
|
||||||
|
local ZoneID = P(1)^1 -- ZoneIDs can be any character
|
||||||
|
local IPv6addrz = raw_IPv6address * (P"%" * ZoneID)^-1 / new_IPv6
|
||||||
|
|
||||||
|
return {
|
||||||
|
IPv6_methods = IPv6_methods;
|
||||||
|
IPv6_mt = IPv6_mt;
|
||||||
|
IPv6address = IPv6address;
|
||||||
|
IPv6addrz = IPv6addrz;
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
-- Core Rules
|
||||||
|
-- https://tools.ietf.org/html/rfc5234#appendix-B.1
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
local _M = { }
|
||||||
|
|
||||||
|
_M.ALPHA = R("AZ","az")
|
||||||
|
_M.BIT = S"01"
|
||||||
|
_M.CHAR = R"\1\127"
|
||||||
|
_M.CR = P"\r"
|
||||||
|
_M.CRLF = P"\r\n"
|
||||||
|
_M.CTL = R"\0\31" + P"\127"
|
||||||
|
_M.DIGIT = R"09"
|
||||||
|
_M.DQUOTE= P'"'
|
||||||
|
_M.HEXDIG= _M.DIGIT + S"ABCDEFabcdef"
|
||||||
|
_M.HTAB = P"\t"
|
||||||
|
_M.LF = P"\n"
|
||||||
|
_M.OCTET = P(1)
|
||||||
|
_M.SP = P" "
|
||||||
|
_M.VCHAR = R"\33\126"
|
||||||
|
_M.WSP = S" \t"
|
||||||
|
|
||||||
|
_M.LWSP = (_M.WSP + _M.CRLF*_M.WSP)^0
|
||||||
|
|
||||||
|
return _M
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
-- Email Addresses
|
||||||
|
-- RFC 5322 Section 3.4.1
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
local S = lpeg.S
|
||||||
|
local V = lpeg.V
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local Cs = lpeg.Cs
|
||||||
|
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local CHAR = core.CHAR
|
||||||
|
local CRLF = core.CRLF
|
||||||
|
local CTL = core.CTL
|
||||||
|
local DQUOTE = core.DQUOTE
|
||||||
|
local WSP = core.WSP
|
||||||
|
local VCHAR = core.VCHAR
|
||||||
|
|
||||||
|
local obs_NO_WS_CTL = R("\1\8", "\11\12", "\14\31") + P"\127"
|
||||||
|
|
||||||
|
local obs_qp = Cg(P"\\" * C(P"\0" + obs_NO_WS_CTL + core.LF + core.CR))
|
||||||
|
local quoted_pair = Cg(P"\\" * C(VCHAR + WSP)) + obs_qp
|
||||||
|
|
||||||
|
-- Folding White Space
|
||||||
|
local FWS = (WSP^0 * CRLF)^-1 * WSP^1 / " " -- Fold whitespace into a single " "
|
||||||
|
|
||||||
|
-- Comments
|
||||||
|
local ctext = R"\33\39" + R"\42\91" + R"\93\126"
|
||||||
|
local comment = P {
|
||||||
|
V"comment" ;
|
||||||
|
ccontent = ctext + quoted_pair + V"comment" ;
|
||||||
|
comment = P"("* (FWS^-1 * V"ccontent")^0 * FWS^-1 * P")";
|
||||||
|
}
|
||||||
|
local CFWS = ((FWS^-1 * comment)^1 * FWS^-1 + FWS ) / function() end
|
||||||
|
|
||||||
|
-- Atom
|
||||||
|
local specials = S[=[()<>@,;:\".[]]=]
|
||||||
|
local atext = CHAR-specials-P" "-CTL
|
||||||
|
local atom = CFWS^-1 * C(atext^1) * CFWS^-1
|
||||||
|
local dot_atom_text = C(atext^1 * ( P"." * atext^1 )^0)
|
||||||
|
local dot_atom = CFWS^-1 * dot_atom_text * CFWS^-1
|
||||||
|
|
||||||
|
-- Quoted Strings
|
||||||
|
local qtext = S"\33"+R("\35\91","\93\126")
|
||||||
|
local qcontent = qtext + quoted_pair
|
||||||
|
local quoted_string_text = DQUOTE * Cs((FWS^-1 * qcontent)^0 * FWS^-1) * DQUOTE
|
||||||
|
local quoted_string = CFWS^-1 * quoted_string_text * CFWS^-1
|
||||||
|
|
||||||
|
-- Miscellaneous Tokens
|
||||||
|
local word = atom + quoted_string
|
||||||
|
local obs_phrase = C(word * (word + P"." + CFWS)^0 / function() end)
|
||||||
|
local phrase = obs_phrase -- obs_phrase is more broad than `word^1`, it's really the same but allows "."
|
||||||
|
|
||||||
|
-- Addr-spec
|
||||||
|
local obs_dtext = obs_NO_WS_CTL + quoted_pair
|
||||||
|
local dtext = R("\33\90", "\94\126") + obs_dtext
|
||||||
|
local domain_literal_text = P"[" * Cs((FWS^-1 * dtext)^0 * FWS^-1) * P"]"
|
||||||
|
|
||||||
|
local domain_text = dot_atom_text + domain_literal_text
|
||||||
|
local local_part_text = dot_atom_text + quoted_string_text
|
||||||
|
local addr_spec_text = local_part_text * P"@" * domain_text
|
||||||
|
|
||||||
|
local domain_literal = CFWS^-1 * domain_literal_text * CFWS^-1
|
||||||
|
local obs_domain = Ct(atom * (C"." * atom)^0) / table.concat
|
||||||
|
local domain = obs_domain + dot_atom + domain_literal
|
||||||
|
local obs_local_part = Ct(word * (C"." * word)^0) / table.concat
|
||||||
|
local local_part = obs_local_part + dot_atom + quoted_string
|
||||||
|
local addr_spec = local_part * P"@" * domain
|
||||||
|
|
||||||
|
local display_name = phrase
|
||||||
|
local obs_domain_list = (CFWS + P",")^0 * P"@" * domain
|
||||||
|
* (P"," * CFWS^-1 * (P"@" * domain)^-1)^0
|
||||||
|
local obs_route = Cg(Ct(obs_domain_list) * P":", "route")
|
||||||
|
local obs_angle_addr = CFWS^-1 * P"<" * obs_route * addr_spec * P">" * CFWS^-1
|
||||||
|
local angle_addr = CFWS^-1 * P"<" * addr_spec * P">" * CFWS^-1
|
||||||
|
+ obs_angle_addr
|
||||||
|
local name_addr = Cg(display_name, "display")^-1 * angle_addr
|
||||||
|
local mailbox = name_addr + addr_spec
|
||||||
|
|
||||||
|
return {
|
||||||
|
local_part = local_part;
|
||||||
|
domain = domain;
|
||||||
|
email = addr_spec;
|
||||||
|
name_addr = name_addr;
|
||||||
|
mailbox = mailbox;
|
||||||
|
|
||||||
|
-- A variant that does not allow comments or folding whitespace
|
||||||
|
local_part_nocfws = local_part_text;
|
||||||
|
domain_nocfws = domain_text;
|
||||||
|
email_nocfws = addr_spec_text;
|
||||||
|
}
|
||||||
@ -0,0 +1,171 @@
|
|||||||
|
-- HTTP related patterns
|
||||||
|
|
||||||
|
local _M = {}
|
||||||
|
|
||||||
|
-- RFC 7230
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
_M.OWS = http_core.OWS
|
||||||
|
_M.RWS = http_core.RWS
|
||||||
|
_M.BWS = http_core.BWS
|
||||||
|
|
||||||
|
_M.chunk_ext = http_core.chunk_ext
|
||||||
|
_M.comment = http_core.comment
|
||||||
|
_M.field_name = http_core.field_name
|
||||||
|
_M.field_value = http_core.field_value
|
||||||
|
_M.header_field = http_core.header_field
|
||||||
|
_M.qdtext = http_core.qdtext
|
||||||
|
_M.quoted_string = http_core.quoted_string
|
||||||
|
_M.request_line = http_core.request_line
|
||||||
|
_M.request_target = http_core.request_target
|
||||||
|
_M.token = http_core.token
|
||||||
|
|
||||||
|
_M.Connection = http_core.Connection
|
||||||
|
_M.Content_Length = http_core.Content_Length
|
||||||
|
_M.Host = http_core.Host
|
||||||
|
_M.TE = http_core.TE
|
||||||
|
_M.Trailer = http_core.Trailer
|
||||||
|
_M.Transfer_Encoding = http_core.Transfer_Encoding
|
||||||
|
_M.Upgrade = http_core.Upgrade
|
||||||
|
_M.Via = http_core.Via
|
||||||
|
|
||||||
|
-- RFC 7231
|
||||||
|
local http_semantics = require "lpeg_patterns.http.semantics"
|
||||||
|
|
||||||
|
_M.IMF_fixdate = http_semantics.IMF_fixdate
|
||||||
|
|
||||||
|
_M.Accept = http_semantics.Accept
|
||||||
|
_M.Accept_Charset = http_semantics.Accept_Charset
|
||||||
|
_M.Accept_Encoding = http_semantics.Accept_Encoding
|
||||||
|
_M.Accept_Language = http_semantics.Accept_Language
|
||||||
|
_M.Allow = http_semantics.Allow
|
||||||
|
_M.Content_Encoding = http_semantics.Content_Encoding
|
||||||
|
_M.Content_Language = http_semantics.Content_Language
|
||||||
|
_M.Content_Location = http_semantics.Content_Location
|
||||||
|
_M.Content_Type = http_semantics.Content_Type
|
||||||
|
_M.Date = http_semantics.Date
|
||||||
|
_M.Expect = http_semantics.Expect
|
||||||
|
_M.From = http_semantics.From
|
||||||
|
_M.Location = http_semantics.Location
|
||||||
|
_M.Max_Forwards = http_semantics.Max_Forwards
|
||||||
|
_M.Referer = http_semantics.Referer
|
||||||
|
_M.Retry_After = http_semantics.Retry_After
|
||||||
|
_M.Server = http_semantics.Server
|
||||||
|
_M.User_Agent = http_semantics.User_Agent
|
||||||
|
_M.Vary = http_semantics.Vary
|
||||||
|
|
||||||
|
-- RFC 7232
|
||||||
|
local http_conditional = require "lpeg_patterns.http.conditional"
|
||||||
|
_M.ETag = http_conditional.ETag
|
||||||
|
_M.If_Match = http_conditional.If_Match
|
||||||
|
_M.If_Modified_Since = http_conditional.If_Modified_Since
|
||||||
|
_M.If_None_Match = http_conditional.If_None_Match
|
||||||
|
_M.If_Unmodified_Since = http_conditional.If_Unmodified_Since
|
||||||
|
_M.Last_Modified = http_conditional.Last_Modified
|
||||||
|
|
||||||
|
-- RFC 7233
|
||||||
|
local http_range = require "lpeg_patterns.http.range"
|
||||||
|
_M.Accept_Ranges = http_range.Accept_Ranges
|
||||||
|
_M.Range = http_range.Range
|
||||||
|
_M.If_Range = http_range.If_Range
|
||||||
|
_M.Content_Range = http_range.Content_Range
|
||||||
|
|
||||||
|
-- RFC 7234
|
||||||
|
local http_caching = require "lpeg_patterns.http.caching"
|
||||||
|
_M.Age = http_caching.Age
|
||||||
|
_M.Cache_Control = http_caching.Cache_Control
|
||||||
|
_M.Expires = http_caching.Expires
|
||||||
|
_M.Pragma = http_caching.Pragma
|
||||||
|
_M.Warning = http_caching.Warning
|
||||||
|
|
||||||
|
-- RFC 7235
|
||||||
|
local http_authentication = require "lpeg_patterns.http.authentication"
|
||||||
|
_M.WWW_Authenticate = http_authentication.WWW_Authenticate
|
||||||
|
_M.Authorization = http_authentication.Authorization
|
||||||
|
_M.Proxy_Authenticate = http_authentication.Proxy_Authenticate
|
||||||
|
_M.Proxy_Authorization = http_authentication.Proxy_Authorization
|
||||||
|
|
||||||
|
-- WebDav
|
||||||
|
local http_webdav = require "lpeg_patterns.http.webdav"
|
||||||
|
_M.CalDAV_Timezones = http_webdav.CalDAV_Timezones
|
||||||
|
_M.DASL = http_webdav.DASL
|
||||||
|
_M.DAV = http_webdav.DAV
|
||||||
|
_M.Depth = http_webdav.Depth
|
||||||
|
_M.Destination = http_webdav.Destination
|
||||||
|
_M.If = http_webdav.If
|
||||||
|
_M.If_Schedule_Tag_Match = http_webdav.If_Schedule_Tag_Match
|
||||||
|
_M.Lock_Token = http_webdav.Lock_Token
|
||||||
|
_M.Overwrite = http_webdav.Overwrite
|
||||||
|
_M.Schedule_Reply = http_webdav.Schedule_Reply
|
||||||
|
_M.Schedule_Tag = http_webdav.Schedule_Tag
|
||||||
|
_M.TimeOut = http_webdav.TimeOut
|
||||||
|
|
||||||
|
-- RFC 5023
|
||||||
|
_M.SLUG = require "lpeg_patterns.http.slug".SLUG
|
||||||
|
|
||||||
|
-- RFC 5789
|
||||||
|
_M.Accept_Patch = http_core.comma_sep_trim(http_semantics.media_type, 1)
|
||||||
|
|
||||||
|
-- RFC 5988
|
||||||
|
_M.Link = require "lpeg_patterns.http.link".Link
|
||||||
|
|
||||||
|
-- RFC 6265
|
||||||
|
local http_cookie = require "lpeg_patterns.http.cookie"
|
||||||
|
_M.Cookie = http_cookie.Cookie
|
||||||
|
_M.Set_Cookie = http_cookie.Set_Cookie
|
||||||
|
|
||||||
|
-- RFC 6266
|
||||||
|
_M.Content_Disposition = require "lpeg_patterns.http.disposition".Content_Disposition
|
||||||
|
|
||||||
|
-- RFC 6454
|
||||||
|
_M.Origin = require "lpeg_patterns.http.origin".Origin
|
||||||
|
|
||||||
|
-- RFC 6455
|
||||||
|
local http_websocket = require "lpeg_patterns.http.websocket"
|
||||||
|
_M.Sec_WebSocket_Accept = http_websocket.Sec_WebSocket_Accept
|
||||||
|
_M.Sec_WebSocket_Key = http_websocket.Sec_WebSocket_Key
|
||||||
|
_M.Sec_WebSocket_Extensions = http_websocket.Sec_WebSocket_Extensions
|
||||||
|
_M.Sec_WebSocket_Protocol_Client = http_websocket.Sec_WebSocket_Protocol_Client
|
||||||
|
_M.Sec_WebSocket_Protocol_Server = http_websocket.Sec_WebSocket_Protocol_Server
|
||||||
|
_M.Sec_WebSocket_Version_Client = http_websocket.Sec_WebSocket_Version_Client
|
||||||
|
_M.Sec_WebSocket_Version_Server = http_websocket.Sec_WebSocket_Version_Server
|
||||||
|
|
||||||
|
-- RFC 6797
|
||||||
|
_M.Strict_Transport_Security = require "lpeg_patterns.http.sts".Strict_Transport_Security
|
||||||
|
|
||||||
|
-- RFC 7034
|
||||||
|
_M.X_Frame_Options = require "lpeg_patterns.http.frameoptions".X_Frame_Options
|
||||||
|
|
||||||
|
-- RFC 7089
|
||||||
|
_M.Accept_Datetime = http_semantics.IMF_fixdate
|
||||||
|
_M.Memento_Datetime = http_semantics.IMF_fixdate
|
||||||
|
|
||||||
|
-- RFC 7239
|
||||||
|
_M.Forwarded = require "lpeg_patterns.http.forwarded".Forwarded
|
||||||
|
|
||||||
|
-- RFC 7469
|
||||||
|
local http_pkp = require "lpeg_patterns.http.pkp"
|
||||||
|
_M.Public_Key_Pins = http_pkp.Public_Key_Pins
|
||||||
|
_M.Public_Key_Pins_Report_Only = http_pkp.Public_Key_Pins_Report_Only
|
||||||
|
|
||||||
|
-- RFC 7486
|
||||||
|
_M.Hobareg = require "lpeg_patterns.http.hoba".Hobareg
|
||||||
|
|
||||||
|
-- RFC 7615
|
||||||
|
_M.Authentication_Info = http_authentication.Authentication_Info
|
||||||
|
_M.Proxy_Authentication_Info = http_authentication.Proxy_Authentication_Info
|
||||||
|
|
||||||
|
-- RFC 7639
|
||||||
|
_M.ALPN = require "lpeg_patterns.http.alpn".ALPN
|
||||||
|
|
||||||
|
-- RFC 7838
|
||||||
|
local http_alternate = require "lpeg_patterns.http.alternate"
|
||||||
|
_M.Alt_Svc = http_alternate.Alt_Svc
|
||||||
|
_M.Alt_Used = http_alternate.Alt_Used
|
||||||
|
|
||||||
|
-- https://tools.ietf.org/html/draft-ietf-httpbis-expect-ct-06#section-2.1
|
||||||
|
_M.Expect_CT = require "lpeg_patterns.http.expect_ct".Expect_CT
|
||||||
|
|
||||||
|
-- https://www.w3.org/TR/referrer-policy/#referrer-policy-header
|
||||||
|
_M.Referrer_Policy = require "lpeg_patterns.http.referrer_policy".Referrer_Policy
|
||||||
|
|
||||||
|
return _M
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
-- RFC 7639
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local Cmt = lpeg.Cmt
|
||||||
|
local Cs = lpeg.Cs
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
|
||||||
|
--[[ protocol-id is a percent-encoded ALPN protocol name
|
||||||
|
- Octets in the ALPN protocol MUST NOT be percent-encoded if they
|
||||||
|
are valid token characters except "%".
|
||||||
|
- When using percent-encoding, uppercase hex digits MUST be used.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local valid_chars = http_core.tchar - P"%"
|
||||||
|
local upper_hex = R("09", "AF")
|
||||||
|
local percent_char = P"%" * (upper_hex * upper_hex / util.read_hex) / string.char
|
||||||
|
local percent_encoded = Cmt(percent_char, function(_, _, c)
|
||||||
|
-- check that decoded character would not have been allowed unescaped
|
||||||
|
if not valid_chars:match(c) then
|
||||||
|
return true, c
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
local percent_replace = Cs((valid_chars + percent_encoded)^0)
|
||||||
|
|
||||||
|
local protocol_id = percent_replace
|
||||||
|
|
||||||
|
local ALPN = http_core.comma_sep_trim(protocol_id, 1)
|
||||||
|
|
||||||
|
return {
|
||||||
|
protocol_id = protocol_id;
|
||||||
|
ALPN = ALPN;
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
-- RFC 7838
|
||||||
|
-- HTTP Alternative Services
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_alpn = require "lpeg_patterns.http.alpn"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_semantics = require "lpeg_patterns.http.semantics"
|
||||||
|
local uri = require "lpeg_patterns.uri"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
local clear = C"clear" -- case-sensitive
|
||||||
|
local alt_authority = http_core.quoted_string -- containing [ uri_host ] ":" port
|
||||||
|
local alternative = http_alpn.protocol_id * P"=" * alt_authority
|
||||||
|
local alt_value = alternative * (http_core.OWS * P";" * http_core.OWS * http_semantics.parameter)^0
|
||||||
|
local Alt_Svc = clear + http_core.comma_sep_trim(alt_value, 1)
|
||||||
|
local Alt_Used = uri.host * (P":" * uri.port)^-1
|
||||||
|
|
||||||
|
return {
|
||||||
|
Alt_Svc = Alt_Svc;
|
||||||
|
Alt_Used = Alt_Used;
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cf = lpeg.Cf
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
-- RFC 7235 Section 2
|
||||||
|
local auth_scheme = http_core.token
|
||||||
|
local auth_param = Cg(http_core.token / string.lower * http_core.BWS * P"=" * http_core.BWS * (http_core.token + http_core.quoted_string))
|
||||||
|
local token68 = C((core.ALPHA + core.DIGIT + P"-" + P"." + P"_" + P"~" + P"+" + P"/" )^1 * (P"=")^0)
|
||||||
|
-- TODO: each parameter name MUST only occur once per challenge
|
||||||
|
local challenge = auth_scheme * (core.SP^1 * (Cf(Ct(true) * http_core.comma_sep(auth_param), rawset) + token68))^-1
|
||||||
|
local credentials = challenge
|
||||||
|
|
||||||
|
-- RFC 7235 Section 4
|
||||||
|
local WWW_Authenticate = http_core.comma_sep_trim(Ct(challenge), 1)
|
||||||
|
local Authorization = credentials
|
||||||
|
local Proxy_Authenticate = WWW_Authenticate
|
||||||
|
local Proxy_Authorization = Authorization
|
||||||
|
|
||||||
|
-- RFC 7615
|
||||||
|
local Authentication_Info = http_core.comma_sep_trim(auth_param)
|
||||||
|
local Proxy_Authentication_Info = http_core.comma_sep_trim(auth_param)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Authentication_Info = Authentication_Info;
|
||||||
|
Authorization = Authorization;
|
||||||
|
Proxy_Authenticate = Proxy_Authenticate;
|
||||||
|
Proxy_Authentication_Info = Proxy_Authentication_Info;
|
||||||
|
Proxy_Authorization = Proxy_Authorization;
|
||||||
|
WWW_Authenticate = WWW_Authenticate;
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
-- RFC 7234
|
||||||
|
-- Hypertext Transfer Protocol (HTTP/1.1): Caching
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_semantics = require "lpeg_patterns.http.semantics"
|
||||||
|
local uri = require "lpeg_patterns.uri"
|
||||||
|
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
-- RFC 7234 Section 1.2.1
|
||||||
|
local delta_seconds = core.DIGIT^1 / tonumber
|
||||||
|
|
||||||
|
-- RFC 7234 Section 5.1
|
||||||
|
local Age = delta_seconds
|
||||||
|
|
||||||
|
-- RFC 7234 Section 5.2
|
||||||
|
local cache_directive = http_core.token / string.lower * ((P"=" * (http_core.token + http_core.quoted_string)) + Cc(true))
|
||||||
|
local Cache_Control = http_core.comma_sep_trim(Cg(cache_directive), 1)
|
||||||
|
|
||||||
|
-- RFC 7234 Section 5.3
|
||||||
|
local Expires = http_semantics.HTTP_date
|
||||||
|
|
||||||
|
-- RFC 7234 Section 5.4
|
||||||
|
local extension_pragma = http_core.token * (P"=" * (http_core.token + http_core.quoted_string))^-1
|
||||||
|
local pragma_directive = "no_cache" + extension_pragma
|
||||||
|
local Pragma = http_core.comma_sep_trim(pragma_directive, 1)
|
||||||
|
|
||||||
|
-- RFC 7234 Section 5.5
|
||||||
|
local warn_code = core.DIGIT * core.DIGIT * core.DIGIT
|
||||||
|
local warn_agent = (uri.host * (P":" * uri.port)^-1) + http_core.pseudonym
|
||||||
|
local warn_text = http_core.quoted_string
|
||||||
|
local warn_date = core.DQUOTE * http_semantics.HTTP_date * core.DQUOTE
|
||||||
|
local warning_value = warn_code * core.SP * warn_agent * core.SP * warn_text * (core.SP * warn_date)^-1
|
||||||
|
local Warning = http_core.comma_sep_trim(warning_value, 1)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Age = Age;
|
||||||
|
Cache_Control = Cache_Control;
|
||||||
|
Expires = Expires;
|
||||||
|
Pragma = Pragma;
|
||||||
|
Warning = Warning;
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
-- RFC 7232
|
||||||
|
-- Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_semantics = require "lpeg_patterns.http.semantics"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
|
||||||
|
-- RFC 7232 Section 2.2
|
||||||
|
local Last_Modified = http_semantics.HTTP_date
|
||||||
|
|
||||||
|
-- RFC 7232 Section 2.3
|
||||||
|
local weak = P"W/" -- case sensitive
|
||||||
|
local etagc = P"\33" + R"\35\115" + http_core.obs_text
|
||||||
|
local opaque_tag = core.DQUOTE * etagc^0 * core.DQUOTE
|
||||||
|
local entity_tag = Cg(weak*Cc(true) + Cc(false), "weak") * C(opaque_tag)
|
||||||
|
local ETag = entity_tag
|
||||||
|
|
||||||
|
-- RFC 7232 Section 3.1
|
||||||
|
local If_Match = P"*" + http_core.comma_sep(entity_tag, 1)
|
||||||
|
|
||||||
|
-- RFC 7232 Section 3.2
|
||||||
|
local If_None_Match = P"*" + http_core.comma_sep(entity_tag, 1)
|
||||||
|
|
||||||
|
-- RFC 7232 Section 3.3
|
||||||
|
local If_Modified_Since = http_semantics.HTTP_date
|
||||||
|
|
||||||
|
-- RFC 7232 Section 3.4
|
||||||
|
local If_Unmodified_Since = http_semantics.HTTP_date
|
||||||
|
|
||||||
|
return {
|
||||||
|
entity_tag = entity_tag;
|
||||||
|
opaque_tag = opaque_tag;
|
||||||
|
|
||||||
|
Last_Modified = Last_Modified;
|
||||||
|
ETag = ETag;
|
||||||
|
If_Match = If_Match;
|
||||||
|
If_None_Match = If_None_Match;
|
||||||
|
If_Modified_Since = If_Modified_Since;
|
||||||
|
If_Unmodified_Since = If_Unmodified_Since;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
-- RFC 6265
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cf = lpeg.Cf
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
local cookie_name = http_core.token
|
||||||
|
local cookie_octet = S"!" + R("\35\43", "\45\58", "\60\91", "\93\126")
|
||||||
|
local cookie_value = core.DQUOTE * C(cookie_octet^0) * core.DQUOTE + C(cookie_octet^0)
|
||||||
|
local cookie_pair = cookie_name * http_core.BWS * P"=" * http_core.BWS * cookie_value * http_core.BWS
|
||||||
|
|
||||||
|
local ext_char = core.CHAR - core.CTL - S";"
|
||||||
|
ext_char = ext_char - core.WSP + core.WSP * #(core.WSP^0 * ext_char) -- No trailing whitespace
|
||||||
|
-- Complexity is to make sure whitespace before an `=` isn't captured
|
||||||
|
local extension_av = ((ext_char - S"=" - core.WSP) + core.WSP^1 * #(1-S"="))^0 / string.lower
|
||||||
|
* http_core.BWS * P"=" * http_core.BWS * C(ext_char^0)
|
||||||
|
+ (ext_char)^0 / string.lower * Cc(true)
|
||||||
|
local cookie_av = extension_av
|
||||||
|
local set_cookie_string = cookie_pair * Cf(Ct(true) * (P";" * http_core.OWS * Cg(cookie_av))^0, rawset)
|
||||||
|
local Set_Cookie = set_cookie_string
|
||||||
|
|
||||||
|
local cookie_string = Cf(Ct(true) * Cg(cookie_pair) * (P";" * http_core.OWS * Cg(cookie_pair))^0, rawset)
|
||||||
|
local Cookie = cookie_string
|
||||||
|
|
||||||
|
return {
|
||||||
|
Cookie = Cookie;
|
||||||
|
Set_Cookie = Set_Cookie;
|
||||||
|
}
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
-- RFC 7230
|
||||||
|
-- Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local uri = require "lpeg_patterns.uri"
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cf = lpeg.Cf
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Cs = lpeg.Cs
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
local S = lpeg.S
|
||||||
|
local V = lpeg.V
|
||||||
|
|
||||||
|
-- RFC 7230 Section 3.2.3
|
||||||
|
local OWS = (core.SP + core.HTAB)^0
|
||||||
|
local RWS = (core.SP + core.HTAB)^1
|
||||||
|
local BWS = OWS
|
||||||
|
|
||||||
|
-- Analogue to RFC 7230 Section 7's ABNF extension of '#'
|
||||||
|
-- Also documented as `#rule` under RFC 2616 Section 2.1
|
||||||
|
local sep = OWS * lpeg.P "," * OWS
|
||||||
|
local optional_sep = (lpeg.P"," + core.SP + core.HTAB)^0
|
||||||
|
local function comma_sep(element, min, max)
|
||||||
|
local extra = sep * optional_sep * element
|
||||||
|
local patt = element
|
||||||
|
if min then
|
||||||
|
for _=2, min do
|
||||||
|
patt = patt * extra
|
||||||
|
end
|
||||||
|
else
|
||||||
|
min = 0
|
||||||
|
patt = patt^-1
|
||||||
|
end
|
||||||
|
if max then
|
||||||
|
local more = max-min-1
|
||||||
|
patt = patt * extra^-more
|
||||||
|
else
|
||||||
|
patt = patt * extra^0
|
||||||
|
end
|
||||||
|
return patt
|
||||||
|
end
|
||||||
|
-- allows leading + trailing
|
||||||
|
local function comma_sep_trim(...)
|
||||||
|
return optional_sep * comma_sep(...) * optional_sep
|
||||||
|
end
|
||||||
|
|
||||||
|
-- RFC 7230 Section 2.6
|
||||||
|
local HTTP_name = P"HTTP"
|
||||||
|
local HTTP_version = HTTP_name * P"/" * (core.DIGIT * P"." * core.DIGIT / util.safe_tonumber)
|
||||||
|
|
||||||
|
-- RFC 7230 Section 2.7
|
||||||
|
local absolute_path = (P"/" * uri.segment )^1
|
||||||
|
local partial_uri = Ct(uri.relative_part * (P"?" * uri.query)^-1)
|
||||||
|
|
||||||
|
-- RFC 7230 Section 3.2.6
|
||||||
|
local tchar = S "!#$%&'*+-.^_`|~" + core.DIGIT + core.ALPHA
|
||||||
|
local token = C(tchar^1)
|
||||||
|
local obs_text = R("\128\255")
|
||||||
|
local qdtext = core.HTAB + core.SP + P"\33" + R("\35\91", "\93\126") + obs_text
|
||||||
|
local quoted_pair = Cs(P"\\" * C(core.HTAB + core.SP + core.VCHAR + obs_text) / "%1")
|
||||||
|
local quoted_string = core.DQUOTE * Cs((qdtext + quoted_pair)^0) * core.DQUOTE
|
||||||
|
|
||||||
|
local ctext = core.HTAB + core.SP + R("\33\39", "\42\91", "\93\126") + obs_text
|
||||||
|
local comment = P { P"(" * ( ctext + quoted_pair + V(1) )^0 * P")" }
|
||||||
|
|
||||||
|
-- RFC 7230 Section 3.2
|
||||||
|
local field_name = token / string.lower -- case insensitive
|
||||||
|
local field_vchar = core.VCHAR + obs_text
|
||||||
|
local field_content = field_vchar * (( core.SP + core.HTAB )^1 * field_vchar)^-1
|
||||||
|
local obs_fold = ( core.SP + core.HTAB )^0 * core.CRLF * ( core.SP + core.HTAB )^1 / " "
|
||||||
|
-- field_value is not correct, see Errata: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189
|
||||||
|
local field_value = Cs((field_content + obs_fold)^0)
|
||||||
|
local header_field = field_name * P":" * OWS * field_value * OWS
|
||||||
|
|
||||||
|
-- RFC 7230 Section 3.3.2
|
||||||
|
local Content_Length = core.DIGIT^1
|
||||||
|
|
||||||
|
-- RFC 7230 Section 4
|
||||||
|
-- See https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4683
|
||||||
|
local transfer_parameter = (token - S"qQ" * BWS * P"=") * BWS * P"=" * BWS * ( token + quoted_string )
|
||||||
|
local transfer_extension = Cf(Ct(token / string.lower) -- case insensitive
|
||||||
|
* ( OWS * P";" * OWS * Cg(transfer_parameter) )^0, rawset)
|
||||||
|
local transfer_coding = transfer_extension
|
||||||
|
|
||||||
|
-- RFC 7230 Section 3.3.1
|
||||||
|
local Transfer_Encoding = comma_sep_trim(transfer_coding, 1)
|
||||||
|
|
||||||
|
-- RFC 7230 Section 4.1.1
|
||||||
|
local chunk_ext_name = token
|
||||||
|
local chunk_ext_val = token + quoted_string
|
||||||
|
-- See https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4667
|
||||||
|
local chunk_ext = ( P";" * chunk_ext_name * ( P"=" * chunk_ext_val)^-1 )^0
|
||||||
|
|
||||||
|
-- RFC 7230 Section 4.3
|
||||||
|
local rank = (P"0" * ((P"." * core.DIGIT^-3) / util.safe_tonumber + Cc(0)) + P"1" * ("." * (P"0")^-3)^-1) * Cc(1)
|
||||||
|
local t_ranking = OWS * P";" * OWS * S"qQ" * P"=" * rank -- q is case insensitive
|
||||||
|
local t_codings = (transfer_coding * t_ranking^-1) / function(t, q)
|
||||||
|
if q then
|
||||||
|
t["q"] = q
|
||||||
|
end
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
local TE = comma_sep_trim(t_codings)
|
||||||
|
|
||||||
|
-- RFC 7230 Section 4.4
|
||||||
|
local Trailer = comma_sep_trim(field_name, 1)
|
||||||
|
|
||||||
|
-- RFC 7230 Section 5.3
|
||||||
|
local origin_form = Cs(absolute_path * (P"?" * uri.query)^-1)
|
||||||
|
local absolute_form = util.no_rich_capture(uri.absolute_uri)
|
||||||
|
local authority_form = util.no_rich_capture(uri.authority)
|
||||||
|
local asterisk_form = C"*"
|
||||||
|
local request_target = asterisk_form + origin_form + absolute_form + authority_form
|
||||||
|
|
||||||
|
-- RFC 7230 Section 3.1.1
|
||||||
|
local method = token
|
||||||
|
local request_line = method * core.SP * request_target * core.SP * HTTP_version * core.CRLF
|
||||||
|
|
||||||
|
-- RFC 7230 Section 5.4
|
||||||
|
local Host = uri.host * (P":" * uri.port)^-1
|
||||||
|
|
||||||
|
-- RFC 7230 Section 6.7
|
||||||
|
local protocol_name = token
|
||||||
|
local protocol_version = token
|
||||||
|
local protocol = protocol_name * (P"/" * protocol_version)^-1 / "%0"
|
||||||
|
local Upgrade = comma_sep_trim(protocol)
|
||||||
|
|
||||||
|
-- RFC 7230 Section 5.7.1
|
||||||
|
local received_protocol = (protocol_name * P"/" + Cc("HTTP")) * protocol_version / "%1/%2"
|
||||||
|
local pseudonym = token
|
||||||
|
-- workaround for https://lists.w3.org/Archives/Public/ietf-http-wg/2016OctDec/0527.html
|
||||||
|
local received_by = uri.host * ((P":" * uri.port) + -lpeg.B(",")) / "%0" + pseudonym
|
||||||
|
local Via = comma_sep_trim(Ct(
|
||||||
|
Cg(received_protocol, "protocol")
|
||||||
|
* RWS * Cg(received_by, "by")
|
||||||
|
* (RWS * Cg(comment, "comment"))^-1
|
||||||
|
), 1)
|
||||||
|
|
||||||
|
-- RFC 7230 Section 6.1
|
||||||
|
local connection_option = token / string.lower -- case insensitive
|
||||||
|
local Connection = comma_sep_trim(connection_option)
|
||||||
|
|
||||||
|
return {
|
||||||
|
comma_sep = comma_sep;
|
||||||
|
comma_sep_trim = comma_sep_trim;
|
||||||
|
|
||||||
|
OWS = OWS;
|
||||||
|
RWS = RWS;
|
||||||
|
BWS = BWS;
|
||||||
|
|
||||||
|
chunk_ext = chunk_ext;
|
||||||
|
comment = comment;
|
||||||
|
field_name = field_name;
|
||||||
|
field_value = field_value;
|
||||||
|
header_field = header_field;
|
||||||
|
method = method;
|
||||||
|
obs_text = obs_text;
|
||||||
|
partial_uri = partial_uri;
|
||||||
|
pseudonym = pseudonym;
|
||||||
|
qdtext = qdtext;
|
||||||
|
quoted_string = quoted_string;
|
||||||
|
rank = rank;
|
||||||
|
request_line = request_line;
|
||||||
|
request_target = request_target;
|
||||||
|
t_ranking = t_ranking;
|
||||||
|
tchar = tchar;
|
||||||
|
token = token;
|
||||||
|
|
||||||
|
Connection = Connection;
|
||||||
|
Content_Length = Content_Length;
|
||||||
|
Host = Host;
|
||||||
|
TE = TE;
|
||||||
|
Trailer = Trailer;
|
||||||
|
Transfer_Encoding = Transfer_Encoding;
|
||||||
|
Upgrade = Upgrade;
|
||||||
|
Via = Via;
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
-- RFC 6266
|
||||||
|
-- Use of the Content-Disposition Header Field in the
|
||||||
|
-- Hypertext Transfer Protocol (HTTP)
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_parameters = require "lpeg_patterns.http.parameters"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cf = lpeg.Cf
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
local disp_ext_type = http_core.token / string.lower
|
||||||
|
local disposition_type = disp_ext_type
|
||||||
|
-- can't use 'token' here as we need to not include the "*" at the end
|
||||||
|
local ext_token = C((http_core.tchar-P"*"*(-http_core.tchar))^1) * P"*"
|
||||||
|
local value = http_core.token + http_core.quoted_string
|
||||||
|
local disp_ext_parm = ext_token * http_core.OWS * P"=" * http_core.OWS * http_parameters.ext_value
|
||||||
|
+ http_core.token * http_core.OWS * P"=" * http_core.OWS * value
|
||||||
|
local disposition_parm = disp_ext_parm
|
||||||
|
local Content_Disposition = disposition_type * Cf(Ct(true) * (http_core.OWS * P";" * http_core.OWS * Cg(disposition_parm))^0, rawset)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Content_Disposition = Content_Disposition;
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
-- https://tools.ietf.org/html/draft-ietf-httpbis-expect-ct-06#section-2.1
|
||||||
|
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_utils = require "lpeg_patterns.http.util"
|
||||||
|
|
||||||
|
local expect_ct_directive = http_utils.directive
|
||||||
|
local Expect_CT = http_utils.no_dup(http_core.comma_sep_trim(expect_ct_directive))
|
||||||
|
|
||||||
|
return {
|
||||||
|
Expect_CT = Expect_CT;
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
-- RFC 7239
|
||||||
|
-- Forwarded HTTP Extension
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
-- RFC 7239 Section 4
|
||||||
|
local value = http_core.token + http_core.quoted_string
|
||||||
|
local forwarded_pair = http_core.token * P"=" * value
|
||||||
|
local forwarded_element = forwarded_pair^-1 * (P";" * forwarded_pair^-1)^0
|
||||||
|
local Forwarded = http_core.comma_sep_trim(forwarded_element)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Forwarded = Forwarded;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
-- RFC 7034
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local case_insensitive = util.case_insensitive
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
|
||||||
|
local X_Frame_Options = case_insensitive "deny" * Cc("deny")
|
||||||
|
+ case_insensitive "sameorigin" * Cc("sameorigin")
|
||||||
|
+ case_insensitive "allow-from" * http_core.RWS * require "lpeg_patterns.http.origin".serialized_origin
|
||||||
|
|
||||||
|
return {
|
||||||
|
X_Frame_Options = X_Frame_Options;
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
-- RFC 7486
|
||||||
|
-- HTTP Origin-Bound Authentication (HOBA)
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
|
||||||
|
local Hobareg = C"regok" + C"reginwork"
|
||||||
|
|
||||||
|
return {
|
||||||
|
Hobareg = Hobareg;
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
-- RFC 5988
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_parameters = require "lpeg_patterns.http.parameters"
|
||||||
|
local uri = require "lpeg_patterns.uri"
|
||||||
|
|
||||||
|
local Cf = lpeg.Cf
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local P = lpeg.P
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
local ptokenchar = S"!#$%&'()*+-./:<=>?@[]^_`{|}~" + core.DIGIT + core.ALPHA
|
||||||
|
local ptoken = ptokenchar^1
|
||||||
|
local ext_name_star = http_parameters.parmname * P"*"
|
||||||
|
local link_extension = ext_name_star * P"=" * http_parameters.ext_value
|
||||||
|
+ http_parameters.parmname * (P"=" * (ptoken + http_core.quoted_string))^-1
|
||||||
|
-- See https://www.rfc-editor.org/errata_search.php?rfc=5988&eid=3158
|
||||||
|
local link_param = link_extension
|
||||||
|
local link_value = Cf(Ct(P"<" * uri.uri_reference * P">") * (http_core.OWS * P";" * http_core.OWS * Cg(link_param))^0, rawset)
|
||||||
|
-- TODO: handle multiple ext_value variants...
|
||||||
|
-- e.g. server might provide one title in english, one in chinese, client should be able to pick which one to display
|
||||||
|
|
||||||
|
local Link = http_core.comma_sep_trim(link_value)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Link = Link;
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
-- RFC 6454
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local uri = require "lpeg_patterns.uri"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
-- discard captures from scheme, host, port and just get whole string
|
||||||
|
local serialized_origin = C(uri.scheme * P"://" * uri.host * (P":" * uri.port)^-1/function() end)
|
||||||
|
local origin_list = serialized_origin * (core.SP * serialized_origin)^0
|
||||||
|
local origin_list_or_null = P"null" + origin_list
|
||||||
|
local Origin = http_core.OWS * origin_list_or_null * http_core.OWS
|
||||||
|
|
||||||
|
return {
|
||||||
|
serialized_origin = serialized_origin;
|
||||||
|
Origin = Origin;
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
-- RFC 5987
|
||||||
|
-- Character Set and Language Encoding for
|
||||||
|
-- Hypertext Transfer Protocol (HTTP) Header Field Parameters
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local language = require "lpeg_patterns.language"
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Cs = lpeg.Cs
|
||||||
|
local P = lpeg.P
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
local attr_char = core.ALPHA + core.DIGIT + S"!#$&+-.^_`|~"
|
||||||
|
-- can't use uri.pct_encoded, as it doesn't decode all characters
|
||||||
|
local pct_encoded = P"%" * (core.HEXDIG * core.HEXDIG / util.read_hex) / string.char
|
||||||
|
local value_chars = Cs((pct_encoded + attr_char)^0)
|
||||||
|
local parmname = C(attr_char^1)
|
||||||
|
-- ext-value uses charset from RFC 5987
|
||||||
|
local mime_charsetc = core.ALPHA + core.DIGIT + S"!#$%&+-^_`{}~"
|
||||||
|
local mime_charset = C(mime_charsetc^1)
|
||||||
|
local ext_value = Cg(mime_charset, "charset") * P"'" * Cg(language.Language_Tag, "language")^-1 * P"'" * value_chars
|
||||||
|
|
||||||
|
return {
|
||||||
|
ext_value = ext_value;
|
||||||
|
parmname = parmname;
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_utils = require "lpeg_patterns.http.util"
|
||||||
|
|
||||||
|
local Cmt = lpeg.Cmt
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
-- RFC 7469
|
||||||
|
local Public_Key_Directives = http_utils.directive * (http_core.OWS * P";" * http_core.OWS * http_utils.directive)^0
|
||||||
|
local function pkp_cmt(pins, t, k, v, ...)
|
||||||
|
-- duplicates are allowed if the directive name starts with "pin-"
|
||||||
|
local pin_name = k:match("^pin%-(.+)")
|
||||||
|
if pin_name then
|
||||||
|
local hashes = pins[pin_name]
|
||||||
|
if hashes then
|
||||||
|
hashes[#hashes+1] = v
|
||||||
|
else
|
||||||
|
hashes = {v}
|
||||||
|
pins[pin_name] = hashes
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local old = t[k]
|
||||||
|
if old then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
t[k] = v
|
||||||
|
end
|
||||||
|
if ... then
|
||||||
|
return pkp_cmt(pins, t, ...)
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local Public_Key_Pins = Cmt(Public_Key_Directives, function(_, _, ...)
|
||||||
|
local pins = {}
|
||||||
|
local t = {}
|
||||||
|
local ok = pkp_cmt(pins, t, ...)
|
||||||
|
if ok and t["max-age"] then
|
||||||
|
return true, pins, t
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
local Public_Key_Pins_Report_Only = Cmt(Public_Key_Directives, function(_, _, ...)
|
||||||
|
local pins = {}
|
||||||
|
local t = {}
|
||||||
|
local ok = pkp_cmt(pins, t, ...)
|
||||||
|
if ok then
|
||||||
|
return true, pins, t
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Public_Key_Pins = Public_Key_Pins;
|
||||||
|
Public_Key_Pins_Report_Only = Public_Key_Pins_Report_Only;
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
-- RFC 7233
|
||||||
|
-- Hypertext Transfer Protocol (HTTP/1.1): Range Requests
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_conditional = require "lpeg_patterns.http.conditional"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_semantics = require "lpeg_patterns.http.semantics"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
local bytes_unit = P"bytes"
|
||||||
|
local other_range_unit = http_core.token
|
||||||
|
local range_unit = C(bytes_unit) + other_range_unit
|
||||||
|
|
||||||
|
local first_byte_pos = core.DIGIT^1 / tonumber
|
||||||
|
local last_byte_pos = core.DIGIT^1 / tonumber
|
||||||
|
local byte_range_spec = first_byte_pos * P"-" * last_byte_pos^-1
|
||||||
|
local suffix_length = core.DIGIT^1 / tonumber
|
||||||
|
local suffix_byte_range_spec = Cc(nil) * P"-" * suffix_length
|
||||||
|
local byte_range_set = http_core.comma_sep(byte_range_spec + suffix_byte_range_spec, 1)
|
||||||
|
local byte_ranges_specifier = bytes_unit * P"=" * byte_range_set
|
||||||
|
|
||||||
|
-- RFC 7233 Section 2.3
|
||||||
|
local acceptable_ranges = http_core.comma_sep_trim(range_unit, 1) + P"none"
|
||||||
|
local Accept_Ranges = acceptable_ranges
|
||||||
|
|
||||||
|
-- RFC 7233 Section 3.1
|
||||||
|
local other_range_set = core.VCHAR^1
|
||||||
|
local other_ranges_specifier = other_range_unit * P"=" * other_range_set
|
||||||
|
local Range = byte_ranges_specifier + other_ranges_specifier
|
||||||
|
|
||||||
|
-- RFC 7233 Section 3.2
|
||||||
|
local If_Range = http_conditional.entity_tag + http_semantics.HTTP_date
|
||||||
|
|
||||||
|
-- RFC 7233 Section 4.2
|
||||||
|
local complete_length = core.DIGIT^1 / tonumber
|
||||||
|
local unsatisfied_range = P"*/" * complete_length
|
||||||
|
local byte_range = first_byte_pos * P"-" * last_byte_pos
|
||||||
|
local byte_range_resp = byte_range * P"/" * (complete_length + P"*")
|
||||||
|
local byte_content_range = bytes_unit * core.SP * (byte_range_resp + unsatisfied_range)
|
||||||
|
local other_range_resp = core.CHAR^0
|
||||||
|
local other_content_range = other_range_unit * core.SP * other_range_resp
|
||||||
|
local Content_Range = byte_content_range + other_content_range
|
||||||
|
|
||||||
|
return {
|
||||||
|
Accept_Ranges = Accept_Ranges;
|
||||||
|
Range = Range;
|
||||||
|
If_Range = If_Range;
|
||||||
|
Content_Range = Content_Range;
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
-- https://www.w3.org/TR/referrer-policy/#referrer-policy-header
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
|
||||||
|
local policy_token = C"no-referrer"
|
||||||
|
+ C"no-referrer-when-downgrade"
|
||||||
|
+ C"strict-origin"
|
||||||
|
+ C"strict-origin-when-cross-origin"
|
||||||
|
+ C"same-origin"
|
||||||
|
+ C"origin"
|
||||||
|
+ C"origin-when-cross-origin"
|
||||||
|
+ C"unsafe-url"
|
||||||
|
local Referrer_Policy = http_core.comma_sep_trim(policy_token, 1)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Referrer_Policy = Referrer_Policy;
|
||||||
|
}
|
||||||
@ -0,0 +1,186 @@
|
|||||||
|
-- RFC 7231
|
||||||
|
-- Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local email = require "lpeg_patterns.email"
|
||||||
|
local language = require "lpeg_patterns.language"
|
||||||
|
local uri = require "lpeg_patterns.uri"
|
||||||
|
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cf = lpeg.Cf
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local P = lpeg.P
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
|
||||||
|
-- RFC 7231 Section 3.1.1
|
||||||
|
local content_coding = http_core.token / string.lower -- case insensitive
|
||||||
|
local Content_Encoding = http_core.comma_sep_trim(content_coding, 1)
|
||||||
|
|
||||||
|
-- RFC 7231 Section 3.1.2
|
||||||
|
local type = http_core.token / string.lower -- case insensitive
|
||||||
|
local subtype = http_core.token / string.lower -- case insensitive
|
||||||
|
local parameter = http_core.token / string.lower -- case insensitive
|
||||||
|
* P"=" * (http_core.token + http_core.quoted_string)
|
||||||
|
local media_type = Cg(type, "type") * P"/" * Cg(subtype, "subtype")
|
||||||
|
* Cg(Cf(Ct(true) * (http_core.OWS * P";" * http_core.OWS * Cg(parameter))^0, rawset), "parameters")
|
||||||
|
local charset = http_core.token / string.lower -- case insensitive
|
||||||
|
local Content_Type = Ct(media_type)
|
||||||
|
|
||||||
|
-- RFC 7231 Section 3.1.3
|
||||||
|
local Content_Language = http_core.comma_sep_trim(language.Language_Tag, 1)
|
||||||
|
|
||||||
|
-- RFC 7231 Section 3.1.4.2
|
||||||
|
local Content_Location = uri.absolute_uri + http_core.partial_uri
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.1.1
|
||||||
|
local Expect = P"100-"*S"cC"*S"oO"*S"nN"*S"tT"*S"iI"*S"nN"*S"uU"*S"eE" * Cc("100-continue")
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.1.2
|
||||||
|
local Max_Forwards = core.DIGIT^1 / tonumber
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.3.1
|
||||||
|
-- local qvalue = http_core.rank -- luacheck: ignore 211
|
||||||
|
local weight = http_core.t_ranking
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.3.2
|
||||||
|
local media_range = (P"*/*"
|
||||||
|
+ (Cg(type, "type") * P"/*")
|
||||||
|
+ (Cg(type, "type") * P"/" * Cg(subtype, "subtype"))
|
||||||
|
) * Cg(Cf(Ct(true) * (http_core.OWS * ";" * http_core.OWS * Cg(parameter) - weight)^0, rawset), "parameters")
|
||||||
|
local accept_ext = http_core.OWS * P";" * http_core.OWS * http_core.token * (P"=" * (http_core.token + http_core.quoted_string))^-1
|
||||||
|
local accept_params = Cg(weight, "q") * Cg(Cf(Ct(true) * Cg(accept_ext)^0, rawset), "extensions")
|
||||||
|
local Accept = http_core.comma_sep_trim(Ct(media_range * (accept_params+Cg(Ct(true), "extensions"))))
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.3.3
|
||||||
|
local Accept_Charset = http_core.comma_sep_trim((charset + P"*") * weight^-1, 1)
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.3.4
|
||||||
|
local codings = content_coding + "*"
|
||||||
|
local Accept_Encoding = http_core.comma_sep_trim(codings * weight^-1)
|
||||||
|
|
||||||
|
-- RFC 4647 Section 2.1
|
||||||
|
local alphanum = core.ALPHA + core.DIGIT
|
||||||
|
local language_range = (core.ALPHA * core.ALPHA^-7 * (P"-" * alphanum * alphanum^-7)^0) + P"*"
|
||||||
|
-- RFC 7231 Section 5.3.5
|
||||||
|
local Accept_Language = http_core.comma_sep_trim(language_range * weight^-1, 1)
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.5.1
|
||||||
|
local From = email.mailbox
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.5.2
|
||||||
|
local Referer = uri.absolute_uri + http_core.partial_uri
|
||||||
|
|
||||||
|
-- RFC 7231 Section 5.5.3
|
||||||
|
local product_version = http_core.token
|
||||||
|
local product = http_core.token * (P"/" * product_version)^-1
|
||||||
|
local User_Agent = product * (http_core.RWS * (product + http_core.comment))^0
|
||||||
|
|
||||||
|
-- RFC 7231 Section 7.1.1.1
|
||||||
|
-- Uses os.date field names
|
||||||
|
local day_name = Cg(P"Mon"*Cc(2)
|
||||||
|
+ P"Tue"*Cc(3)
|
||||||
|
+ P"Wed"*Cc(4)
|
||||||
|
+ P"Thu"*Cc(5)
|
||||||
|
+ P"Fri"*Cc(6)
|
||||||
|
+ P"Sat"*Cc(7)
|
||||||
|
+ P"Sun"*Cc(1), "wday")
|
||||||
|
local day = Cg(core.DIGIT * core.DIGIT / tonumber, "day")
|
||||||
|
local month = Cg(P"Jan"*Cc(1)
|
||||||
|
+ P"Feb"*Cc(2)
|
||||||
|
+ P"Mar"*Cc(3)
|
||||||
|
+ P"Apr"*Cc(4)
|
||||||
|
+ P"May"*Cc(5)
|
||||||
|
+ P"Jun"*Cc(6)
|
||||||
|
+ P"Jul"*Cc(7)
|
||||||
|
+ P"Aug"*Cc(8)
|
||||||
|
+ P"Sep"*Cc(9)
|
||||||
|
+ P"Oct"*Cc(10)
|
||||||
|
+ P"Nov"*Cc(11)
|
||||||
|
+ P"Dec"*Cc(12), "month")
|
||||||
|
local year = Cg(core.DIGIT * core.DIGIT * core.DIGIT * core.DIGIT / tonumber, "year")
|
||||||
|
local date1 = day * core.SP * month * core.SP * year
|
||||||
|
|
||||||
|
local GMT = P"GMT"
|
||||||
|
|
||||||
|
local minute = Cg(core.DIGIT * core.DIGIT / tonumber, "min")
|
||||||
|
local second = Cg(core.DIGIT * core.DIGIT / tonumber, "sec")
|
||||||
|
local hour = Cg(core.DIGIT * core.DIGIT / tonumber, "hour")
|
||||||
|
-- XXX only match 00:00:00 - 23:59:60 (leap second)?
|
||||||
|
|
||||||
|
local time_of_day = hour * P":" * minute * P":" * second
|
||||||
|
local IMF_fixdate = Ct(day_name * P"," * core.SP * date1 * core.SP * time_of_day * core.SP * GMT)
|
||||||
|
|
||||||
|
local date2 do
|
||||||
|
local year_barrier = 70
|
||||||
|
local twodayyear = Cg(core.DIGIT * core.DIGIT / function(y)
|
||||||
|
y = tonumber(y, 10)
|
||||||
|
if y < year_barrier then
|
||||||
|
return 2000+y
|
||||||
|
else
|
||||||
|
return 1900+y
|
||||||
|
end
|
||||||
|
end, "year")
|
||||||
|
date2 = day * P"-" * month * P"-" * twodayyear
|
||||||
|
end
|
||||||
|
local day_name_l = Cg(P"Monday"*Cc(2)
|
||||||
|
+ P"Tuesday"*Cc(3)
|
||||||
|
+ P"Wednesday"*Cc(4)
|
||||||
|
+ P"Thursday"*Cc(5)
|
||||||
|
+ P"Friday"*Cc(6)
|
||||||
|
+ P"Saturday"*Cc(7)
|
||||||
|
+ P"Sunday"*Cc(1), "wday")
|
||||||
|
local rfc850_date = Ct(day_name_l * P"," * core.SP * date2 * core.SP * time_of_day * core.SP * GMT)
|
||||||
|
|
||||||
|
local date3 = month * core.SP * (day + Cg(core.SP * core.DIGIT / tonumber, "day"))
|
||||||
|
local asctime_date = Ct(day_name * core.SP * date3 * core.SP * time_of_day * core.SP * year)
|
||||||
|
local obs_date = rfc850_date + asctime_date
|
||||||
|
|
||||||
|
local HTTP_date = IMF_fixdate + obs_date
|
||||||
|
local Date = HTTP_date
|
||||||
|
|
||||||
|
-- RFC 7231 Section 7.1.2
|
||||||
|
local Location = uri.uri_reference
|
||||||
|
|
||||||
|
-- RFC 7231 Section 7.1.3
|
||||||
|
local delay_seconds = core.DIGIT^1 / tonumber
|
||||||
|
local Retry_After = HTTP_date + delay_seconds
|
||||||
|
|
||||||
|
-- RFC 7231 Section 7.1.4
|
||||||
|
local Vary = P"*" + http_core.comma_sep(http_core.field_name, 1)
|
||||||
|
|
||||||
|
-- RFC 7231 Section 7.4.1
|
||||||
|
local Allow = http_core.comma_sep_trim(http_core.method)
|
||||||
|
|
||||||
|
-- RFC 7231 Section 7.4.2
|
||||||
|
local Server = product * (http_core.RWS * (product + http_core.comment))^0
|
||||||
|
|
||||||
|
return {
|
||||||
|
HTTP_date = HTTP_date;
|
||||||
|
IMF_fixdate = IMF_fixdate;
|
||||||
|
media_type = media_type;
|
||||||
|
parameter = parameter;
|
||||||
|
|
||||||
|
Accept = Accept;
|
||||||
|
Accept_Charset = Accept_Charset;
|
||||||
|
Accept_Encoding = Accept_Encoding;
|
||||||
|
Accept_Language = Accept_Language;
|
||||||
|
Allow = Allow;
|
||||||
|
Content_Encoding = Content_Encoding;
|
||||||
|
Content_Language = Content_Language;
|
||||||
|
Content_Location = Content_Location;
|
||||||
|
Content_Type = Content_Type;
|
||||||
|
Date = Date;
|
||||||
|
Expect = Expect;
|
||||||
|
From = From;
|
||||||
|
Location = Location;
|
||||||
|
Max_Forwards = Max_Forwards;
|
||||||
|
Referer = Referer;
|
||||||
|
Retry_After = Retry_After;
|
||||||
|
Server = Server;
|
||||||
|
User_Agent = User_Agent;
|
||||||
|
Vary = Vary;
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
-- RFC 5023
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local Cs = lpeg.Cs
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
|
||||||
|
local slugtext = http_core.RWS / " "
|
||||||
|
+ P"%" * (core.HEXDIG * core.HEXDIG / util.read_hex) / string.char
|
||||||
|
+ R"\32\126"
|
||||||
|
|
||||||
|
local SLUG = Cs(slugtext^0)
|
||||||
|
|
||||||
|
return {
|
||||||
|
SLUG = SLUG;
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
-- RFC 6797
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local http_utils = require "lpeg_patterns.http.util"
|
||||||
|
|
||||||
|
local P = lpeg.P
|
||||||
|
|
||||||
|
local Strict_Transport_Security = http_utils.no_dup(http_utils.directive^-1 * (http_core.OWS * P";" * http_core.OWS * http_utils.directive^-1)^0)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Strict_Transport_Security = Strict_Transport_Security;
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
-- This is a private module containing utility functions shared by various http parsers
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
|
||||||
|
local P = lpeg.P
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local Cmt = lpeg.Cmt
|
||||||
|
|
||||||
|
local directive_name = http_core.token / string.lower
|
||||||
|
local directive_value = http_core.token + http_core.quoted_string
|
||||||
|
local directive = Cg(directive_name * ((http_core.OWS * P"=" * http_core.OWS * directive_value) + Cc(true)))
|
||||||
|
|
||||||
|
-- Helper function that doesn't match if there are duplicate keys
|
||||||
|
local function no_dup_cmt(s, i, t, name, value, ...)
|
||||||
|
local old = t[name]
|
||||||
|
if old then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
t[name] = value
|
||||||
|
if ... then
|
||||||
|
return no_dup_cmt(s, i, t, ...)
|
||||||
|
elseif t["max-age"] then -- max-age is required
|
||||||
|
return true, t
|
||||||
|
end
|
||||||
|
-- else return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function no_dup(patt)
|
||||||
|
return Cmt(Ct(true) * patt, no_dup_cmt)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
directive = directive;
|
||||||
|
no_dup = no_dup;
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
-- WebDAV
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_conditional = require "lpeg_patterns.http.conditional"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
local uri = require "lpeg_patterns.uri"
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local case_insensitive = util.case_insensitive
|
||||||
|
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local P = lpeg.P
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
local T_F = S"Tt" * Cc(true) + S"Ff" * Cc(false)
|
||||||
|
|
||||||
|
-- RFC 4918
|
||||||
|
local Coded_URL = P"<" * uri.absolute_uri * P">"
|
||||||
|
local extend = Coded_URL + http_core.token
|
||||||
|
local compliance_class = P"1" + P"2" + P"3" + extend
|
||||||
|
local DAV = http_core.comma_sep_trim(compliance_class)
|
||||||
|
local Depth = P"0" * Cc(0)
|
||||||
|
+ P"1" * Cc(1)
|
||||||
|
+ case_insensitive "infinity" * Cc(math.huge)
|
||||||
|
local Simple_ref = uri.absolute_uri + http_core.partial_uri
|
||||||
|
local Destination = Simple_ref
|
||||||
|
local State_token = Coded_URL
|
||||||
|
local Condition = (case_insensitive("not") * Cc("not"))^-1
|
||||||
|
* http_core.OWS * (State_token + P"[" * http_conditional.entity_tag * P"]")
|
||||||
|
local List = P"(" * http_core.OWS * (Condition * http_core.OWS)^1 * P")"
|
||||||
|
local No_tag_list = List
|
||||||
|
local Resource_Tag = P"<" * Simple_ref * P">"
|
||||||
|
local Tagged_list = Resource_Tag * http_core.OWS * (List * http_core.OWS)^1
|
||||||
|
local If = (Tagged_list * http_core.OWS)^1 + (No_tag_list * http_core.OWS)^1
|
||||||
|
local Lock_Token = Coded_URL
|
||||||
|
local Overwrite = T_F
|
||||||
|
local DAVTimeOutVal = core.DIGIT^1 / tonumber
|
||||||
|
local TimeType = case_insensitive "Second-" * DAVTimeOutVal
|
||||||
|
+ case_insensitive "Infinite" * Cc(math.huge)
|
||||||
|
local TimeOut = http_core.comma_sep_trim(TimeType)
|
||||||
|
|
||||||
|
-- RFC 5323
|
||||||
|
local DASL = http_core.comma_sep_trim(Coded_URL, 1)
|
||||||
|
|
||||||
|
-- RFC 6638
|
||||||
|
local Schedule_Reply = T_F
|
||||||
|
local Schedule_Tag = http_conditional.opaque_tag
|
||||||
|
local If_Schedule_Tag_Match = http_conditional.opaque_tag
|
||||||
|
|
||||||
|
-- RFC 7809
|
||||||
|
local CalDAV_Timezones = T_F
|
||||||
|
|
||||||
|
return {
|
||||||
|
CalDAV_Timezones = CalDAV_Timezones;
|
||||||
|
DASL = DASL;
|
||||||
|
DAV = DAV;
|
||||||
|
Depth = Depth;
|
||||||
|
Destination = Destination;
|
||||||
|
If = If;
|
||||||
|
If_Schedule_Tag_Match = If_Schedule_Tag_Match;
|
||||||
|
Lock_Token = Lock_Token;
|
||||||
|
Overwrite = Overwrite;
|
||||||
|
Schedule_Reply = Schedule_Reply;
|
||||||
|
Schedule_Tag = Schedule_Tag;
|
||||||
|
TimeOut = TimeOut;
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local http_core = require "lpeg_patterns.http.core"
|
||||||
|
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cf = lpeg.Cf
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local Cmt = lpeg.Cmt
|
||||||
|
local P = lpeg.P
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
-- RFC 6455
|
||||||
|
local base64_character = core.ALPHA + core.DIGIT + S"+/"
|
||||||
|
local base64_data = base64_character * base64_character * base64_character * base64_character
|
||||||
|
local base64_padding = base64_character * base64_character * P"=="
|
||||||
|
+ base64_character * base64_character * base64_character * P"="
|
||||||
|
local base64_value_non_empty = (base64_data^1 * base64_padding^-1) + base64_padding
|
||||||
|
local Sec_WebSocket_Accept = base64_value_non_empty
|
||||||
|
local Sec_WebSocket_Key = base64_value_non_empty
|
||||||
|
local registered_token = http_core.token
|
||||||
|
local extension_token = registered_token
|
||||||
|
local extension_param do
|
||||||
|
local EOF = P(-1)
|
||||||
|
local token_then_EOF = Cc(true) * http_core.token * EOF
|
||||||
|
-- the quoted-string must be a valid token
|
||||||
|
local quoted_token = Cmt(http_core.quoted_string, function(_, _, q)
|
||||||
|
return token_then_EOF:match(q)
|
||||||
|
end)
|
||||||
|
extension_param = http_core.token * ((P"=" * (http_core.token + quoted_token)) + Cc(true))
|
||||||
|
end
|
||||||
|
local extension = extension_token * Cg(Cf(Ct(true) * (P";" * Cg(extension_param))^0, rawset), "parameters")
|
||||||
|
local extension_list = http_core.comma_sep_trim(Ct(extension))
|
||||||
|
local Sec_WebSocket_Extensions = extension_list
|
||||||
|
local Sec_WebSocket_Protocol_Client = http_core.comma_sep_trim(http_core.token)
|
||||||
|
local Sec_WebSocket_Protocol_Server = http_core.token
|
||||||
|
local NZDIGIT = S"123456789"
|
||||||
|
-- Limited to 0-255 range, with no leading zeros
|
||||||
|
local version = (
|
||||||
|
P"2" * (S"01234" * core.DIGIT + P"5" * S"012345")
|
||||||
|
+ (P"1") * core.DIGIT * core.DIGIT
|
||||||
|
+ NZDIGIT * core.DIGIT^-1
|
||||||
|
) / tonumber
|
||||||
|
local Sec_WebSocket_Version_Client = version
|
||||||
|
local Sec_WebSocket_Version_Server = http_core.comma_sep_trim(version)
|
||||||
|
|
||||||
|
return {
|
||||||
|
Sec_WebSocket_Accept = Sec_WebSocket_Accept;
|
||||||
|
Sec_WebSocket_Key = Sec_WebSocket_Key;
|
||||||
|
Sec_WebSocket_Extensions = Sec_WebSocket_Extensions;
|
||||||
|
Sec_WebSocket_Protocol_Client = Sec_WebSocket_Protocol_Client;
|
||||||
|
Sec_WebSocket_Protocol_Server = Sec_WebSocket_Protocol_Server;
|
||||||
|
Sec_WebSocket_Version_Client = Sec_WebSocket_Version_Client;
|
||||||
|
Sec_WebSocket_Version_Server = Sec_WebSocket_Version_Server;
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
-- RFC 5646 Section 2.1
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
|
||||||
|
local C = lpeg.C
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
local Cmt = lpeg.Cmt
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local alphanum = core.ALPHA + core.DIGIT
|
||||||
|
|
||||||
|
local extlang = core.ALPHA * core.ALPHA * core.ALPHA * -#alphanum
|
||||||
|
* (P"-" * core.ALPHA * core.ALPHA * core.ALPHA * -#alphanum)^-2
|
||||||
|
|
||||||
|
local language = Cg(core.ALPHA * core.ALPHA * core.ALPHA * core.ALPHA * core.ALPHA * core.ALPHA^-3, "language")
|
||||||
|
+ Cg(core.ALPHA * core.ALPHA * core.ALPHA * core.ALPHA, "language")
|
||||||
|
+ Cg(core.ALPHA * core.ALPHA * core.ALPHA^-1, "language") * (P"-" * Cg(extlang, "extlang"))^-1
|
||||||
|
|
||||||
|
local script = core.ALPHA * core.ALPHA * core.ALPHA * core.ALPHA
|
||||||
|
* -#alphanum -- Prevent intepretation of a 'variant'
|
||||||
|
|
||||||
|
local region = (
|
||||||
|
core.ALPHA * core.ALPHA
|
||||||
|
+ core.DIGIT * core.DIGIT * core.DIGIT
|
||||||
|
) * -#alphanum -- Prevent intepretation of a 'variant'
|
||||||
|
|
||||||
|
local variant = core.DIGIT * alphanum * alphanum * alphanum
|
||||||
|
+ alphanum * alphanum * alphanum * alphanum * alphanum * alphanum^-3
|
||||||
|
|
||||||
|
local singleton = core.DIGIT + R("AW", "YZ", "aw", "yz")
|
||||||
|
|
||||||
|
local extension = C(singleton) * Ct((P"-" * (alphanum*alphanum*alphanum^-6 / string.lower))^1)
|
||||||
|
|
||||||
|
M.privateuse = P"x" * Ct((P"-" * C(alphanum*alphanum^-7))^1)
|
||||||
|
|
||||||
|
M.langtag = language
|
||||||
|
* (P"-" * Cg(script, "script"))^-1
|
||||||
|
* (P"-" * Cg(region, "region"))^-1
|
||||||
|
* Cg(Ct((P"-" * C(variant))^1), "variant")^-1
|
||||||
|
* Cg(Cmt(Ct((P"-" * Ct(extension))^1), function(_, _, c)
|
||||||
|
-- Can't use a fold with rawset as we want the pattern to not match if there is a duplicate extension
|
||||||
|
local r = {}
|
||||||
|
for _, v in ipairs(c) do
|
||||||
|
local a, b = v[1], v[2]
|
||||||
|
if r[a] then
|
||||||
|
-- duplicate extension
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
r[a] = b
|
||||||
|
end
|
||||||
|
return true, r
|
||||||
|
end), "extension")^-1
|
||||||
|
* (P"-" * Cg(M.privateuse, "privateuse"))^-1
|
||||||
|
|
||||||
|
local irregular = P"en-GB-oed"
|
||||||
|
+ P"i-ami"
|
||||||
|
+ P"i-bnn"
|
||||||
|
+ P"i-default"
|
||||||
|
+ P"i-enochian"
|
||||||
|
+ P"i-hak"
|
||||||
|
+ P"i-klingon"
|
||||||
|
+ P"i-lux"
|
||||||
|
+ P"i-mingo"
|
||||||
|
+ P"i-navajo"
|
||||||
|
+ P"i-pwn"
|
||||||
|
+ P"i-tao"
|
||||||
|
+ P"i-tay"
|
||||||
|
+ P"i-tsu"
|
||||||
|
+ P"sgn-BE-FR"
|
||||||
|
+ P"sgn-BE-NL"
|
||||||
|
+ P"sgn-CH-DE"
|
||||||
|
|
||||||
|
M.Language_Tag = C((M.langtag
|
||||||
|
+ M.privateuse
|
||||||
|
+ irregular) / function() end) -- capture the whole tag. throws away decomposition
|
||||||
|
|
||||||
|
return M
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
-- Phone numbers
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local P = lpeg.P
|
||||||
|
local R = lpeg.R
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
local digit = R"09"
|
||||||
|
local seperator = S"- ,."
|
||||||
|
local function optional_parens(patt)
|
||||||
|
return P"(" * patt * P")" + patt
|
||||||
|
end
|
||||||
|
|
||||||
|
local _M = {}
|
||||||
|
|
||||||
|
local extension = P"e" * (P"xt")^-1 * seperator^-1 * digit^1
|
||||||
|
local optional_extension = (seperator^-1 * extension)^-1
|
||||||
|
|
||||||
|
_M.Australia = (
|
||||||
|
-- Normal landlines
|
||||||
|
optional_parens((P"0")^-1*S"2378") * seperator^-1 * digit*digit*digit*digit * seperator^-1 * digit*digit*digit*digit
|
||||||
|
-- Mobile numbers
|
||||||
|
+ (optional_parens(P"0"*S"45"*digit*digit) + S"45"*digit*digit)
|
||||||
|
* seperator^-1 * digit*digit*digit * seperator^-1 * digit*digit*digit
|
||||||
|
-- Local rate calls
|
||||||
|
+ P"1300" * seperator^-1 * digit*digit*digit * seperator^-1 * digit*digit*digit
|
||||||
|
-- 1345 is only used for back-to-base monitored alarm systems
|
||||||
|
+ P"1345" * seperator^-1 * digit*digit * seperator^-1 * digit*digit
|
||||||
|
+ P"13" * seperator^-1 * digit*digit * seperator^-1 * digit*digit
|
||||||
|
+ (P"0")^-1*P"198" * seperator^-1 * digit*digit*digit * seperator^-1 * digit*digit*digit -- data calls
|
||||||
|
-- Free calls
|
||||||
|
+ P"1800" * seperator^-1 * digit*digit*digit * seperator^-1 * digit*digit*digit
|
||||||
|
+ P"180" * seperator^-1 * digit*digit*digit*digit
|
||||||
|
) * optional_extension
|
||||||
|
|
||||||
|
local NPA = (digit-S"01")*digit*digit
|
||||||
|
local NXX = ((digit-S"01")*(digit-P"9")-P"37"-P"96")*digit-P(1)*P"11"
|
||||||
|
local USSubscriber = digit*digit*digit*digit
|
||||||
|
_M.USA = ((P"1" * seperator^-1)^-1 * optional_parens(NPA) * seperator^-1)^-1
|
||||||
|
* NXX * seperator^-1 * USSubscriber * optional_extension
|
||||||
|
|
||||||
|
local international = (
|
||||||
|
P"1" * seperator^-1 * #(-P"1") * _M.USA
|
||||||
|
+ P"61" * seperator^-1 * #(digit-P"0") * _M.Australia
|
||||||
|
-- Other countries we haven't made specific patterns for yet
|
||||||
|
+(P"20"+P"212"+P"213"+P"216"+P"218"+P"220"+P"221"
|
||||||
|
+P"222"+P"223"+P"224"+P"225"+P"226"+P"227"+P"228"+P"229"
|
||||||
|
+P"230"+P"231"+P"232"+P"233"+P"234"+P"235"+P"236"+P"237"
|
||||||
|
+P"238"+P"239"+P"240"+P"241"+P"242"+P"243"+P"244"+P"245"
|
||||||
|
+P"246"+P"247"+P"248"+P"249"+P"250"+P"251"+P"252"+P"253"
|
||||||
|
+P"254"+P"255"+P"256"+P"257"+P"258"+P"260"+P"261"+P"262"
|
||||||
|
+P"263"+P"264"+P"265"+P"266"+P"267"+P"268"+P"269"+P"27"
|
||||||
|
+P"290"+P"291"+P"297"+P"298"+P"299"+P"30" +P"31" +P"32"
|
||||||
|
+P"33" +P"34" +P"350"+P"351"+P"352"+P"353"+P"354"+P"355"
|
||||||
|
+P"356"+P"357"+P"358"+P"359"+P"36" +P"370"+P"371"+P"372"
|
||||||
|
+P"373"+P"374"+P"375"+P"376"+P"377"+P"378"+P"380"+P"381"
|
||||||
|
+P"385"+P"386"+P"387"+P"389"+P"39" +P"40" +P"41" +P"420"
|
||||||
|
+P"421"+P"423"+P"43" +P"44" +P"45" +P"46" +P"47" +P"48"
|
||||||
|
+P"49" +P"500"+P"501"+P"502"+P"503"+P"504"+P"505"+P"506"
|
||||||
|
+P"507"+P"508"+P"509"+P"51" +P"52" +P"53" +P"54" +P"55"
|
||||||
|
+P"56" +P"57" +P"58" +P"590"+P"591"+P"592"+P"593"+P"594"
|
||||||
|
+P"595"+P"596"+P"597"+P"598"+P"599"+P"60" +P"62"
|
||||||
|
+P"63" +P"64" +P"65" +P"66" +P"670"+P"672"+P"673"+P"674"
|
||||||
|
+P"675"+P"676"+P"677"+P"678"+P"679"+P"680"+P"681"+P"682"
|
||||||
|
+P"683"+P"684"+P"685"+P"686"+P"687"+P"688"+P"689"+P"690"
|
||||||
|
+P"691"+P"692"+P"7" +P"808"+P"81" +P"82" +P"84" +P"850"
|
||||||
|
+P"852"+P"853"+P"855"+P"856"+P"86" +P"870"+P"871"+P"872"
|
||||||
|
+P"873"+P"874"+P"878"+P"880"+P"881"+P"886"+P"90" +P"91"
|
||||||
|
+P"92" +P"93" +P"94" +P"95" +P"960"+P"961"+P"962"+P"963"
|
||||||
|
+P"964"+P"965"+P"966"+P"967"+P"968"+P"970"+P"971"+P"972"
|
||||||
|
+P"973"+P"974"+P"975"+P"976"+P"977"+P"98" +P"992"+P"993"
|
||||||
|
+P"994"+P"995"+P"996"+P"998" ) * (seperator^-1*digit)^6 -- At least 6 digits
|
||||||
|
)
|
||||||
|
|
||||||
|
_M.phone = P"+" * seperator^-1 * international
|
||||||
|
|
||||||
|
return _M
|
||||||
@ -0,0 +1,143 @@
|
|||||||
|
-- URI
|
||||||
|
-- RFC 3986
|
||||||
|
|
||||||
|
local lpeg = require "lpeg"
|
||||||
|
local P = lpeg.P
|
||||||
|
local S = lpeg.S
|
||||||
|
local C = lpeg.C
|
||||||
|
local Cc = lpeg.Cc
|
||||||
|
local Cg = lpeg.Cg
|
||||||
|
local Cs = lpeg.Cs
|
||||||
|
local Ct = lpeg.Ct
|
||||||
|
|
||||||
|
local util = require "lpeg_patterns.util"
|
||||||
|
|
||||||
|
local core = require "lpeg_patterns.core"
|
||||||
|
local ALPHA = core.ALPHA
|
||||||
|
local DIGIT = core.DIGIT
|
||||||
|
local HEXDIG = core.HEXDIG
|
||||||
|
|
||||||
|
local IPv4address = require "lpeg_patterns.IPv4".IPv4address
|
||||||
|
local IPv6address = require "lpeg_patterns.IPv6".IPv6address
|
||||||
|
|
||||||
|
local _M = {}
|
||||||
|
|
||||||
|
_M.sub_delims = S"!$&'()*+,;=" -- 2.2
|
||||||
|
local unreserved = ALPHA + DIGIT + S"-._~" -- 2.3
|
||||||
|
_M.pct_encoded = P"%" * (HEXDIG * HEXDIG / util.read_hex) / function(n)
|
||||||
|
local c = string.char(n)
|
||||||
|
if unreserved:match(c) then
|
||||||
|
-- always decode unreserved characters (2.3)
|
||||||
|
return c
|
||||||
|
else
|
||||||
|
-- normalise to upper-case (6.2.2.1)
|
||||||
|
return string.format("%%%02X", n)
|
||||||
|
end
|
||||||
|
end -- 2.1
|
||||||
|
|
||||||
|
_M.scheme = ALPHA * (ALPHA + DIGIT + S"+-.")^0 / string.lower -- 3.1
|
||||||
|
|
||||||
|
_M.userinfo = Cs((unreserved + _M.pct_encoded + _M.sub_delims + P":")^0) -- 3.2.1
|
||||||
|
|
||||||
|
-- Host 3.2.2
|
||||||
|
|
||||||
|
local IPvFuture_mt = {
|
||||||
|
__name = "lpeg_patterns.IPvFuture";
|
||||||
|
}
|
||||||
|
function IPvFuture_mt:__tostring()
|
||||||
|
return string.format("v%x.%s", self.version, self.string)
|
||||||
|
end
|
||||||
|
local function new_IPvFuture(version, string)
|
||||||
|
return setmetatable({version=version, string=string}, IPvFuture_mt)
|
||||||
|
end
|
||||||
|
local IPvFuture = S"vV" * (HEXDIG^1/util.read_hex) * P"." * C((unreserved+_M.sub_delims+P":")^1) / new_IPvFuture
|
||||||
|
|
||||||
|
-- RFC 6874
|
||||||
|
local ZoneID = Cs((unreserved + _M.pct_encoded)^1)
|
||||||
|
local IPv6addrz = IPv6address * (P"%25" * ZoneID)^-1 / function(IPv6, zoneid)
|
||||||
|
IPv6:setzoneid(zoneid)
|
||||||
|
return IPv6
|
||||||
|
end
|
||||||
|
|
||||||
|
_M.IP_literal = P"[" * (IPv6addrz + IPvFuture) * P"]"
|
||||||
|
local IP_host = (_M.IP_literal + IPv4address) / tostring
|
||||||
|
local reg_name = Cs((
|
||||||
|
unreserved / string.lower
|
||||||
|
+ _M.pct_encoded / function(s) return s:sub(1,1) == "%" and s or string.lower(s) end
|
||||||
|
+ _M.sub_delims
|
||||||
|
)^1) + Cc(nil)
|
||||||
|
_M.host = IP_host + reg_name
|
||||||
|
|
||||||
|
_M.port = DIGIT^0 / tonumber -- 3.2.3
|
||||||
|
|
||||||
|
-- Path 3.3
|
||||||
|
local pchar = unreserved + _M.pct_encoded + _M.sub_delims + S":@"
|
||||||
|
local segment = pchar^0
|
||||||
|
_M.segment = Cs(segment)
|
||||||
|
local segment_nz = pchar^1
|
||||||
|
local segment_nz_nc = (pchar - P":")^1
|
||||||
|
|
||||||
|
-- an empty path is nil instead of the empty string
|
||||||
|
local path_empty = Cc(nil)
|
||||||
|
local path_abempty = Cs((P"/" * segment)^1) + path_empty
|
||||||
|
local path_rootless = Cs(segment_nz * (P"/" * segment)^0)
|
||||||
|
local path_noscheme = Cs(segment_nz_nc * (P"/" * segment)^0)
|
||||||
|
local path_absolute = Cs(P"/" * (segment_nz * (P"/" * segment)^0)^-1)
|
||||||
|
|
||||||
|
_M.query = Cs( ( pchar + S"/?" )^0 ) -- 3.4
|
||||||
|
_M.fragment = _M.query -- 3.5
|
||||||
|
|
||||||
|
-- Put together with named captures
|
||||||
|
_M.authority = ( Cg(_M.userinfo, "userinfo") * P"@" )^-1
|
||||||
|
* Cg(_M.host, "host")
|
||||||
|
* ( P":" * Cg(_M.port, "port") )^-1
|
||||||
|
|
||||||
|
local hier_part = P"//" * _M.authority * Cg (path_abempty, "path")
|
||||||
|
+ Cg(path_absolute + path_rootless + path_empty, "path")
|
||||||
|
|
||||||
|
_M.absolute_uri = Ct (
|
||||||
|
( Cg(_M.scheme, "scheme") * P":" )
|
||||||
|
* hier_part
|
||||||
|
* ( P"?" * Cg(_M.query, "query"))^-1
|
||||||
|
)
|
||||||
|
|
||||||
|
_M.uri = Ct (
|
||||||
|
( Cg(_M.scheme, "scheme") * P":" )
|
||||||
|
* hier_part
|
||||||
|
* ( P"?" * Cg(_M.query, "query"))^-1
|
||||||
|
* ( P"#" * Cg(_M.fragment, "fragment"))^-1
|
||||||
|
)
|
||||||
|
|
||||||
|
_M.relative_part = P"//" * _M.authority * Cg(path_abempty, "path")
|
||||||
|
+ Cg(path_absolute + path_noscheme + path_empty, "path")
|
||||||
|
|
||||||
|
local relative_ref = Ct (
|
||||||
|
_M.relative_part
|
||||||
|
* ( P"?" * Cg(_M.query, "query"))^-1
|
||||||
|
* ( P"#" * Cg(_M.fragment, "fragment"))^-1
|
||||||
|
)
|
||||||
|
_M.uri_reference = _M.uri + relative_ref
|
||||||
|
|
||||||
|
_M.path = path_abempty + path_absolute + path_noscheme + path_rootless + path_empty
|
||||||
|
|
||||||
|
-- Create a slightly more sane host pattern
|
||||||
|
-- scheme is optional
|
||||||
|
-- the "//" isn't required
|
||||||
|
-- if missing, the host needs to at least have a "." and end in two alpha characters
|
||||||
|
-- an authority is always required
|
||||||
|
local sane_host_char = unreserved / string.lower
|
||||||
|
local hostsegment = (sane_host_char - P".")^1
|
||||||
|
local dns_entry = Cs ( ( hostsegment * P"." )^1 * ALPHA^2 )
|
||||||
|
_M.sane_host = IP_host + dns_entry
|
||||||
|
_M.sane_authority = ( Cg(_M.userinfo, "userinfo") * P"@" )^-1
|
||||||
|
* Cg(_M.sane_host, "host")
|
||||||
|
* ( P":" * Cg(_M.port, "port") )^-1
|
||||||
|
local sane_hier_part = (P"//")^-1 * _M.sane_authority * Cg(path_absolute + path_empty, "path")
|
||||||
|
_M.sane_uri = Ct (
|
||||||
|
( Cg(_M.scheme, "scheme") * P":" )^-1
|
||||||
|
* sane_hier_part
|
||||||
|
* ( P"?" * Cg(_M.query, "query"))^-1
|
||||||
|
* ( P"#" * Cg(_M.fragment, "fragment"))^-1
|
||||||
|
)
|
||||||
|
|
||||||
|
return _M
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
local lpeg = require "lpeg"
|
||||||
|
local C = lpeg.C
|
||||||
|
local P = lpeg.P
|
||||||
|
local S = lpeg.S
|
||||||
|
|
||||||
|
local function case_insensitive(str)
|
||||||
|
local patt = P(true)
|
||||||
|
for i=1, #str do
|
||||||
|
local c = str:sub(i, i)
|
||||||
|
patt = patt * S(c:upper() .. c:lower())
|
||||||
|
end
|
||||||
|
return patt
|
||||||
|
end
|
||||||
|
|
||||||
|
local function no_rich_capture(patt)
|
||||||
|
return C(patt) / function(a) return a end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function read_hex(hex_num)
|
||||||
|
return tonumber(hex_num, 16)
|
||||||
|
end
|
||||||
|
|
||||||
|
local safe_tonumber do -- locale independent tonumber function
|
||||||
|
local tolocale
|
||||||
|
local function updatelocale()
|
||||||
|
local decpoint = string.format("%f", 0.5):match "[^05]+"
|
||||||
|
if decpoint == "." then
|
||||||
|
tolocale = function(str)
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tolocale = function(str)
|
||||||
|
str = str:gsub("%.", decpoint, 1)
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
updatelocale()
|
||||||
|
safe_tonumber = function(str)
|
||||||
|
local num = tonumber(tolocale(str))
|
||||||
|
if num then
|
||||||
|
return num
|
||||||
|
else
|
||||||
|
updatelocale()
|
||||||
|
return tonumber(tolocale(str))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
case_insensitive = case_insensitive;
|
||||||
|
no_rich_capture = no_rich_capture;
|
||||||
|
read_hex = read_hex;
|
||||||
|
safe_tonumber = safe_tonumber;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,41 @@
|
|||||||
|
local switch = {}
|
||||||
|
|
||||||
|
switch.__index = switch
|
||||||
|
|
||||||
|
switch.__call = function(self, v)
|
||||||
|
local c = self._callbacks[v] or self._default
|
||||||
|
assert(c, "No case statement defined for variable, and :default is not defined")
|
||||||
|
c()
|
||||||
|
end
|
||||||
|
|
||||||
|
function switch:case(v, f)
|
||||||
|
self._callbacks[v] = f
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function switch:default(f)
|
||||||
|
self._default = f
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
return function()
|
||||||
|
return setmetatable({
|
||||||
|
_callbacks = {},
|
||||||
|
}, switch)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- local switch = require 'switch'
|
||||||
|
|
||||||
|
-- local numbercase = switch()
|
||||||
|
-- :case(10, function()
|
||||||
|
-- print("Hello Ten")
|
||||||
|
-- end)
|
||||||
|
|
||||||
|
-- :case(20, function()
|
||||||
|
-- print("Hello Twenty")
|
||||||
|
-- end)
|
||||||
|
|
||||||
|
-- :default(function()
|
||||||
|
-- print("Unrecognised")
|
||||||
|
-- end)
|
||||||
|
-- numbercase(15 + 5)
|
||||||
@ -0,0 +1,148 @@
|
|||||||
|
-- =========================================
|
||||||
|
-- tuple, A minimal tuple class for Lua
|
||||||
|
-- https://github.com/Yonaba/tuple.lua
|
||||||
|
-- =========================================
|
||||||
|
local unpack = unpack or table.unpack
|
||||||
|
local setmetatable = setmetatable
|
||||||
|
local ipairs = ipairs
|
||||||
|
local tostring = tostring
|
||||||
|
local min = math.min
|
||||||
|
local type = type
|
||||||
|
local assert = assert
|
||||||
|
local select = select
|
||||||
|
local t_concat = table.concat
|
||||||
|
|
||||||
|
local tuple = {}
|
||||||
|
tuple.__index = tuple
|
||||||
|
|
||||||
|
-- Collects values i to j to return a new tuple
|
||||||
|
function tuple.__call(t, i, j)
|
||||||
|
return tuple(unpack(t, i, j))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns a string representation of tuple
|
||||||
|
function tuple:__tostring()
|
||||||
|
local t = self:toArray()
|
||||||
|
for k, v in ipairs(t) do
|
||||||
|
t[k] = tostring(v)
|
||||||
|
end
|
||||||
|
return ('(%s)'):format(t_concat(t, ', '))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tuple elements iterator function
|
||||||
|
function tuple:elements(...)
|
||||||
|
local i = 0
|
||||||
|
return function(...)
|
||||||
|
i = i + 1
|
||||||
|
if self[i] ~= nil then
|
||||||
|
return i, self[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns tuple length
|
||||||
|
function tuple:len()
|
||||||
|
return self.n
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tests if tuple contains element v
|
||||||
|
function tuple:has(v)
|
||||||
|
for k, _v in ipairs(self) do
|
||||||
|
if _v == v then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Does this tuple includes all elements in tuple other ?
|
||||||
|
function tuple:includes(other)
|
||||||
|
if self.n < other.n then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for _, element in other:elements() do
|
||||||
|
if not self:has(element) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Converts tuple to simpe array ?
|
||||||
|
function tuple:toArray()
|
||||||
|
return {unpack(self)}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ==========
|
||||||
|
-- Operators
|
||||||
|
-- ==========
|
||||||
|
|
||||||
|
-- Tuple equality test
|
||||||
|
function tuple:__eq(other)
|
||||||
|
if self.n ~= other.n then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for i, element in other:elements() do
|
||||||
|
if element ~= self[i] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tuple relational <= comparison
|
||||||
|
function tuple:__le(other)
|
||||||
|
local n = min(self.n, other.n)
|
||||||
|
for i = 1, n do
|
||||||
|
if (self[i] > other[i]) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tuple relational < comparison
|
||||||
|
function tuple:__lt(other)
|
||||||
|
local n = min(self.n, other.n)
|
||||||
|
for i = 1, n do
|
||||||
|
if self[i] >= other[i] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Tuple addition
|
||||||
|
function tuple.__add(a, b)
|
||||||
|
local t = a()
|
||||||
|
for _, element in b:elements() do
|
||||||
|
t[#t + 1] = element
|
||||||
|
end
|
||||||
|
t.n = #t
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Multiplication
|
||||||
|
function tuple.__mul(t, n)
|
||||||
|
if type(n) == 'number' then
|
||||||
|
assert(math.floor(n) == n, ('Wrong argument n. Integer expected, got (%s)'):format(n))
|
||||||
|
local _t
|
||||||
|
for i = 1, n do
|
||||||
|
_t = (_t or tuple()) + t
|
||||||
|
end
|
||||||
|
return _t
|
||||||
|
else
|
||||||
|
return n * t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Class constructor, wrapping up and return
|
||||||
|
return setmetatable(tuple, {
|
||||||
|
__call = function(self, ...)
|
||||||
|
local new_tuple = {
|
||||||
|
n = select('#', ...),
|
||||||
|
...,
|
||||||
|
}
|
||||||
|
return setmetatable(new_tuple, tuple)
|
||||||
|
end,
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue