1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
require "spec"
require "log/spec"
require "http/server/handler"
require "../../../../support/io"
describe HTTP::ErrorHandler do
it "rescues from exception" do
io = IO::Memory.new
request = HTTP::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)
exception = Exception.new("OH NO!")
handler = HTTP::ErrorHandler.new(verbose: true)
handler.next = ->(ctx : HTTP::Server::Context) { raise exception }
logs = Log.capture("http.server") { handler.call(context) }
response.close
client_response = HTTP::Client::Response.from_io(io.rewind)
client_response.status_code.should eq(500)
client_response.status_message.should eq("Internal Server Error")
client_response.headers["content-type"].should eq("text/plain")
client_response.headers.has_key?("content-length").should be_true
client_response.body.should match(/^ERROR: OH NO! \(Exception\)/)
logs.check(:error, "Unhandled exception")
logs.entry.exception.should eq(exception)
end
it "logs to custom logger" do
request = HTTP::Request.new("GET", "/")
response = HTTP::Server::Response.new(IO::Memory.new)
context = HTTP::Server::Context.new(request, response)
exception = Exception.new("OH NO!")
backend = Log::MemoryBackend.new
log = Log.new("custom", backend, :info)
handler = HTTP::ErrorHandler.new(log: log)
handler.next = ->(ctx : HTTP::Server::Context) { raise exception }
handler.call(context)
logs = Log::EntriesChecker.new(backend.entries)
logs.check(:error, "Unhandled exception")
logs.entry.exception.should eq(exception)
end
it "can return a generic error message" do
io = IO::Memory.new
request = HTTP::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)
exception = Exception.new("OH NO!")
handler = HTTP::ErrorHandler.new
handler.next = ->(ctx : HTTP::Server::Context) { raise exception }
logs = Log.capture("http.server") { handler.call(context) }
client_response = HTTP::Client::Response.from_io(io.rewind)
client_response.status_code.should eq(500)
client_response.status_message.should eq("Internal Server Error")
client_response.headers["content-type"].should eq("text/plain")
client_response.body.should eq("500 Internal Server Error\n")
logs.check(:error, "Unhandled exception")
logs.entry.exception.should eq(exception)
end
it "log debug message when the output is closed" do
io = IO::Memory.new
io.close
request = HTTP::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)
handler = HTTP::ErrorHandler.new
handler.next = ->(ctx : HTTP::Server::Context) { ctx.response.print "Hi!"; ctx.response.flush }
logs = Log.capture("http.server") { handler.call(context) }
logs.check(:debug, "Error while writing data to the client")
logs.entry.exception.should be_a(IO::Error)
end
it "doesn't write errors when there is some output already sent" do
io = IO::Memory.new
request = HTTP::Request.new("GET", "/")
response = HTTP::Server::Response.new(io)
context = HTTP::Server::Context.new(request, response)
exception = Exception.new("OH NO!")
handler = HTTP::ErrorHandler.new
handler.next = ->(ctx : HTTP::Server::Context) do
ctx.response.print "Hi"
ctx.response.flush
raise exception
end
logs = Log.capture("http.server") { handler.call(context) }
response.close
client_response = HTTP::Client::Response.from_io(io.rewind)
client_response.status_code.should eq(200)
client_response.status_message.should eq("OK")
client_response.body.should eq("Hi")
logs.check(:error, "Unhandled exception")
logs.entry.exception.should eq(exception)
end
end
|