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