-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathparser.lua
120 lines (96 loc) · 2.54 KB
/
parser.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
local find = string.find
local sub = string.sub
local re_match = ngx.re.match
local re_find = ngx.re.find
local _M = {}
local mt = { __index = _M }
local match_table = {}
local function get_boundary(header)
if type(header) == "table" then
header = header[1]
end
match_table[1] = nil
match_table[2] = nil
local m, err = re_match(header,
[[;\s*boundary\s*=\s*(?:"([^"]+)"|([-|+*$&!.%'`~^\#\w]+))]],
"joi", nil, match_table)
if m then
return m[1] or m[2]
end
if err then
return nil, "bad regex: " .. err
end
return nil
end
function _M.new(body, content_type)
if not content_type then
return nil, "no Content-Type header specified"
end
local boundary, err = get_boundary(content_type)
if not boundary then
if err then
return nil, err
end
return nil, "no boundary defined in Content-Type"
end
return setmetatable({
start = 1,
boundary = "--" .. boundary,
boundary2 = "\r\n--" .. boundary,
body = body,
}, mt)
end
function _M.parse_part(self)
local start = self.start
local body = self.body
if start == 1 then
local fr, to = find(body, self.boundary, 1, true)
if not fr then
return nil
end
-- ignore the preamble
start = to + 1
end
-- parse headers
local fr, to = find(body, "\r\n\r\n", start, true)
if not fr then
self.start = start
return nil, "missing header"
end
local header = sub(body, start, fr + 2)
start = to + 1
-- parse the "name" parameter:
match_table[1] = nil
match_table[2] = nil
local m, err = re_match(header,
[[^Content-Disposition:.*?;\s*name\s*=\s*(?:"([^"]+)"|([-'\w]+))]],
"joim", nil, match_table)
local name
if m then
name = m[1] or m[2]
end
m, err = re_match(header,
[[^Content-Disposition:.*?;\s*filename\s*=\s*(?:"([^"]+)"|([-'\w]+))]],
"joim", nil, match_table)
local filename
if m then
filename = m[1] or m[2]
end
-- parse the MIME type:
local fr, to = re_find(header, [[^Content-Type:\s*([^;\s]+)]], "joim",
nil, 1)
local mime
if fr then
mime = sub(header, fr, to)
end
-- find delimiter:
fr, to = find(body, self.boundary2, start, true)
if not fr then
self.start = start
return nil
end
local part_body = sub(body, start, fr - 1)
self.start = to + 3
return part_body, name, mime, filename
end
return _M