Skip to content

Commit 0c60ed8

Browse files
committed
Downloader: new module to HTTP fetch data
1 parent 8a462f6 commit 0c60ed8

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

ffi/downloader.lua

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
local http = require("socket.http")
2+
local ffi = require("ffi")
3+
4+
local Downloader = {}
5+
6+
function Downloader:new()
7+
local o = {}
8+
setmetatable(o, self)
9+
self.__index = self
10+
return o
11+
end
12+
13+
function Downloader:free()
14+
self.ce:free()
15+
self.ce = nil
16+
end
17+
18+
local function merge_ranges(ranges)
19+
local new_ranges = {}
20+
for i, r in ipairs(ranges) do
21+
if #new_ranges > 0 and new_ranges[#new_ranges][2] == r[1] - 1 then
22+
new_ranges[#new_ranges][2] = r[2]
23+
else
24+
table.insert(new_ranges, r)
25+
end
26+
end
27+
return new_ranges
28+
end
29+
30+
function Downloader:fetch(url, callback, ranges, etag, stats)
31+
assert(not (ranges and etag))
32+
self.status_code = nil
33+
self.etag = nil
34+
local ok
35+
local sink = function(s)
36+
return s and callback(ffi.cast("uint8_t *", s), #s)
37+
end
38+
local body, status_code, resp_headers, status_line
39+
if ranges then
40+
body, status_code, resp_headers, status_line = http.request{
41+
url = url,
42+
method = 'HEAD',
43+
}
44+
if not body or status_code ~= 200 then
45+
self.err = status_line
46+
return false
47+
end
48+
if resp_headers["accept-ranges"] ~= "bytes" then
49+
self.err = "server does not support range requests!"
50+
return false
51+
end
52+
ranges = merge_ranges(ranges)
53+
local ranges_index = 1
54+
repeat
55+
body, status_code, resp_headers, status_line = http.request{
56+
url = url,
57+
headers = { ["Range"] = string.format("bytes=%u-%u", ranges[ranges_index][1], ranges[ranges_index][2]) },
58+
sink = sink,
59+
}
60+
if not body then
61+
self.err = status_code
62+
return false
63+
end
64+
ok = status_code == 206
65+
if not ok then
66+
self.err = status_line
67+
return false
68+
end
69+
ranges_index = ranges_index + 1
70+
until ranges_index > #ranges
71+
else
72+
body, status_code, resp_headers, status_line = http.request{
73+
url = url,
74+
headers = etag and { ["If-None-Match"] = etag },
75+
sink = sink,
76+
}
77+
if not body then
78+
self.err = status_code
79+
return false
80+
end
81+
self.etag = resp_headers['etag']
82+
ok = status_code == 200 or status_code == 304
83+
if not ok then
84+
self.err = status_line
85+
end
86+
end
87+
self.status_code = status_code
88+
return ok
89+
end
90+
91+
return Downloader

0 commit comments

Comments
 (0)