Reworked error handling and pipeline functionality
This commit is contained in:
parent
dd745ca123
commit
7b7d3c928a
|
@ -8,19 +8,58 @@ app = Landline::Server.new do
|
|||
header "content-type", "text/plain"
|
||||
"Hello World!"
|
||||
end
|
||||
get "/error" do
|
||||
|
||||
get "/error" do # This error will be caught by the default server handler
|
||||
raise StandardError, "I raised an error! (and that's very sad)"
|
||||
end
|
||||
handle do |status, backtrace: nil|
|
||||
page = ([Landline::Util::HTTP_STATUS[status]] +
|
||||
|
||||
path "/handled" do
|
||||
get "/error" do # This error will be caught by the handler defined for this path
|
||||
raise StandardError, "I raised an error! (and that's very sad)"
|
||||
end
|
||||
|
||||
handle do |status, backtrace: nil, error: nil|
|
||||
([Landline::Util::HTTP_STATUS[status]] +
|
||||
(backtrace || [""])).join("\n")
|
||||
[
|
||||
{
|
||||
"content-length": page.bytesize,
|
||||
"content-type": "text/plain"
|
||||
},
|
||||
page
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
path "/pipelined" do
|
||||
# The pipeline executes inside the function which catches errors,
|
||||
# so it can catch errors before the handler for the current path.
|
||||
# This may be useful in order to override the way things are output.
|
||||
pipeline do |request, &output|
|
||||
output.call(request)
|
||||
rescue StandardError
|
||||
throw :finish, "Internal error caught in pipeline!"
|
||||
end
|
||||
|
||||
path "/inner" do
|
||||
get "/error" do # This error will be caught by the pipeline
|
||||
raise StandardError, "I raised an error! (and that's very sad)"
|
||||
end
|
||||
end
|
||||
|
||||
path "/inner_override" do
|
||||
get "/error" do # This error will be caught by the innermost handler
|
||||
raise StandardError, "I raised an error! (and that's very sad)"
|
||||
end
|
||||
|
||||
handle do |status, backtrace: nil, error: nil|
|
||||
([Landline::Util::HTTP_STATUS[status]] +
|
||||
(backtrace || [""])).join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
get "/error" do # This error will be caught by the pipeline
|
||||
raise StandardError, "I raised an error! (and that's very sad)"
|
||||
end
|
||||
|
||||
# This handler is preceded by the pipeline, but it may handle 404 codes.
|
||||
handle do |status, backtrace: nil, error: nil|
|
||||
([Landline::Util::HTTP_STATUS[status]] +
|
||||
(backtrace || [""])).join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ class HelloServer < Landline::App
|
|||
page = ([Landline::Util::HTTP_STATUS[status]] +
|
||||
(backtrace || [""])).join("\n")
|
||||
[
|
||||
status,
|
||||
{
|
||||
"content-length": page.bytesize,
|
||||
"content-type": "text/plain",
|
||||
|
|
|
@ -9,14 +9,17 @@ module Landline
|
|||
# @param errorcode [Integer]
|
||||
# @param backtrace [Array(String), nil]
|
||||
# @raise [UncaughtThrowError] throws :finish to return back to Server
|
||||
def die(errorcode, backtrace: nil)
|
||||
throw :finish, [errorcode].append(
|
||||
*(@origin.properties["handle.#{errorcode}"] or
|
||||
def die(errorcode, backtrace: nil, error: nil)
|
||||
response = Landline::Response.convert(
|
||||
(@origin.properties["handle.#{errorcode}"] or
|
||||
@origin.properties["handle.default"]).call(
|
||||
errorcode,
|
||||
backtrace: backtrace
|
||||
backtrace: backtrace,
|
||||
error: error
|
||||
)
|
||||
)
|
||||
response.status = errorcode if response.status == 200
|
||||
throw :finish, response
|
||||
end
|
||||
|
||||
# (in Landline::Probe context)
|
||||
|
|
|
@ -37,6 +37,24 @@ module Landline
|
|||
context.instance_exec(&setup)
|
||||
end
|
||||
|
||||
# (see ::Landline::Node#go)
|
||||
def go(request)
|
||||
# This is done to allow pipeline to interject handlers
|
||||
# I'm more than willing to admit that this is stupid,
|
||||
# but it is well worth the logical flexibility.
|
||||
if ['handle.default', 'handle.505'].any? do |x|
|
||||
@properties.storage.include? x
|
||||
end
|
||||
begin
|
||||
super(request)
|
||||
rescue StandardError => e
|
||||
_die(request, 500, backtrace: [e.to_s] + e.backtrace, error: e)
|
||||
end
|
||||
else
|
||||
super(request)
|
||||
end
|
||||
end
|
||||
|
||||
# Method callback on successful request navigation.
|
||||
# Finds the next appropriate path to go to.
|
||||
# @return [Boolean] true if further navigation will be done
|
||||
|
@ -138,8 +156,6 @@ module Landline
|
|||
return exit_stack(request, value) if value
|
||||
|
||||
notfound(request)
|
||||
rescue StandardError => e
|
||||
_die(request, 500, backtrace: [e.to_s] + e.backtrace)
|
||||
end
|
||||
|
||||
# Run enqueued postprocessors on navigation failure
|
||||
|
@ -175,16 +191,19 @@ module Landline
|
|||
# @param errorcode [Integer]
|
||||
# @param backtrace [Array(String), nil]
|
||||
# @raise [UncaughtThrowError] throws :finish to stop processing
|
||||
def _die(request, errorcode, backtrace: nil)
|
||||
def _die(request, errorcode, backtrace: nil, error: nil)
|
||||
proccontext = get_context(request)
|
||||
throw :finish, [errorcode].append(
|
||||
*proccontext.instance_exec(
|
||||
response = Landline::Response.convert(
|
||||
proccontext.instance_exec(
|
||||
errorcode,
|
||||
backtrace: backtrace,
|
||||
error: error,
|
||||
&(@properties["handle.#{errorcode}"] or
|
||||
@properties["handle.default"])
|
||||
)
|
||||
)
|
||||
response.status = errorcode if response.status == 200
|
||||
throw :finish, response
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ module Landline
|
|||
def match(input)
|
||||
if @pattern.is_a? String
|
||||
input = Landline::PatternMatching.canonicalize(input)
|
||||
if input.start_with?(@pattern)
|
||||
if _match?(input)
|
||||
[input.delete_prefix(@pattern), [], {}]
|
||||
else
|
||||
false
|
||||
|
@ -51,7 +51,8 @@ module Landline
|
|||
# @return [Boolean]
|
||||
def match?(input)
|
||||
if @pattern.is_a? String
|
||||
Landline::PatternMatching.canonicalize(input).start_with? @pattern
|
||||
input = Landline::PatternMatching.canonicalize(input)
|
||||
_match?(input)
|
||||
else
|
||||
@pattern.match?(input)
|
||||
end
|
||||
|
@ -59,6 +60,13 @@ module Landline
|
|||
|
||||
private
|
||||
|
||||
def _match?(input)
|
||||
parts = input.split("/")
|
||||
@pattern.split("/").map.with_index do |part, index|
|
||||
parts[index] == part
|
||||
end.all?(true)
|
||||
end
|
||||
|
||||
def patternify(pattern)
|
||||
classdomain = Landline::PatternMatching
|
||||
classdomain.constants
|
||||
|
|
|
@ -58,14 +58,14 @@ module Landline
|
|||
def setup_properties(*_args, **_opts)
|
||||
{
|
||||
"index" => [],
|
||||
"handle.default" => proc do |code, backtrace: nil|
|
||||
"handle.default" => proc do |code, backtrace: nil, **_extra|
|
||||
page = Landline::Util.default_error_page(code, backtrace)
|
||||
headers = {
|
||||
"content-length": page.bytesize,
|
||||
"content-type": "text/html",
|
||||
"x-cascade": true
|
||||
}
|
||||
[headers, page]
|
||||
[code, headers, page]
|
||||
end,
|
||||
"path" => "/"
|
||||
}.each { |k, v| @properties[k] = v unless @properties[k] }
|
||||
|
|
|
@ -31,7 +31,7 @@ module Landline
|
|||
@storage[key] = value
|
||||
end
|
||||
|
||||
attr_accessor :parent
|
||||
attr_accessor :parent, :storage
|
||||
end
|
||||
|
||||
# Read-only lookup proxy
|
||||
|
|
Loading…
Reference in New Issue