summaryrefslogtreecommitdiffhomepage
path: root/libs/httpclient/luasrc
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2014-12-03 15:17:05 +0100
committerJo-Philipp Wich <jow@openwrt.org>2015-01-08 16:26:20 +0100
commit1bb4822dca6113f73e3bc89e2acf15935e6f8e92 (patch)
tree35e16f100466e4e00657199b38bb3d87d52bf73f /libs/httpclient/luasrc
parent9edd0e46c3f880727738ce8ca6ff1c8b85f99ef4 (diff)
Rework LuCI build system
* Rename subdirectories to their repective OpenWrt package names * Make each LuCI module its own standalone package * Deploy a shared luci.mk which is used by each module Makefile Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
Diffstat (limited to 'libs/httpclient/luasrc')
-rw-r--r--libs/httpclient/luasrc/httpclient.lua369
-rw-r--r--libs/httpclient/luasrc/httpclient/receiver.lua295
2 files changed, 0 insertions, 664 deletions
diff --git a/libs/httpclient/luasrc/httpclient.lua b/libs/httpclient/luasrc/httpclient.lua
deleted file mode 100644
index e9fec5dbb..000000000
--- a/libs/httpclient/luasrc/httpclient.lua
+++ /dev/null
@@ -1,369 +0,0 @@
---[[
-LuCI - Lua Development Framework
-
-Copyright 2009 Steven Barth <steven@midlink.org>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-$Id$
-]]--
-
-require "nixio.util"
-local nixio = require "nixio"
-
-local ltn12 = require "luci.ltn12"
-local util = require "luci.util"
-local table = require "table"
-local http = require "luci.http.protocol"
-local date = require "luci.http.protocol.date"
-
-local type, pairs, ipairs, tonumber = type, pairs, ipairs, tonumber
-local unpack = unpack
-
-module "luci.httpclient"
-
-function chunksource(sock, buffer)
- buffer = buffer or ""
- return function()
- local output
- local _, endp, count = buffer:find("^([0-9a-fA-F]+);?.-\r\n")
- while not count and #buffer <= 1024 do
- local newblock, code = sock:recv(1024 - #buffer)
- if not newblock then
- return nil, code
- end
- buffer = buffer .. newblock
- _, endp, count = buffer:find("^([0-9a-fA-F]+);?.-\r\n")
- end
- count = tonumber(count, 16)
- if not count then
- return nil, -1, "invalid encoding"
- elseif count == 0 then
- return nil
- elseif count + 2 <= #buffer - endp then
- output = buffer:sub(endp+1, endp+count)
- buffer = buffer:sub(endp+count+3)
- return output
- else
- output = buffer:sub(endp+1, endp+count)
- buffer = ""
- if count - #output > 0 then
- local remain, code = sock:recvall(count-#output)
- if not remain then
- return nil, code
- end
- output = output .. remain
- count, code = sock:recvall(2)
- else
- count, code = sock:recvall(count+2-#buffer+endp)
- end
- if not count then
- return nil, code
- end
- return output
- end
- end
-end
-
-
-function request_to_buffer(uri, options)
- local source, code, msg = request_to_source(uri, options)
- local output = {}
-
- if not source then
- return nil, code, msg
- end
-
- source, code = ltn12.pump.all(source, (ltn12.sink.table(output)))
-
- if not source then
- return nil, code
- end
-
- return table.concat(output)
-end
-
-function request_to_source(uri, options)
- local status, response, buffer, sock = request_raw(uri, options)
- if not status then
- return status, response, buffer
- elseif status ~= 200 and status ~= 206 then
- return nil, status, buffer
- end
-
- if response.headers["Transfer-Encoding"] == "chunked" then
- return chunksource(sock, buffer)
- else
- return ltn12.source.cat(ltn12.source.string(buffer), sock:blocksource())
- end
-end
-
---
--- GET HTTP-resource
---
-function request_raw(uri, options)
- options = options or {}
- local pr, auth, host, port, path
-
- if uri:find("%[") then
- if uri:find("@") then
- pr, auth, host, port, path = uri:match("(%w+)://(.+)@(%b[]):?([0-9]*)(.*)")
- host = host:sub(2,-2)
- else
- pr, host, port, path = uri:match("(%w+)://(%b[]):?([0-9]*)(.*)")
- host = host:sub(2,-2)
- end
- else
- if uri:find("@") then
- pr, auth, host, port, path =
- uri:match("(%w+)://(.+)@([%w-.]+):?([0-9]*)(.*)")
- else
- pr, host, port, path = uri:match("(%w+)://([%w-.]+):?([0-9]*)(.*)")
- end
- end
-
- if not host then
- return nil, -1, "unable to parse URI"
- end
-
- if pr ~= "http" and pr ~= "https" then
- return nil, -2, "protocol not supported"
- end
-
- port = #port > 0 and port or (pr == "https" and 443 or 80)
- path = #path > 0 and path or "/"
-
- options.depth = options.depth or 10
- local headers = options.headers or {}
- local protocol = options.protocol or "HTTP/1.1"
- headers["User-Agent"] = headers["User-Agent"] or "LuCI httpclient 0.1"
-
- if headers.Connection == nil then
- headers.Connection = "close"
- end
-
- if auth and not headers.Authorization then
- headers.Authorization = "Basic " .. nixio.bin.b64encode(auth)
- end
-
- local sock, code, msg = nixio.connect(host, port)
- if not sock then
- return nil, code, msg
- end
-
- sock:setsockopt("socket", "sndtimeo", options.sndtimeo or 15)
- sock:setsockopt("socket", "rcvtimeo", options.rcvtimeo or 15)
-
- if pr == "https" then
- local tls = options.tls_context or nixio.tls()
- sock = tls:create(sock)
- local stat, code, error = sock:connect()
- if not stat then
- return stat, code, error
- end
- end
-
- -- Pre assemble fixes
- if protocol == "HTTP/1.1" then
- headers.Host = headers.Host or host
- end
-
- if type(options.body) == "table" then
- options.body = http.urlencode_params(options.body)
- end
-
- if type(options.body) == "string" then
- headers["Content-Length"] = headers["Content-Length"] or #options.body
- headers["Content-Type"] = headers["Content-Type"] or
- "application/x-www-form-urlencoded"
- options.method = options.method or "POST"
- end
-
- if type(options.body) == "function" then
- options.method = options.method or "POST"
- end
-
- -- Assemble message
- local message = {(options.method or "GET") .. " " .. path .. " " .. protocol}
-
- for k, v in pairs(headers) do
- if type(v) == "string" or type(v) == "number" then
- message[#message+1] = k .. ": " .. v
- elseif type(v) == "table" then
- for i, j in ipairs(v) do
- message[#message+1] = k .. ": " .. j
- end
- end
- end
-
- if options.cookies then
- for _, c in ipairs(options.cookies) do
- local cdo = c.flags.domain
- local cpa = c.flags.path
- if (cdo == host or cdo == "."..host or host:sub(-#cdo) == cdo)
- and (cpa == path or cpa == "/" or cpa .. "/" == path:sub(#cpa+1))
- and (not c.flags.secure or pr == "https")
- then
- message[#message+1] = "Cookie: " .. c.key .. "=" .. c.value
- end
- end
- end
-
- message[#message+1] = ""
- message[#message+1] = ""
-
- -- Send request
- sock:sendall(table.concat(message, "\r\n"))
-
- if type(options.body) == "string" then
- sock:sendall(options.body)
- elseif type(options.body) == "function" then
- local res = {options.body(sock)}
- if not res[1] then
- sock:close()
- return unpack(res)
- end
- end
-
- -- Create source and fetch response
- local linesrc = sock:linesource()
- local line, code, error = linesrc()
-
- if not line then
- sock:close()
- return nil, code, error
- end
-
- local protocol, status, msg = line:match("^([%w./]+) ([0-9]+) (.*)")
-
- if not protocol then
- sock:close()
- return nil, -3, "invalid response magic: " .. line
- end
-
- local response = {
- status = line, headers = {}, code = 0, cookies = {}, uri = uri
- }
-
- line = linesrc()
- while line and line ~= "" do
- local key, val = line:match("^([%w-]+)%s?:%s?(.*)")
- if key and key ~= "Status" then
- if type(response.headers[key]) == "string" then
- response.headers[key] = {response.headers[key], val}
- elseif type(response.headers[key]) == "table" then
- response.headers[key][#response.headers[key]+1] = val
- else
- response.headers[key] = val
- end
- end
- line = linesrc()
- end
-
- if not line then
- sock:close()
- return nil, -4, "protocol error"
- end
-
- -- Parse cookies
- if response.headers["Set-Cookie"] then
- local cookies = response.headers["Set-Cookie"]
- for _, c in ipairs(type(cookies) == "table" and cookies or {cookies}) do
- local cobj = cookie_parse(c)
- cobj.flags.path = cobj.flags.path or path:match("(/.*)/?[^/]*")
- if not cobj.flags.domain or cobj.flags.domain == "" then
- cobj.flags.domain = host
- response.cookies[#response.cookies+1] = cobj
- else
- local hprt, cprt = {}, {}
-
- -- Split hostnames and save them in reverse order
- for part in host:gmatch("[^.]*") do
- table.insert(hprt, 1, part)
- end
- for part in cobj.flags.domain:gmatch("[^.]*") do
- table.insert(cprt, 1, part)
- end
-
- local valid = true
- for i, part in ipairs(cprt) do
- -- If parts are different and no wildcard
- if hprt[i] ~= part and #part ~= 0 then
- valid = false
- break
- -- Wildcard on invalid position
- elseif hprt[i] ~= part and #part == 0 then
- if i ~= #cprt or (#hprt ~= i and #hprt+1 ~= i) then
- valid = false
- break
- end
- end
- end
- -- No TLD cookies
- if valid and #cprt > 1 and #cprt[2] > 0 then
- response.cookies[#response.cookies+1] = cobj
- end
- end
- end
- end
-
- -- Follow
- response.code = tonumber(status)
- if response.code and options.depth > 0 then
- if (response.code == 301 or response.code == 302 or response.code == 307)
- and response.headers.Location then
- local nuri = response.headers.Location or response.headers.location
- if not nuri then
- return nil, -5, "invalid reference"
- end
- if not nuri:find("https?://") then
- nuri = pr .. "://" .. host .. ":" .. port .. nuri
- end
-
- options.depth = options.depth - 1
- if options.headers then
- options.headers.Host = nil
- end
- sock:close()
-
- return request_raw(nuri, options)
- end
- end
-
- return response.code, response, linesrc(true), sock
-end
-
-function cookie_parse(cookiestr)
- local key, val, flags = cookiestr:match("%s?([^=;]+)=?([^;]*)(.*)")
- if not key then
- return nil
- end
-
- local cookie = {key = key, value = val, flags = {}}
- for fkey, fval in flags:gmatch(";%s?([^=;]+)=?([^;]*)") do
- fkey = fkey:lower()
- if fkey == "expires" then
- fval = date.to_unix(fval:gsub("%-", " "))
- end
- cookie.flags[fkey] = fval
- end
-
- return cookie
-end
-
-function cookie_create(cookie)
- local cookiedata = {cookie.key .. "=" .. cookie.value}
-
- for k, v in pairs(cookie.flags) do
- if k == "expires" then
- v = date.to_http(v):gsub(", (%w+) (%w+) (%w+) ", ", %1-%2-%3 ")
- end
- cookiedata[#cookiedata+1] = k .. ((#v > 0) and ("=" .. v) or "")
- end
-
- return table.concat(cookiedata, "; ")
-end
diff --git a/libs/httpclient/luasrc/httpclient/receiver.lua b/libs/httpclient/luasrc/httpclient/receiver.lua
deleted file mode 100644
index 4f08e93fe..000000000
--- a/libs/httpclient/luasrc/httpclient/receiver.lua
+++ /dev/null
@@ -1,295 +0,0 @@
---[[
-LuCI - Lua Development Framework
-
-Copyright 2009 Steven Barth <steven@midlink.org>
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-$Id$
-]]--
-
-require "nixio.util"
-local nixio = require "nixio"
-local httpc = require "luci.httpclient"
-local ltn12 = require "luci.ltn12"
-
-local print, tonumber, require, unpack = print, tonumber, require, unpack
-
-module "luci.httpclient.receiver"
-
-local function prepare_fd(target)
- -- Open fd for appending
- local oflags = nixio.open_flags("wronly", "creat")
- local file, code, msg = nixio.open(target, oflags)
- if not file then
- return file, code, msg
- end
-
- -- Acquire lock
- local stat, code, msg = file:lock("tlock")
- if not stat then
- return stat, code, msg
- end
-
- file:seek(0, "end")
-
- return file
-end
-
-local function splice_async(sock, pipeout, pipein, file, cb)
- local ssize = 65536
- local smode = nixio.splice_flags("move", "more", "nonblock")
-
- -- Set pipe non-blocking otherwise we might end in a deadlock
- local stat, code, msg = pipein:setblocking(false)
- if stat then
- stat, code, msg = pipeout:setblocking(false)
- end
- if not stat then
- return stat, code, msg
- end
-
-
- local pollsock = {
- {fd=sock, events=nixio.poll_flags("in")}
- }
-
- local pollfile = {
- {fd=file, events=nixio.poll_flags("out")}
- }
-
- local done
- local active -- Older splice implementations sometimes don't detect EOS
-
- repeat
- active = false
-
- -- Socket -> Pipe
- repeat
- nixio.poll(pollsock, 15000)
-
- stat, code, msg = nixio.splice(sock, pipeout, ssize, smode)
- if stat == nil then
- return stat, code, msg
- elseif stat == 0 then
- done = true
- break
- elseif stat then
- active = true
- end
- until stat == false
-
- -- Pipe -> File
- repeat
- nixio.poll(pollfile, 15000)
-
- stat, code, msg = nixio.splice(pipein, file, ssize, smode)
- if stat == nil then
- return stat, code, msg
- elseif stat then
- active = true
- end
- until stat == false
-
- if cb then
- cb(file)
- end
-
- if not active then
- -- We did not splice any data, maybe EOS, fallback to default
- return false
- end
- until done
-
- pipein:close()
- pipeout:close()
- sock:close()
- file:close()
- return true
-end
-
-local function splice_sync(sock, pipeout, pipein, file, cb)
- local os = require "os"
- local ssize = 65536
- local smode = nixio.splice_flags("move", "more")
- local stat
-
- -- This is probably the only forking http-client ;-)
- local pid, code, msg = nixio.fork()
- if not pid then
- return pid, code, msg
- elseif pid == 0 then
- pipein:close()
- file:close()
-
- repeat
- stat, code = nixio.splice(sock, pipeout, ssize, smode)
- until not stat or stat == 0
-
- pipeout:close()
- sock:close()
- os.exit(stat or code)
- else
- pipeout:close()
- sock:close()
-
- repeat
- stat, code, msg = nixio.splice(pipein, file, ssize, smode)
- if cb then
- cb(file)
- end
- until not stat or stat == 0
-
- pipein:close()
- file:close()
-
- if not stat then
- nixio.kill(pid, 15)
- nixio.wait(pid)
- return stat, code, msg
- else
- pid, msg, code = nixio.wait(pid)
- if msg == "exited" then
- if code == 0 then
- return true
- else
- return nil, code, nixio.strerror(code)
- end
- else
- return nil, -0x11, "broken pump"
- end
- end
- end
-end
-
-function request_to_file(uri, target, options, cbs)
- options = options or {}
- cbs = cbs or {}
- options.headers = options.headers or {}
- local hdr = options.headers
- local file, code, msg
-
- if target then
- file, code, msg = prepare_fd(target)
- if not file then
- return file, code, msg
- end
-
- local off = file:tell()
-
- -- Set content range
- if off > 0 then
- hdr.Range = hdr.Range or ("bytes=" .. off .. "-")
- end
- end
-
- local code, resp, buffer, sock = httpc.request_raw(uri, options)
- if not code then
- -- No success
- if file then
- file:close()
- end
- return code, resp, buffer
- elseif hdr.Range and code ~= 206 then
- -- We wanted a part but we got the while file
- sock:close()
- if file then
- file:close()
- end
- return nil, -4, code, resp
- elseif not hdr.Range and code ~= 200 then
- -- We encountered an error
- sock:close()
- if file then
- file:close()
- end
- return nil, -4, code, resp
- end
-
- if cbs.on_header then
- local stat = {cbs.on_header(file, code, resp)}
- if stat[1] == false then
- if file then
- file:close()
- end
- sock:close()
- return unpack(stat)
- elseif stat[2] then
- file = file and stat[2]
- end
- end
-
- if not file then
- return nil, -5, "no target given"
- end
-
- local chunked = resp.headers["Transfer-Encoding"] == "chunked"
- local stat
-
- -- Write the buffer to file
- file:writeall(buffer)
-
- repeat
- if not options.splice or not sock:is_socket() or chunked then
- break
- end
-
- -- This is a plain TCP socket and there is no encoding so we can splice
-
- local pipein, pipeout, msg = nixio.pipe()
- if not pipein then
- sock:close()
- file:close()
- return pipein, pipeout, msg
- end
-
-
- -- Adjust splice values
- local ssize = 65536
- local smode = nixio.splice_flags("move", "more")
-
- -- Splicing 512 bytes should never block on a fresh pipe
- local stat, code, msg = nixio.splice(sock, pipeout, 512, smode)
- if stat == nil then
- break
- end
-
- -- Now do the real splicing
- local cb = cbs.on_write
- if options.splice == "asynchronous" then
- stat, code, msg = splice_async(sock, pipeout, pipein, file, cb)
- elseif options.splice == "synchronous" then
- stat, code, msg = splice_sync(sock, pipeout, pipein, file, cb)
- else
- break
- end
-
- if stat == false then
- break
- end
-
- return stat, code, msg
- until true
-
- local src = chunked and httpc.chunksource(sock) or sock:blocksource()
- local snk = file:sink()
-
- if cbs.on_write then
- src = ltn12.source.chain(src, function(chunk)
- cbs.on_write(file)
- return chunk
- end)
- end
-
- -- Fallback to read/write
- stat, code, msg = ltn12.pump.all(src, snk)
-
- file:close()
- sock:close()
- return stat and true, code, msg
-end
-