|
1 | | --- |
2 | | --- Author: Alexey Melnichuk <mimir@newmail.ru> |
3 | | --- |
4 | | --- Copyright (C) 2014 Alexey Melnichuk <mimir@newmail.ru> |
5 | | --- |
6 | | --- Licensed according to the included 'LICENSE' document |
7 | | --- |
8 | | --- This file is part of lua-lcurl library. |
9 | | --- |
10 | | - |
11 | | --- |
12 | | --- Implementation of Lua-cURL http://msva.github.io/lua-curl |
13 | | --- |
14 | | - |
15 | 1 | local curl = require "lcurl" |
| 2 | +local impl = require "cURL.impl.cURL" |
16 | 3 |
|
17 | | -local function wrap_function(k) |
18 | | - return function(self, ...) |
19 | | - local ok, err = self._handle[k](self._handle, ...) |
20 | | - if ok == self._handle then return self end |
21 | | - return ok, err |
22 | | - end |
23 | | -end |
24 | | - |
25 | | -local function wrap_setopt_flags(k, flags) |
26 | | - k = "setopt_" .. k |
27 | | - return function(self, v) |
28 | | - v = assert(flags[v], "Unsupported value " .. tostring(v)) |
29 | | - local ok, err = self._handle[k](self._handle, v) |
30 | | - if ok == self._handle then return self end |
31 | | - return ok, err |
32 | | - end |
33 | | -end |
34 | | - |
35 | | -local function class(ctor) |
36 | | - local C = {} |
37 | | - C.__index = function(self, k) |
38 | | - local fn = C[k] |
39 | | - |
40 | | - if not fn and self._handle[k] then |
41 | | - fn = wrap_function(k) |
42 | | - self[k] = fn |
43 | | - end |
44 | | - return fn |
45 | | - end |
46 | | - |
47 | | - function C:new() |
48 | | - local h, err = ctor() |
49 | | - if not h then return nil, err end |
50 | | - |
51 | | - local o = setmetatable({ |
52 | | - _handle = h |
53 | | - }, self) |
54 | | - |
55 | | - return o |
56 | | - end |
57 | | - |
58 | | - function C:handle() |
59 | | - return self._handle |
60 | | - end |
61 | | - |
62 | | - return C |
63 | | -end |
64 | | - |
65 | | -------------------------------------------- |
66 | | -local Easy = class(curl.easy) do |
67 | | - |
68 | | -local perform = wrap_function("perform") |
69 | | -local setopt_share = wrap_function("setopt_share") |
70 | | -local setopt_readfunction = wrap_function("setopt_readfunction") |
71 | | - |
72 | | -local NONE = {} |
73 | | - |
74 | | -function Easy:_call_readfunction(...) |
75 | | - if self._rd_ud == NONE then |
76 | | - return self._rd_fn(...) |
77 | | - end |
78 | | - return self._rd_fn(self._rd_ud, ...) |
79 | | -end |
80 | | - |
81 | | -function Easy:setopt_readfunction(fn, ...) |
82 | | - assert(fn) |
83 | | - |
84 | | - if select('#', ...) == 0 then |
85 | | - if type(fn) == "function" then |
86 | | - self._rd_fn = fn |
87 | | - self._rd_ud = NONE |
88 | | - else |
89 | | - self._rd_fn = assert(fn.read) |
90 | | - self._rd_ud = fn |
91 | | - end |
92 | | - else |
93 | | - self._rd_fn = fn |
94 | | - self._ud_fn = ... |
95 | | - end |
96 | | - |
97 | | - return setopt_readfunction(self, fn, ...) |
98 | | -end |
99 | | - |
100 | | -function Easy:perform(opt) |
101 | | - opt = opt or {} |
102 | | - |
103 | | - local oerror = opt.errorfunction or function(err) return nil, err end |
104 | | - |
105 | | - if opt.readfunction then |
106 | | - local ok, err = self:setopt_readfunction(opt.readfunction) |
107 | | - if not ok then return oerror(err) end |
108 | | - end |
109 | | - |
110 | | - if opt.writefunction then |
111 | | - local ok, err = self:setopt_writefunction(opt.writefunction) |
112 | | - if not ok then return oerror(err) end |
113 | | - end |
114 | | - |
115 | | - if opt.headerfunction then |
116 | | - local ok, err = self:setopt_headerfunction(opt.headerfunction) |
117 | | - if not ok then return oerror(err) end |
118 | | - end |
119 | | - |
120 | | - local ok, err = perform(self) |
121 | | - if not ok then return oerror(err) end |
122 | | - |
123 | | - return self |
124 | | -end |
125 | | - |
126 | | -function Easy:post(data) |
127 | | - local form = curl.form() |
128 | | - local ok, err = true |
129 | | - |
130 | | - for k, v in pairs(data) do |
131 | | - if type(v) == "string" then |
132 | | - ok, err = form:add_content(k, v) |
133 | | - else |
134 | | - assert(type(v) == "table") |
135 | | - if v.stream_length then |
136 | | - local len = assert(tonumber(v.stream_length)) |
137 | | - assert(v.file) |
138 | | - if v.stream then |
139 | | - ok, err = form:add_stream(k, v.file, v.type, v.headers, len, v.stream) |
140 | | - else |
141 | | - ok, err = form:add_stream(k, v.file, v.type, v.headers, len, self._call_readfunction, self) |
142 | | - end |
143 | | - elseif v.data then |
144 | | - ok, err = form:add_buffer(k, v.file, v.data, v.type, v.headers) |
145 | | - else |
146 | | - ok, err = form:add_file(k, v.file, v.type, v.filename, v.headers) |
147 | | - end |
148 | | - end |
149 | | - if not ok then break end |
150 | | - end |
151 | | - |
152 | | - if not ok then |
153 | | - form:free() |
154 | | - return nil, err |
155 | | - end |
156 | | - |
157 | | - ok, err = self:setopt_httppost(form) |
158 | | - if not ok then |
159 | | - form:free() |
160 | | - return nil, err |
161 | | - end |
162 | | - |
163 | | - return self |
164 | | -end |
165 | | - |
166 | | -function Easy:setopt_share(s) |
167 | | - return setopt_share(self, s:handle()) |
168 | | -end |
169 | | - |
170 | | -Easy.setopt_proxytype = wrap_setopt_flags("proxytype", { |
171 | | - ["HTTP" ] = curl.PROXY_HTTP; |
172 | | - ["HTTP_1_0" ] = curl.PROXY_HTTP_1_0; |
173 | | - ["SOCKS4" ] = curl.PROXY_SOCKS4; |
174 | | - ["SOCKS5" ] = curl.PROXY_SOCKS5; |
175 | | - ["SOCKS4A" ] = curl.PROXY_SOCKS4A; |
176 | | - ["SOCKS5_HOSTNAME" ] = curl.PROXY_SOCKS5_HOSTNAME; |
177 | | -}) |
178 | | - |
179 | | -Easy.setopt_httpauth = wrap_setopt_flags("httpauth", { |
180 | | - ["NONE" ] = curl.AUTH_NONE; |
181 | | - ["BASIC" ] = curl.AUTH_BASIC; |
182 | | - ["DIGEST" ] = curl.AUTH_DIGEST; |
183 | | - ["GSSNEGOTIATE" ] = curl.AUTH_GSSNEGOTIATE; |
184 | | - ["NTLM" ] = curl.AUTH_NTLM; |
185 | | - ["DIGEST_IE" ] = curl.AUTH_DIGEST_IE; |
186 | | - ["NTLM_WB" ] = curl.AUTH_NTLM_WB; |
187 | | - ["ONLY" ] = curl.AUTH_ONLY; |
188 | | - ["ANY" ] = curl.AUTH_ANY; |
189 | | - ["ANYSAFE" ] = curl.AUTH_ANYSAFE; |
190 | | - ["SSH_ANY" ] = curl.SSH_AUTH_ANY; |
191 | | - ["SSH_NONE" ] = curl.SSH_AUTH_NONE; |
192 | | - ["SSH_PUBLICKEY" ] = curl.SSH_AUTH_PUBLICKEY; |
193 | | - ["SSH_PASSWORD" ] = curl.SSH_AUTH_PASSWORD; |
194 | | - ["SSH_HOST" ] = curl.SSH_AUTH_HOST; |
195 | | - ["SSH_KEYBOARD" ] = curl.SSH_AUTH_KEYBOARD; |
196 | | - ["SSH_AGENT" ] = curl.SSH_AUTH_AGENT; |
197 | | - ["SSH_DEFAULT" ] = curl.SSH_AUTH_DEFAULT; |
198 | | -}) |
199 | | - |
200 | | -end |
201 | | -------------------------------------------- |
202 | | - |
203 | | -------------------------------------------- |
204 | | -local Multi = class(curl.multi) do |
205 | | - |
206 | | -local perform = wrap_function("perform") |
207 | | -local add_handle = wrap_function("add_handle") |
208 | | -local remove_handle = wrap_function("remove_handle") |
209 | | - |
210 | | -local function make_iterator(self) |
211 | | - local curl = require "lcurl.safe" |
212 | | - |
213 | | - local buffers = {resp = {}, _ = {}} do |
214 | | - |
215 | | - function buffers:append(e, ...) |
216 | | - local resp = assert(e:getinfo_response_code()) |
217 | | - if not self._[e] then self._[e] = {} end |
218 | | - |
219 | | - local b = self._[e] |
220 | | - |
221 | | - if self.resp[e] ~= resp then |
222 | | - b[#b + 1] = {"response", resp} |
223 | | - self.resp[e] = resp |
224 | | - end |
225 | | - |
226 | | - b[#b + 1] = {...} |
227 | | - end |
228 | | - |
229 | | - function buffers:next() |
230 | | - for e, t in pairs(self._) do |
231 | | - local m = table.remove(t, 1) |
232 | | - if m then return e, m end |
233 | | - end |
234 | | - end |
235 | | - |
236 | | - end |
237 | | - |
238 | | - local remain = #self._easy |
239 | | - for _, e in ipairs(self._easy) do |
240 | | - e:setopt_writefunction (function(str) buffers:append(e, "data", str) end) |
241 | | - e:setopt_headerfunction(function(str) buffers:append(e, "header", str) end) |
242 | | - end |
243 | | - |
244 | | - assert(perform(self)) |
245 | | - |
246 | | - return function() |
247 | | - while true do |
248 | | - local e, t = buffers:next() |
249 | | - if t then return t[2], t[1], e end |
250 | | - if remain == 0 then break end |
251 | | - |
252 | | - self:wait() |
253 | | - |
254 | | - local n, err = assert(perform(self)) |
255 | | - |
256 | | - if n <= remain then |
257 | | - while true do |
258 | | - local e, ok, err = assert(self:info_read()) |
259 | | - if e == 0 then break end |
260 | | - for _, a in ipairs(self._easy) do |
261 | | - if e == a:handle() then e = a break end |
262 | | - end |
263 | | - if ok then buffers:append(e, "done", ok) |
264 | | - else buffers:append(e, "error", err) end |
265 | | - end |
266 | | - remain = n |
267 | | - end |
268 | | - |
269 | | - end |
270 | | - end |
271 | | -end |
272 | | - |
273 | | -function Multi:perform() |
274 | | - return make_iterator(self) |
275 | | -end |
276 | | - |
277 | | -function Multi:add_handle(e) |
278 | | - self._easy[#self._easy + 1] = e |
279 | | - return add_handle(self, e:handle()) |
280 | | -end |
281 | | - |
282 | | -function Multi:remove_handle(e) |
283 | | - self._easy[#self._easy + 1] = e |
284 | | - return remove_handle(self, e:handle()) |
285 | | -end |
286 | | - |
287 | | -end |
288 | | -------------------------------------------- |
289 | | - |
290 | | -------------------------------------------- |
291 | | -local Share = class(curl.share) do |
292 | | - |
293 | | -Share.setopt_share = wrap_setopt_flags("share", { |
294 | | - [ "COOKIE" ] = curl.LOCK_DATA_COOKIE; |
295 | | - [ "DNS" ] = curl.LOCK_DATA_DNS; |
296 | | - [ "SSL_SESSION" ] = curl.LOCK_DATA_SSL_SESSION; |
297 | | -}) |
298 | | - |
299 | | -end |
300 | | -------------------------------------------- |
301 | | - |
302 | | -local cURL = setmetatable({}, {__index = curl}) |
303 | | - |
304 | | -function cURL.easy_init() return Easy:new() end |
305 | | - |
306 | | -function cURL.multi_init() return Multi:new() end |
307 | | - |
308 | | -function cURL.share_init() return Share:new() end |
309 | | - |
310 | | -return cURL |
| 4 | +return impl(curl) |
0 commit comments