Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
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
Hide 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