singe/thirdparty/copas/tests/http-timeout.lua

331 lines
11 KiB
Lua

-- tests timeouts with http requests.
--
-- in sending/receiving headers/body
--
local copas = require 'copas'
local socket = require 'socket'
local ltn12 = require 'ltn12'
local request = copas.http.request
-- copas.debug.start()
local response_body = ("A"):rep(1023).."x" -- 1 kb string
local response_headers = [[HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Type: text/html
Content-Length: ]]
local response = response_headers .. tostring(#response_body) .. "\n\n" .. response_body
response = response:gsub("\13?\10", "\13\10") -- update lineendings
local request_headers = {
Header1 = "header value 1 which is really a dummy value",
Header2 = "header value 2 which is really a dummy value",
Header3 = "header value 3 which is really a dummy value",
Header4 = "header value 4 which is really a dummy value",
Header5 = "header value 5 which is really a dummy value",
Header6 = "header value 6 which is really a dummy value",
}
local request_body = response_body
request_headers["Content-Length"] = #request_body
local request_size -- will be set on first test
local timeout = 5
local timeout_bytes_request
local timeout_bytes_response
copas.setErrorHandler(function(msg, co, skt)
-- on any error we want to exit forcefully
print(copas.gettraceback(msg, co, skt))
os.exit(1)
end, true) -- true: make it the default for all threads/coros
local function runtest()
local s1 = socket.bind('*', 49500)
copas.addserver(s1, copas.handler(function(skt)
-- HTTP server that will optionally do a timeout on the request, or on the response
copas.setsocketname("Server 49500", skt)
copas.setthreadname("Server 49500")
-- read bytes up to where we're supposed to do the timeout (if at all)
print("Server reading port 49500: incoming connection")
skt:settimeout(1)
if timeout_bytes_request then
print("Server reading port 49500: generating request-timeout at byte: ", timeout_bytes_request)
local res, err, part = skt:receive(timeout_bytes_request)
if not res then
print("Server reading port 49500: full request:", err, "received:", part)
os.exit(1)
end
-- we timeout on the request, so sleep here and exit
copas.pause(timeout + 1) -- sleep 1 second more than the requester timeout, to force a timeout on the request
print("Server reading port 49500: request-timeout complete")
return skt:close()
end
-- receive full request
print("Server reading port 49500: reading full request")
local res, err, part = skt:receive("*a")
-- print("res",res)
-- print("err",err)
-- print("part",part)
if not res and err == "timeout" then
res = part
end
request_size = #res
print("request size: ", #res)
if not res then
print("Server reading port 49500: first chunk:", err, "received:", part)
os.exit(1)
end
-- request was read, now send the reposnse
if not timeout_bytes_response then
-- just send full response, not timeout generation
local ok, err = skt:send(response)
if not ok then
print("Server reading port 49500: failed sending full response:", err)
os.exit(1)
end
print("Server reading port 49500: send full response, done!")
return skt:close()
end
-- we send a partial response and timeout
print("Server reading port 49500: generating response-timeout at byte: ", timeout_bytes_response)
local ok, err = skt:send(response:sub(1, timeout_bytes_response))
if not ok then
print("Server reading port 49500: failed sending partial response:", err)
os.exit(1)
end
copas.pause(timeout + 1) -- sleep 1 second more than the requester timeout, to force a timeout on the response
print("Server reading port 49500: response-timeout complete")
return skt:close()
end))
copas.addnamedthread("test request", function()
print "Waiting a bit for server to start..."
copas.pause(1) -- give server some time to start
do
print("first test: succesfull round trip")
timeout_bytes_request = nil
timeout_bytes_response = nil
-- make request
local ok, rstatus, rheaders, rstatus_line = request {
url = "http://localhost:49500/some/path",
method = "POST",
headers = request_headers,
timeout = timeout,
source = ltn12.source.string(("B"):rep(1023).."x"), -- request body
sink = ltn12.sink.table({}), -- response body
}
print("Client received response: ")
print(" ok = "..tostring(ok))
print(" status = "..tostring(rstatus))
if not rheaders then
print(" headers = "..tostring(rheaders))
else
print(" headers = {")
for k, v in pairs(rheaders) do
print(" "..tostring(k)..": "..tostring(v))
end
print(" }")
end
print(" status_line = "..tostring(rstatus_line))
if ok and rstatus == 200 then
print("Client: received a '200 OK', as expected!")
else
print("Client: error when requesting:", rstatus)
os.exit(1)
end
-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.pause(2)
print(("="):rep(80))
end
do
print("second test: server generates time-out while receiving the headers")
timeout_bytes_request = 100 -- 100 bytes is still headers
timeout_bytes_response = nil
-- make request
local ok, rstatus, rheaders, rstatus_line = request {
url = "http://localhost:49500/some/path",
method = "POST",
headers = request_headers,
timeout = timeout,
source = ltn12.source.string(("B"):rep(1023).."x"), -- request body
sink = ltn12.sink.table({}), -- response body
}
print("Client received response: ")
print(" ok = "..tostring(ok))
print(" status = "..tostring(rstatus))
if not rheaders then
print(" headers = "..tostring(rheaders))
else
print(" headers = {")
for k, v in pairs(rheaders) do
print(" "..tostring(k)..": "..tostring(v))
end
print(" }")
end
print(" status_line = "..tostring(rstatus_line))
if not ok and rstatus == "timeout" then
print("Client: received a timeout error, as expected!")
else
print("Client: error when requesting:", rstatus)
os.exit(1)
end
-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.pause(2)
print(("="):rep(80))
end
do
print("third test: server generates time-out while receiving the body")
timeout_bytes_request = request_size - 500 -- body = 1k, so 500 before end is right in the middle of the body
timeout_bytes_response = nil
-- make request
local ok, rstatus, rheaders, rstatus_line = request {
url = "http://localhost:49500/some/path",
method = "POST",
headers = request_headers,
timeout = timeout,
source = ltn12.source.string(("B"):rep(1023).."x"), -- request body
sink = ltn12.sink.table({}), -- response body
}
print("Client received response: ")
print(" ok = "..tostring(ok))
print(" status = "..tostring(rstatus))
if not rheaders then
print(" headers = "..tostring(rheaders))
else
print(" headers = {")
for k, v in pairs(rheaders) do
print(" "..tostring(k)..": "..tostring(v))
end
print(" }")
end
print(" status_line = "..tostring(rstatus_line))
if not ok and rstatus == "timeout" then
print("Client: received a timeout error, as expected!")
else
print("Client: error when requesting:", rstatus)
os.exit(1)
end
-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.pause(2)
print(("="):rep(80))
end
do
print("fourth test: server generates time-out while sending the headers")
timeout_bytes_request = nil
timeout_bytes_response = 100 -- after 100 bytes, is still in the headers
-- make request
local ok, rstatus, rheaders, rstatus_line = request {
url = "http://localhost:49500/some/path",
method = "POST",
headers = request_headers,
timeout = timeout,
source = ltn12.source.string(("B"):rep(1023).."x"), -- request body
sink = ltn12.sink.table({}), -- response body
}
print("Client received response: ")
print(" ok = "..tostring(ok))
print(" status = "..tostring(rstatus))
if not rheaders then
print(" headers = "..tostring(rheaders))
else
print(" headers = {")
for k, v in pairs(rheaders) do
print(" "..tostring(k)..": "..tostring(v))
end
print(" }")
end
print(" status_line = "..tostring(rstatus_line))
if not ok and rstatus == "timeout" then
print("Client: received a timeout error, as expected!")
else
print("Client: error when requesting:", rstatus)
os.exit(1)
end
-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.pause(2)
print(("="):rep(80))
end
do
print("fifth test: server generates time-out while sending the body")
timeout_bytes_request = nil
timeout_bytes_response = #response - 500 -- body = 1024, so 500 before end is right in the middle of the body
-- make request
local ok, rstatus, rheaders, rstatus_line = request {
url = "http://localhost:49500/some/path",
method = "POST",
headers = request_headers,
timeout = timeout,
source = ltn12.source.string(("B"):rep(1023).."x"), -- request body
sink = ltn12.sink.table({}), -- response body
}
print("Client received response: ")
print(" ok = "..tostring(ok))
print(" status = "..tostring(rstatus))
if not rheaders then
print(" headers = "..tostring(rheaders))
else
print(" headers = {")
for k, v in pairs(rheaders) do
print(" "..tostring(k)..": "..tostring(v))
end
print(" }")
end
print(" status_line = "..tostring(rstatus_line))
if not ok and rstatus == "timeout" then
print("Client: received a timeout error, as expected!")
else
print("Client: error when requesting:", rstatus)
os.exit(1)
end
-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.pause(2)
print(("="):rep(80))
end
-- close server and exit
print("closing server and exiting...")
copas.removeserver(s1)
end)
print("starting loop")
copas.loop()
print("Loop done")
end
runtest()
print "test success!"