331 lines
11 KiB
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!"
|