diff options
| author | Diego Nehab <diego@impa.br> | 2016-03-07 01:30:30 -0300 |
|---|---|---|
| committer | Diego Nehab <diego@impa.br> | 2016-03-07 01:30:30 -0300 |
| commit | 916b548240b1513410b13f964d80f329aec9c13a (patch) | |
| tree | dee1cfd05ca7ad72a3db2673fbc7ce005098bb2a /src | |
| parent | 5b4b9158799293eeaf8439d40a7845b5b0a5e125 (diff) | |
| download | luasocket-916b548240b1513410b13f964d80f329aec9c13a.tar.gz luasocket-916b548240b1513410b13f964d80f329aec9c13a.tar.bz2 luasocket-916b548240b1513410b13f964d80f329aec9c13a.zip | |
Family agostic FTP and expose HTTP/FTP url parsing
Diffstat (limited to 'src')
| -rw-r--r-- | src/ftp.lua | 67 | ||||
| -rw-r--r-- | src/http.lua | 17 | ||||
| -rw-r--r-- | src/tp.lua | 10 |
3 files changed, 73 insertions, 21 deletions
diff --git a/src/ftp.lua b/src/ftp.lua index e0c3cae..11798ad 100644 --- a/src/ftp.lua +++ b/src/ftp.lua | |||
| @@ -51,7 +51,7 @@ end | |||
| 51 | function metat.__index:pasvconnect() | 51 | function metat.__index:pasvconnect() |
| 52 | self.data = self.try(socket.tcp()) | 52 | self.data = self.try(socket.tcp()) |
| 53 | self.try(self.data:settimeout(_M.TIMEOUT)) | 53 | self.try(self.data:settimeout(_M.TIMEOUT)) |
| 54 | self.try(self.data:connect(self.pasvt.ip, self.pasvt.port)) | 54 | self.try(self.data:connect(self.pasvt.address, self.pasvt.port)) |
| 55 | end | 55 | end |
| 56 | 56 | ||
| 57 | function metat.__index:login(user, password) | 57 | function metat.__index:login(user, password) |
| @@ -71,32 +71,65 @@ function metat.__index:pasv() | |||
| 71 | local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) | 71 | local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) |
| 72 | self.try(a and b and c and d and p1 and p2, reply) | 72 | self.try(a and b and c and d and p1 and p2, reply) |
| 73 | self.pasvt = { | 73 | self.pasvt = { |
| 74 | ip = string.format("%d.%d.%d.%d", a, b, c, d), | 74 | address = string.format("%d.%d.%d.%d", a, b, c, d), |
| 75 | port = p1*256 + p2 | 75 | port = p1*256 + p2 |
| 76 | } | 76 | } |
| 77 | if self.server then | 77 | if self.server then |
| 78 | self.server:close() | 78 | self.server:close() |
| 79 | self.server = nil | 79 | self.server = nil |
| 80 | end | 80 | end |
| 81 | return self.pasvt.ip, self.pasvt.port | 81 | return self.pasvt.address, self.pasvt.port |
| 82 | end | 82 | end |
| 83 | 83 | ||
| 84 | function metat.__index:port(ip, port) | 84 | function metat.__index:epsv() |
| 85 | self.try(self.tp:command("epsv")) | ||
| 86 | local code, reply = self.try(self.tp:check("229")) | ||
| 87 | local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)" | ||
| 88 | local d, prt, address, port = string.match(reply, pattern) | ||
| 89 | self.try(port, "invalid epsv response") | ||
| 90 | self.pasvt = { | ||
| 91 | address = self.tp:getpeername(), | ||
| 92 | port = port | ||
| 93 | } | ||
| 94 | if self.server then | ||
| 95 | self.server:close() | ||
| 96 | self.server = nil | ||
| 97 | end | ||
| 98 | return self.pasvt.address, self.pasvt.port | ||
| 99 | end | ||
| 100 | |||
| 101 | |||
| 102 | function metat.__index:port(address, port) | ||
| 85 | self.pasvt = nil | 103 | self.pasvt = nil |
| 86 | if not ip then | 104 | if not address then |
| 87 | ip, port = self.try(self.tp:getcontrol():getsockname()) | 105 | address, port = self.try(self.tp:getsockname()) |
| 88 | self.server = self.try(socket.bind(ip, 0)) | 106 | self.server = self.try(socket.bind(address, 0)) |
| 89 | ip, port = self.try(self.server:getsockname()) | 107 | address, port = self.try(self.server:getsockname()) |
| 90 | self.try(self.server:settimeout(_M.TIMEOUT)) | 108 | self.try(self.server:settimeout(_M.TIMEOUT)) |
| 91 | end | 109 | end |
| 92 | local pl = math.mod(port, 256) | 110 | local pl = math.mod(port, 256) |
| 93 | local ph = (port - pl)/256 | 111 | local ph = (port - pl)/256 |
| 94 | local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",") | 112 | local arg = string.gsub(string.format("%s,%d,%d", address, ph, pl), "%.", ",") |
| 95 | self.try(self.tp:command("port", arg)) | 113 | self.try(self.tp:command("port", arg)) |
| 96 | self.try(self.tp:check("2..")) | 114 | self.try(self.tp:check("2..")) |
| 97 | return 1 | 115 | return 1 |
| 98 | end | 116 | end |
| 99 | 117 | ||
| 118 | function metat.__index:eprt(family, address, port) | ||
| 119 | self.pasvt = nil | ||
| 120 | if not address then | ||
| 121 | address, port = self.try(self.tp:getsockname()) | ||
| 122 | self.server = self.try(socket.bind(address, 0)) | ||
| 123 | address, port = self.try(self.server:getsockname()) | ||
| 124 | self.try(self.server:settimeout(_M.TIMEOUT)) | ||
| 125 | end | ||
| 126 | local arg = string.format("|%s|%s|%d|", family, address, port) | ||
| 127 | self.try(self.tp:command("eprt", arg)) | ||
| 128 | self.try(self.tp:check("2..")) | ||
| 129 | return 1 | ||
| 130 | end | ||
| 131 | |||
| 132 | |||
| 100 | function metat.__index:send(sendt) | 133 | function metat.__index:send(sendt) |
| 101 | self.try(self.pasvt or self.server, "need port or pasv first") | 134 | self.try(self.pasvt or self.server, "need port or pasv first") |
| 102 | -- if there is a pasvt table, we already sent a PASV command | 135 | -- if there is a pasvt table, we already sent a PASV command |
| @@ -110,12 +143,12 @@ function metat.__index:send(sendt) | |||
| 110 | -- send the transfer command and check the reply | 143 | -- send the transfer command and check the reply |
| 111 | self.try(self.tp:command(command, argument)) | 144 | self.try(self.tp:command(command, argument)) |
| 112 | local code, reply = self.try(self.tp:check{"2..", "1.."}) | 145 | local code, reply = self.try(self.tp:check{"2..", "1.."}) |
| 113 | -- if there is not a a pasvt table, then there is a server | 146 | -- if there is not a pasvt table, then there is a server |
| 114 | -- and we already sent a PORT command | 147 | -- and we already sent a PORT command |
| 115 | if not self.pasvt then self:portconnect() end | 148 | if not self.pasvt then self:portconnect() end |
| 116 | -- get the sink, source and step for the transfer | 149 | -- get the sink, source and step for the transfer |
| 117 | local step = sendt.step or ltn12.pump.step | 150 | local step = sendt.step or ltn12.pump.step |
| 118 | local readt = {self.tp.c} | 151 | local readt = { self.tp } |
| 119 | local checkstep = function(src, snk) | 152 | local checkstep = function(src, snk) |
| 120 | -- check status in control connection while downloading | 153 | -- check status in control connection while downloading |
| 121 | local readyt = socket.select(readt, nil, 0) | 154 | local readyt = socket.select(readt, nil, 0) |
| @@ -207,7 +240,7 @@ local function tput(putt) | |||
| 207 | f:greet() | 240 | f:greet() |
| 208 | f:login(putt.user, putt.password) | 241 | f:login(putt.user, putt.password) |
| 209 | if putt.type then f:type(putt.type) end | 242 | if putt.type then f:type(putt.type) end |
| 210 | f:pasv() | 243 | f:epsv() |
| 211 | local sent = f:send(putt) | 244 | local sent = f:send(putt) |
| 212 | f:quit() | 245 | f:quit() |
| 213 | f:close() | 246 | f:close() |
| @@ -219,7 +252,7 @@ local default = { | |||
| 219 | scheme = "ftp" | 252 | scheme = "ftp" |
| 220 | } | 253 | } |
| 221 | 254 | ||
| 222 | local function parse(u) | 255 | local function genericform(u) |
| 223 | local t = socket.try(url.parse(u, default)) | 256 | local t = socket.try(url.parse(u, default)) |
| 224 | socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") | 257 | socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") |
| 225 | socket.try(t.host, "missing hostname") | 258 | socket.try(t.host, "missing hostname") |
| @@ -232,8 +265,10 @@ local function parse(u) | |||
| 232 | return t | 265 | return t |
| 233 | end | 266 | end |
| 234 | 267 | ||
| 268 | _M.genericform = genericform | ||
| 269 | |||
| 235 | local function sput(u, body) | 270 | local function sput(u, body) |
| 236 | local putt = parse(u) | 271 | local putt = genericform(u) |
| 237 | putt.source = ltn12.source.string(body) | 272 | putt.source = ltn12.source.string(body) |
| 238 | return tput(putt) | 273 | return tput(putt) |
| 239 | end | 274 | end |
| @@ -250,14 +285,14 @@ local function tget(gett) | |||
| 250 | f:greet() | 285 | f:greet() |
| 251 | f:login(gett.user, gett.password) | 286 | f:login(gett.user, gett.password) |
| 252 | if gett.type then f:type(gett.type) end | 287 | if gett.type then f:type(gett.type) end |
| 253 | f:pasv() | 288 | f:epsv() |
| 254 | f:receive(gett) | 289 | f:receive(gett) |
| 255 | f:quit() | 290 | f:quit() |
| 256 | return f:close() | 291 | return f:close() |
| 257 | end | 292 | end |
| 258 | 293 | ||
| 259 | local function sget(u) | 294 | local function sget(u) |
| 260 | local gett = parse(u) | 295 | local gett = genericform(u) |
| 261 | local t = {} | 296 | local t = {} |
| 262 | gett.sink = ltn12.sink.table(t) | 297 | gett.sink = ltn12.sink.table(t) |
| 263 | tget(gett) | 298 | tget(gett) |
diff --git a/src/http.lua b/src/http.lua index d6bcc91..f2fff01 100644 --- a/src/http.lua +++ b/src/http.lua | |||
| @@ -346,11 +346,13 @@ end | |||
| 346 | return 1, code, headers, status | 346 | return 1, code, headers, status |
| 347 | end | 347 | end |
| 348 | 348 | ||
| 349 | local function srequest(u, b) | 349 | -- turns an url and a body into a generic request |
| 350 | local function genericform(u, b) | ||
| 350 | local t = {} | 351 | local t = {} |
| 351 | local reqt = { | 352 | local reqt = { |
| 352 | url = u, | 353 | url = u, |
| 353 | sink = ltn12.sink.table(t) | 354 | sink = ltn12.sink.table(t), |
| 355 | target = t | ||
| 354 | } | 356 | } |
| 355 | if b then | 357 | if b then |
| 356 | reqt.source = ltn12.source.string(b) | 358 | reqt.source = ltn12.source.string(b) |
| @@ -360,8 +362,15 @@ local function srequest(u, b) | |||
| 360 | } | 362 | } |
| 361 | reqt.method = "POST" | 363 | reqt.method = "POST" |
| 362 | end | 364 | end |
| 363 | local code, headers, status = socket.skip(1, trequest(reqt)) | 365 | return reqt |
| 364 | return table.concat(t), code, headers, status | 366 | end |
| 367 | |||
| 368 | _M.genericform = genericform | ||
| 369 | |||
| 370 | local function srequest(u, b) | ||
| 371 | local reqt = genericform(u, b) | ||
| 372 | local _, code, headers, status = trequest(reqt) | ||
| 373 | return table.concat(reqt.target), code, headers, status | ||
| 365 | end | 374 | end |
| 366 | 375 | ||
| 367 | _M.request = socket.protect(function(reqt, body) | 376 | _M.request = socket.protect(function(reqt, body) |
| @@ -46,6 +46,14 @@ end | |||
| 46 | -- metatable for sock object | 46 | -- metatable for sock object |
| 47 | local metat = { __index = {} } | 47 | local metat = { __index = {} } |
| 48 | 48 | ||
| 49 | function metat.__index:getpeername() | ||
| 50 | return self.c:getpeername() | ||
| 51 | end | ||
| 52 | |||
| 53 | function metat.__index:getsockname() | ||
| 54 | return self.c:getpeername() | ||
| 55 | end | ||
| 56 | |||
| 49 | function metat.__index:check(ok) | 57 | function metat.__index:check(ok) |
| 50 | local code, reply = get_reply(self.c) | 58 | local code, reply = get_reply(self.c) |
| 51 | if not code then return nil, reply end | 59 | if not code then return nil, reply end |
| @@ -123,4 +131,4 @@ function _M.connect(host, port, timeout, create) | |||
| 123 | return base.setmetatable({c = c}, metat) | 131 | return base.setmetatable({c = c}, metat) |
| 124 | end | 132 | end |
| 125 | 133 | ||
| 126 | return _M \ No newline at end of file | 134 | return _M |
