Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
93249a52
Commit
93249a52
authored
Jan 19, 2015
by
Vladimir Dronnikov
Browse files
http module draft, with example
parent
0f835d0c
Changes
2
Show whitespace changes
Inline
Side-by-side
lua_modules/http/http-example.lua
0 → 100644
View file @
93249a52
------------------------------------------------------------------------------
-- HTTP server Hello world example
--
-- LICENCE: http://opensource.org/licenses/MIT
-- Vladimir Dronnikov <dronnikov@gmail.com>
------------------------------------------------------------------------------
require
(
"http"
).
createServer
(
80
,
function
(
req
,
res
)
-- analyse method and url
print
(
"+R"
,
req
.
method
,
req
.
url
)
-- setup handler of headers, if any
--[[
req.onheader = function(self, name, value)
-- print("+H", name, value)
-- E.g. look for "content-type" header,
-- setup body parser to particular format
-- if name == "content-type" then
-- if value == "application/json" then
-- req.ondata = function(self, chunk) ... end
-- elseif value == "application/x-www-form-urlencoded" then
-- req.ondata = function(self, chunk) ... end
-- end
-- end
end
-- setup handler of body, if any
req.ondata = function(self, chunk)
print("+B", chunk and #chunk, node.heap())
-- request ended?
if not chunk then
-- reply
--res:finish("")
res:send(nil, 200)
res:send_header("Connection", "close")
res:send("Hello, world!")
res:finish()
end
end
]]
-- or just do something not waiting till body (if any) comes
--res:finish("Hello, world!")
res
:
finish
(
"Salut, monde!"
)
end
)
lua_modules/http/http.lua
0 → 100644
View file @
93249a52
------------------------------------------------------------------------------
-- HTTP server module
--
-- LICENCE: http://opensource.org/licenses/MIT
-- Vladimir Dronnikov <dronnikov@gmail.com>
------------------------------------------------------------------------------
local
collectgarbage
,
tonumber
,
tostring
=
collectgarbage
,
tonumber
,
tostring
local
http
do
------------------------------------------------------------------------------
-- request methods
------------------------------------------------------------------------------
local
make_req
=
function
(
conn
,
method
,
url
)
local
req
=
{
conn
=
conn
,
method
=
method
,
url
=
url
,
}
-- return setmetatable(req, {
-- })
return
req
end
------------------------------------------------------------------------------
-- response methods
------------------------------------------------------------------------------
local
send
=
function
(
self
,
data
,
status
)
local
c
=
self
.
conn
-- TODO: req.send should take care of response headers!
if
self
.
send_header
then
c
:
send
(
"HTTP/1.1 "
)
c
:
send
(
tostring
(
status
or
200
))
-- TODO: real HTTP status code/name table
c
:
send
(
" OK\r\n"
)
-- we use chunked transfer encoding, to not deal with Content-Length:
-- response header
self
:
send_header
(
"Transfer-Encoding"
,
"chunked"
)
-- TODO: send standard response headers, such as Server:, Date:
end
if
data
then
-- NB: no headers allowed after response body started
if
self
.
send_header
then
self
.
send_header
=
nil
-- end response headers
c
:
send
(
"
\r\n
"
)
end
-- chunked transfer encoding
c
:
send
((
"%X\r\n"
):
format
(
#
data
))
c
:
send
(
data
)
c
:
send
(
"
\r\n
"
)
end
end
local
send_header
=
function
(
self
,
name
,
value
)
local
c
=
self
.
conn
-- NB: quite a naive implementation
c
:
send
(
name
)
c
:
send
(
": "
)
c
:
send
(
value
)
c
:
send
(
"
\r\n
"
)
end
-- finalize request, optionally sending data
local
finish
=
function
(
self
,
data
,
status
)
local
c
=
self
.
conn
-- NB: req.send takes care of response headers
if
data
then
self
:
send
(
data
,
status
)
end
-- finalize chunked transfer encoding
c
:
send
(
"0\r\n\r\n"
)
-- close connection
c
:
close
()
end
--
local
make_res
=
function
(
conn
)
local
res
=
{
conn
=
conn
,
}
-- return setmetatable(res, {
-- send_header = send_header,
-- send = send,
-- finish = finish,
-- })
res
.
send_header
=
send_header
res
.
send
=
send
res
.
finish
=
finish
return
res
end
tmr
.
wdclr
()
------------------------------------------------------------------------------
-- HTTP parser
------------------------------------------------------------------------------
local
http_handler
=
function
(
handler
)
return
function
(
conn
)
local
req
,
res
local
buf
=
""
local
method
,
url
local
ondisconnect
=
function
(
conn
)
collectgarbage
(
"collect"
)
end
-- header parser
local
cnt_len
=
0
local
onheader
=
function
(
conn
,
k
,
v
)
-- TODO: look for Content-Type: header
-- to help parse body
-- parse content length to know body length
if
k
==
"content-length"
then
cnt_len
=
tonumber
(
v
)
end
if
k
==
"expect"
and
v
==
"100-continue"
then
conn
:
send
(
"HTTP/1.1 100 Continue\r\n"
)
end
-- delegate to request object
if
req
and
req
.
onheader
then
req
:
onheader
(
k
,
v
)
end
end
-- body data handler
local
body_len
=
0
local
ondata
=
function
(
conn
,
chunk
)
-- NB: do not reset node in case of lengthy requests
tmr
.
wdclr
()
-- feed request data to request handler
if
not
req
or
not
req
.
ondata
then
return
end
req
:
ondata
(
chunk
)
-- NB: once length of seen chunks equals Content-Length:
-- onend(conn) is called
body_len
=
body_len
+
#
chunk
-- print("-B", #chunk, body_len, cnt_len, node.heap())
if
body_len
>=
cnt_len
then
req
:
ondata
()
end
end
local
onreceive
=
function
(
conn
,
chunk
)
-- merge chunks in buffer
if
buf
then
buf
=
buf
..
chunk
else
buf
=
chunk
end
-- consume buffer line by line
while
#
buf
>
0
do
-- extract line
local
e
=
buf
:
find
(
"
\r\n
"
,
1
,
true
)
if
not
e
then
break
end
local
line
=
buf
:
sub
(
1
,
e
-
1
)
buf
=
buf
:
sub
(
e
+
2
)
-- method, url?
if
not
method
then
local
i
-- NB: just version 1.1 assumed
_
,
i
,
method
,
url
=
line
:
find
(
"^([A-Z]+) (.-) HTTP/1.1$"
)
if
method
then
-- make request and response objects
req
=
make_req
(
conn
,
method
,
url
)
res
=
make_res
(
conn
)
end
-- header line?
elseif
#
line
>
0
then
-- parse header
local
_
,
_
,
k
,
v
=
line
:
find
(
"^([%w-]+):%s*(.+)"
)
-- header seems ok?
if
k
then
k
=
k
:
lower
()
onheader
(
conn
,
k
,
v
)
end
-- headers end
else
-- spawn request handler
-- NB: do not reset in case of lengthy requests
tmr
.
wdclr
()
handler
(
req
,
res
)
tmr
.
wdclr
()
-- NB: we feed the rest of the buffer as starting chunk of body
ondata
(
conn
,
buf
)
-- buffer no longer needed
buf
=
nil
-- NB: we explicitly reassign receive handler so that
-- next received chunks go directly to body handler
conn
:
on
(
"receive"
,
ondata
)
-- parser done
break
end
end
end
conn
:
on
(
"receive"
,
onreceive
)
conn
:
on
(
"disconnection"
,
ondisconnect
)
end
end
tmr
.
wdclr
()
------------------------------------------------------------------------------
-- HTTP server
------------------------------------------------------------------------------
local
srv
local
createServer
=
function
(
port
,
handler
)
-- NB: only one server at a time
if
srv
then
srv
:
close
()
end
srv
=
net
.
createServer
(
net
.
TCP
,
15
)
-- listen
srv
:
listen
(
port
,
http_handler
(
handler
))
return
srv
end
------------------------------------------------------------------------------
-- HTTP server methods
------------------------------------------------------------------------------
http
=
{
createServer
=
createServer
,
}
end
return
http
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment