From 383f84fa0535a2aef958b2ece7c1ba0cd973b524 Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Tue, 5 Feb 2013 20:50:50 +0100 Subject: http.client: added --- Makefile.in | 1 + lem/http/client.lua | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test/download.lua | 50 ++++++++++++++++++++ test/httptest.lua | 24 ++++------ 4 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 lem/http/client.lua create mode 100755 test/download.lua diff --git a/Makefile.in b/Makefile.in index f4b58e2..d6b3a9b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,6 +28,7 @@ llibs = \ lem/io/queue.lua \ lem/lfs.lua \ lem/http.lua \ + lem/http/client.lua \ lem/http/server.lua \ lem/queue.lua \ lem/hathaway.lua diff --git a/lem/http/client.lua b/lem/http/client.lua new file mode 100644 index 0000000..04b9de6 --- /dev/null +++ b/lem/http/client.lua @@ -0,0 +1,128 @@ +-- +-- This file is part of LEM, a Lua Event Machine. +-- Copyright 2013 Emil Renner Berthing +-- +-- LEM is free software: you can redistribute it and/or modify it +-- under the terms of the GNU Lesser General Public License as +-- published by the Free Software Foundation, either version 3 of +-- the License, or (at your option) any later version. +-- +-- LEM is distributed in the hope that it will be useful, but +-- WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with LEM. If not, see . +-- + +local io = require 'lem.io' +require 'lem.http' + +local client = {} + +local Client = {} +Client.__index = Client +client.Client = Client + +function client.new() + return setmetatable({ + proto = false, + domain = false, + conn = false, + }, Client) +end + +local req_get = "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n\r\n" +--local req_get = "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" + +local function close(self) + local c = self.conn + if c then + self.conn = false + return c:close() + end + return true +end +Client.close = close + +local function fail(self, err) + self.proto = false + close(self) + return nil, err +end + +function Client:get(url) + local proto, domain, uri = url:match('([a-zA-Z0-9]+)://([a-zA-Z0-9.]+)(/.*)') + if not proto then + error('Invalid URL', 2) + end + + local c, err + local req = req_get:format(uri, domain) + local res + if proto == self.proto and domain == self.domain then + c = self.conn + if c:write(req) then + res = c:read('HTTPResponse') + end + end + + if not res then + c = self.conn + if c then + c:close() + end + + if proto == 'http' then + c, err = io.tcp.connect(domain, '80') + elseif proto == 'https' then + local ssl = self.ssl + if not ssl then + error('No ssl context defined', 2) + end + c, err = ssl:connect(domain, '443') + else + error('Unknown protocol', 2) + end + if not c then return fail(self, err) end + + local ok + ok, err = c:write(req) + if not ok then return fail(self, err) end + + res, err = c:read('HTTPResponse') + if not res then return fail(self, err) end + end + + local body + body, err = res:body() + if not body then return fail(self, err) end + + self.proto = proto + self.domain = domain + self.conn = c + res.body = body + return res +end + +function Client:download(url, filename) + local res, err = self:get(url) + if not res then return res, err end + + local file + file, err = io.open(filename, 'w') + if not file then return file, err end + + local ok + ok, err = file:write(res.body) + if not ok then return ok, err end + ok, err = file:close() + if not ok then return ok, err end + + return true +end + +return client + +-- vim: set ts=2 sw=2 noet: diff --git a/test/download.lua b/test/download.lua new file mode 100755 index 0000000..10b38d9 --- /dev/null +++ b/test/download.lua @@ -0,0 +1,50 @@ +#!bin/lem +-- +-- This file is part of LEM, a Lua Event Machine. +-- Copyright 2013 Emil Renner Berthing +-- +-- LEM is free software: you can redistribute it and/or modify it +-- under the terms of the GNU Lesser General Public License as +-- published by the Free Software Foundation, either version 3 of +-- the License, or (at your option) any later version. +-- +-- LEM is distributed in the hope that it will be useful, but +-- WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Lesser General Public License for more details. +-- +-- You should have received a copy of the GNU Lesser General Public +-- License along with LEM. If not, see . +-- + +package.path = '?.lua' +package.cpath = '?.so' + +local utils = require 'lem.utils' +local io = require 'lem.io' +local client = require 'lem.http.client' + +local write, format = io.write, string.format +local function printf(...) + return write(format(...)) +end + +local url = arg[1] or 'http://ompldr.org/vODFnOA/Birgit%20Lystager%20-%20Birger.mp3' +local filename = arg[2] or 'birger.mp3' +local stop = false + +utils.spawn(function() + local c = client.new() + + assert(c:download(url, filename)) + assert(c:close()) + stop = true +end) + +local sleeper = utils.newsleeper() +repeat + write('.') + sleeper:sleep(0.001) +until stop + +-- vim: set ts=2 sw=2 noet: diff --git a/test/httptest.lua b/test/httptest.lua index 7e38533..bce4cff 100755 --- a/test/httptest.lua +++ b/test/httptest.lua @@ -20,41 +20,33 @@ package.path = '?.lua' package.cpath = '?.so' -local utils = require 'lem.utils' -local io = require 'lem.io' -local http = require 'lem.http' +local utils = require 'lem.utils' +local io = require 'lem.io' +local client = require 'lem.http.client' local write, format = io.write, string.format local function printf(...) return write(format(...)) end -local domain, port = arg[1] or 'www.google.com', 'http' +local url = arg[1] or 'http://www.google.com/' local running = 0 local function get(n, close) running = running + 1 - local req - if close then - req = 'GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n' - else - req = 'GET / HTTP/1.1\r\nHost: %s\r\n\r\n' - end + local c = client.new() - local conn = assert(io.tcp.connect(domain, port)) - assert(conn:write(req:format(domain))) - local res = assert(conn:read('HTTPResponse')) + local res = assert(c:get(url)) printf('\n%d: HTTP/%s %d %s\n', n, res.version, res.status, res.text) for k, v in pairs(res.headers) do printf('%d: %s: %s\n', n, k, v) end - local body = assert(res:body()) - printf('\n%d: #body = %d\n', n, #body) + printf('\n%d: #body = %d\n', n, #res.body) - conn:close() + assert(c:close()) running = running - 1 end -- cgit v1.2.1