summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Renner Berthing <esmil@mailme.dk>2013-08-21 10:31:14 +0200
committerEmil Renner Berthing <esmil@mailme.dk>2013-08-21 22:25:43 +0200
commit8499b5bc97bff61e1c37902c9147ba362fff3e58 (patch)
tree694e333f05fd276b49dd2fd70eb1b8a2b1836bf7
parent2e3607ab70ca069da846f875d9eb3685f93a71f2 (diff)
downloadlem-8499b5bc97bff61e1c37902c9147ba362fff3e58.tar.gz
lem-8499b5bc97bff61e1c37902c9147ba362fff3e58.tar.xz
lem-8499b5bc97bff61e1c37902c9147ba362fff3e58.zip
http: move Request and Response objects out
..to http.server and http.client modules respectively, and don't tie them to the parser.
-rw-r--r--lem/http.lua85
-rw-r--r--lem/http/client.lua78
-rw-r--r--lem/http/core.c52
-rw-r--r--lem/http/server.lua25
-rwxr-xr-xtest/httptest.lua3
5 files changed, 115 insertions, 128 deletions
diff --git a/lem/http.lua b/lem/http.lua
index 1f972a9..c758430 100644
--- a/lem/http.lua
+++ b/lem/http.lua
@@ -16,86 +16,13 @@
-- License along with LEM. If not, see <http://www.gnu.org/licenses/>.
--
-local io = require 'lem.io'
-local http = require 'lem.http.core'
+local http = require 'lem.http.core'
+local parsers = require 'lem.parsers'
-do
- local parsers = require 'lem.parsers'
-
- parsers.lookup['HTTPRequest'] = http.HTTPRequest
- http.HTTPRequest = nil
- parsers.lookup['HTTPResponse'] = http.HTTPResponse
- http.HTTPResponse = nil
-end
-
-local tonumber = tonumber
-local concat = table.concat
-
-function http.Request:body()
- local len, body = self.headers['content-length'], ''
- if not len then return body end
-
- len = tonumber(len)
- if len <= 0 then return body end
-
- if self.headers['expect'] == '100-continue' then
- local ok, err = self.client:write('HTTP/1.1 100 Continue\r\n\r\n')
- if not ok then return nil, err end
- end
-
- local err
- body, err = self.client:read(len)
- if not body then return nil, err end
-
- return body
-end
-
-function http.Response:body_chunked()
- local client = self.client
- local t, n = {}, 0
- local line, err
- while true do
- line, err = client:read('*l')
- if not line then return nil, err end
-
- local num = tonumber(line, 16)
- if not num then return nil, 'expectation failed' end
- if num == 0 then break end
-
- local data, err = client:read(num)
- if not data then return nil, err end
-
- n = n + 1
- t[n] = data
-
- line, err = client:read('*l')
- if not line then return nil, err end
- end
-
- line, err = client:read('*l')
- if not line then return nil, err end
-
- return concat(t)
-end
-
-function http.Response:body()
- if self.headers['transfer-encoding'] == 'chunked' then
- return self:body_chunked()
- end
-
- local num = self.headers['content-length']
- if not num then
- if self.headers['connection'] == 'close' then
- return self.client:read('*a')
- end
- return nil, 'no content length specified'
- end
-
- num = tonumber(num)
- if not num then return nil, 'invalid content length' end
-
- return self.client:read(num)
-end
+parsers.lookup['HTTPRequest'] = http.HTTPRequest
+http.HTTPRequest = nil
+parsers.lookup['HTTPResponse'] = http.HTTPResponse
+http.HTTPResponse = nil
return http
diff --git a/lem/http/client.lua b/lem/http/client.lua
index 04b9de6..0e9631e 100644
--- a/lem/http/client.lua
+++ b/lem/http/client.lua
@@ -16,16 +16,80 @@
-- License along with LEM. If not, see <http://www.gnu.org/licenses/>.
--
+local setmetatable = setmetatable
+local tonumber = tonumber
+local concat = table.concat
+
local io = require 'lem.io'
require 'lem.http'
-local client = {}
+local M = {}
+
+local Response = {}
+Response.__index = Response
+M.Response = Response
+
+function Response:body_chunked()
+ if self._body then return self._body end
+
+ local conn = self.conn
+ local rope, i = {}, 0
+ local line, err
+ while true do
+ line, err = conn:read('*l')
+ if not line then return nil, err end
+
+ local len = tonumber(line, 16)
+ if not len then return nil, 'expectation failed' end
+ if len == 0 then break end
+
+ local data, err = conn:read(len)
+ if not data then return nil, err end
+
+ i = i + 1
+ rope[i] = data
+
+ line, err = conn:read('*l')
+ if not line then return nil, err end
+ end
+
+ line, err = conn:read('*l')
+ if not line then return nil, err end
+
+ rope = concat(rope)
+ self._body = rope
+ return rope
+end
+
+function Response:body()
+ if self._body then return self._body end
+ if self.headers['transfer-encoding'] == 'chunked' then
+ return self:body_chunked()
+ end
+
+ local len, body, err = self.headers['content-length']
+ if len then
+ len = tonumber(len)
+ if not len then return nil, 'invalid content length' end
+ body, err = self.conn:read(len)
+ else
+ if self.headers['connection'] == 'close' then
+ body, err = self.client:read('*a')
+ else
+ return nil, 'no content length specified'
+ end
+ end
+ if not body then return nil, err end
+
+ self._body = body
+ return body
+end
local Client = {}
Client.__index = Client
-client.Client = Client
+M.Client = Client
-function client.new()
+function M.new()
return setmetatable({
proto = false,
domain = false,
@@ -95,14 +159,12 @@ function Client:get(url)
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
+ res.conn = c
+ setmetatable(res, Response)
self.proto = proto
self.domain = domain
self.conn = c
- res.body = body
return res
end
@@ -123,6 +185,6 @@ function Client:download(url, filename)
return true
end
-return client
+return M
-- vim: set ts=2 sw=2 noet:
diff --git a/lem/http/core.c b/lem/http/core.c
index 5c14d13..9fdd954 100644
--- a/lem/http/core.c
+++ b/lem/http/core.c
@@ -18,11 +18,6 @@
#include <lem-parsers.h>
-#if !(LUA_VERSION_NUM >= 502)
-#define lua_getuservalue lua_getfenv
-#define lua_setuservalue lua_setfenv
-#endif
-
enum classes {
C_CTL, /* control characters */
C_LF, /* \n */
@@ -164,8 +159,6 @@ parse_http_init(lua_State *T)
/* create result table */
lua_settop(T, 2);
lua_createtable(T, 0, 5);
- lua_pushvalue(T, 1);
- lua_setfield(T, -2, "client");
}
static void
@@ -303,10 +296,6 @@ parse_http_process(lua_State *T, struct lem_inputbuf *b)
}
lua_setfield(T, -2, "headers");
- /* set metatable */
- lua_getuservalue(T, 2);
- lua_setmetatable(T, -2);
-
if (r == end)
b->start = b->end = 0;
else
@@ -328,42 +317,25 @@ parse_http_process(lua_State *T, struct lem_inputbuf *b)
return LEM_PMORE;
}
+static const struct lem_parser http_req_parser = {
+ .init = parse_http_req_init,
+ .process = parse_http_process,
+};
+
+static const struct lem_parser http_res_parser = {
+ .init = parse_http_res_init,
+ .process = parse_http_process,
+};
+
int
luaopen_lem_http_core(lua_State *L)
{
- struct lem_parser *p;
-
/* create module table M */
lua_newtable(L);
- /* create Request metatable */
- lua_newtable(L);
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
- /* insert Request metatable */
- lua_setfield(L, -2, "Request");
-
- /* create Response metatable */
- lua_newtable(L);
- lua_pushvalue(L, -1);
- lua_setfield(L, -2, "__index");
- /* insert Request metatable */
- lua_setfield(L, -2, "Response");
-
- p = lua_newuserdata(L, sizeof(struct lem_parser));
- p->init = parse_http_req_init;
- p->process = parse_http_process;
- p->destroy = NULL;
- lua_getfield(L, -2, "Request");
- lua_setuservalue(L, -2);
+ lua_pushlightuserdata(L, (void *)&http_req_parser);
lua_setfield(L, -2, "HTTPRequest");
-
- p = lua_newuserdata(L, sizeof(struct lem_parser));
- p->init = parse_http_res_init;
- p->process = parse_http_process;
- p->destroy = NULL;
- lua_getfield(L, -2, "Response");
- lua_setuservalue(L, -2);
+ lua_pushlightuserdata(L, (void *)&http_res_parser);
lua_setfield(L, -2, "HTTPResponse");
return 1;
diff --git a/lem/http/server.lua b/lem/http/server.lua
index fcab33b..a3cb86b 100644
--- a/lem/http/server.lua
+++ b/lem/http/server.lua
@@ -35,6 +35,29 @@ local M = {}
function M.debug() end
+local Request = {}
+Request.__index = Request
+M.Request = Request
+
+function Request:body()
+ local len, body = self.headers['content-length'], ''
+ if not len then return body end
+
+ len = tonumber(len)
+ if len <= 0 then return body end
+
+ if self.headers['expect'] == '100-continue' then
+ local ok, err = self.client:write('HTTP/1.1 100 Continue\r\n\r\n')
+ if not ok then return nil, err end
+ end
+
+ local err
+ body, err = self.client:read(len)
+ if not body then return nil, err end
+
+ return body
+end
+
do
local gsub, char, tonumber = string.gsub, string.char, tonumber
@@ -67,6 +90,8 @@ local function handleHTTP(self, client)
if not req then self.debug('read', err) break end
local method, uri, version = req.method, req.uri, req.version
+ setmetatable(req, Request)
+ req.client = client
req.path = urldecode(uri:match('^([^?]*)'))
local res = newresponse(req)
diff --git a/test/httptest.lua b/test/httptest.lua
index bce4cff..311a317 100755
--- a/test/httptest.lua
+++ b/test/httptest.lua
@@ -44,7 +44,8 @@ local function get(n, close)
printf('%d: %s: %s\n', n, k, v)
end
- printf('\n%d: #body = %d\n', n, #res.body)
+ local body = assert(res:body())
+ printf('\n%d: #body = %d\n', n, #body)
assert(c:close())
running = running - 1