Skip to content
Permalink
Browse files

Makes a https server easier...

by making the onClient handler public and by adding a :shutdown to cleartext so
that the http.Response can call self.socket:shutdown (ie, on Cleartext).
  • Loading branch information...
kans authored and Ryan Phillips committed Sep 19, 2012
1 parent be683ff commit e6e63f5ed4fba8562d056b2fdd90f1263d164dca
Showing with 145 additions and 140 deletions.
  1. +140 −139 lib/luvit/http.lua
  2. +4 −0 lib/luvit/tls.lua
  3. +1 −1 tests/runner.lua
@@ -1054,164 +1054,165 @@ function http.get(options, callback)
return req
end

function http.createServer(onConnection)
local server
server = net.createServer(function (client)

-- Convert tcp stream to HTTP stream
local request
local current_field
local parser
local url
local headers
parser = HttpParser.new("request", {
onMessageBegin = function ()
headers = {}
end,
onUrl = function (value)
url = value
end,
onHeaderField = function (field)
current_field = field:lower()
end,
onHeaderValue = function (value)
headers[current_field] = value
end,
onHeadersComplete = function (info)

-- Accept the client and build request and response objects
request = Request:new(client)
local response = Response:new(client)

request.method = info.method
request.headers = headers
request.url = url
request.upgrade = info.upgrade

request.version_major = info.version_major
request.version_minor = info.version_minor

-- Give upgrade requests access to the raw client if they want it
if info.upgrade then
request.client = client
end
function http.onClient(server, client, onConnection)
-- Convert tcp stream to HTTP stream
local request
local current_field
local parser
local url
local headers
parser = HttpParser.new("request", {
onMessageBegin = function ()
headers = {}
end,
onUrl = function (value)
url = value
end,
onHeaderField = function (field)
current_field = field:lower()
end,
onHeaderValue = function (value)
headers[current_field] = value
end,
onHeadersComplete = function (info)

-- HTTP keep-alive logic
request.should_keep_alive = info.should_keep_alive
response.should_keep_alive = info.should_keep_alive
-- N.B. keep-alive requires explicit message length
if info.should_keep_alive then
--[[
In order to remain persistent, all messages on the connection MUST
have a self-defined message length (i.e., one not defined by closure
of the connection)
]]
response.auto_content_length = false
-- HTTP/1.0 should insert Connection: keep-alive
if info.version_minor < 1 then
response:setHeader("Connection", "keep-alive")
end
else
-- HTTP/1.1 should insert Connection: close for last message
if info.version_minor >= 1 then
response:setHeader("Connection", "close")
end
end
-- Accept the client and build request and response objects
request = Request:new(client)
local response = Response:new(client)

-- Handle 100-continue requests
if request.headers.expect
and info.version_major == 1
and info.version_minor == 1
and request.headers.expect:lower() == "100-continue"
then
if server.handlers and server.handlers.check_continue then
server:emit("check_continue", request, response)
else
response:writeContinue()
onConnection(request, response)
end
else
onConnection(request, response)
end
request.method = info.method
request.headers = headers
request.url = url
request.upgrade = info.upgrade

end,
onBody = function (chunk)
request:emit("data", chunk)
end,
onMessageComplete = function ()
request:emit("end")
request:removeListener("end")
if request.should_keep_alive then
parser:finish()
end
end
})
request.version_major = info.version_major
request.version_minor = info.version_minor

client:on("data", function (chunk)
-- Give upgrade requests access to the raw client if they want it
if info.upgrade then
request.client = client
end

-- Once we're in "upgrade" mode, the protocol is no longer HTTP and we
-- shouldn't send data to the HTTP parser
if request and request.upgrade then
request:emit("data", chunk)
return
-- HTTP keep-alive logic
request.should_keep_alive = info.should_keep_alive
response.should_keep_alive = info.should_keep_alive
-- N.B. keep-alive requires explicit message length
if info.should_keep_alive then
--[[
In order to remain persistent, all messages on the connection MUST
have a self-defined message length (i.e., one not defined by closure
of the connection)
]]
response.auto_content_length = false
-- HTTP/1.0 should insert Connection: keep-alive
if info.version_minor < 1 then
response:setHeader("Connection", "keep-alive")
end
else
-- HTTP/1.1 should insert Connection: close for last message
if info.version_minor >= 1 then
response:setHeader("Connection", "close")
end
end

--[[ from http_parser documentation:
To tell http_parser about EOF, give 0 as the forth parameter to
http_parser_execute()
]]--
-- don't route empty chunks to the parser
if #chunk == 0 then return end

-- Parse the chunk of HTTP, this will syncronously emit several of the
-- above events and return how many bytes were parsed
local nparsed = parser:execute(chunk, 0, #chunk)

-- If it wasn't all parsed then there was an error parsing
if nparsed < #chunk and request then
if request.upgrade then
request:emit("data", chunk:sub(nparsed + 1))
-- Handle 100-continue requests
if request.headers.expect
and info.version_major == 1
and info.version_minor == 1
and request.headers.expect:lower() == "100-continue"
then
if server.handlers and server.handlers.check_continue then
server:emit("check_continue", request, response)
else
request:emit("error", "parse error: " .. chunk)
response:writeContinue()
onConnection(request, response)
end
else
onConnection(request, response)
end

end)

client:once("end", function ()
if request then
request:emit("end")
request:removeListener("end")
end,
onBody = function (chunk)
request:emit("data", chunk)
end,
onMessageComplete = function ()
request:emit("end")
request:removeListener("end")
if request.should_keep_alive then
parser:finish()
end
parser:finish()
end)
end
})

client:once("closed", function ()
if request then
request:emit("end")
request:removeListener("end")
end
parser:finish()
end)
client:on("data", function(chunk)
-- Once we're in "upgrade" mode, the protocol is no longer HTTP and we
-- shouldn't send data to the HTTP parser
if request and request.upgrade then
request:emit("data", chunk)
return
end

--[[ from http_parser documentation:
To tell http_parser about EOF, give 0 as the forth parameter to
http_parser_execute()
]]--
-- don't route empty chunks to the parser
if #chunk == 0 then return end

-- Parse the chunk of HTTP, this will syncronously emit several of the
-- above events and return how many bytes were parsed
local nparsed = parser:execute(chunk, 0, #chunk)

client:once("error", function (err)
parser:finish()
-- read from closed client
if err.code == "ECONNRESET" then
-- ???
-- written to closed client
elseif err.code == "EPIPE" then
-- ???
-- other errors
-- If it wasn't all parsed then there was an error parsing
if nparsed < #chunk and request then
if request.upgrade then
request:emit("data", chunk:sub(nparsed + 1))
else
if request then
request:emit("error", err)
end
request:emit("error", "parse error: " .. chunk)
end
end)
end
end)

client:once("end", function ()
if request then
request:emit("end")
request:removeListener("end")
end
parser:finish()
end)

client:once("closed", function ()
if request then
request:emit("end")
request:removeListener("end")
end
parser:finish()
end)

client:once("error", function (err)
parser:finish()
-- read from closed client
if err.code == "ECONNRESET" then
-- ???
-- written to closed client
elseif err.code == "EPIPE" then
-- ???
-- other errors
else
if request then
request:emit("error", err)
end
end
end)

return server
end

function http.createServer(onConnection)
local server
server = net.createServer(function(client)
return http.onClient(server, client, onConnection)
end)
return server
end

@@ -427,6 +427,10 @@ function CleartextStream:_pusher()
return self.pair.ssl:clearOut()
end

function CleartextStream:shutdown(cb)
self:destroy()
if cb then cb() end
end
function CleartextStream:destroy()
if self.socket and self._closing ~= true then
self.socket:destroy()
@@ -92,7 +92,7 @@ local function run(callback)
end
process.stdout:write('Done\n')
if nerr ~= 0 then
callback()
if callback then callback() end
process.exit(1)
end
end)

0 comments on commit e6e63f5

Please sign in to comment.
You can’t perform that action at this time.