mirror of
https://gitea.invidious.io/iv-org/shard-kemal.git
synced 2024-08-15 00:53:36 +00:00
Merge pull request #102 from jmoriau/fix-filters-verb
added verb for filters and minor improvements
This commit is contained in:
commit
4c9b9ad3d5
13 changed files with 259 additions and 92 deletions
|
@ -2,7 +2,7 @@ require "./spec_helper"
|
||||||
|
|
||||||
describe "Context" do
|
describe "Context" do
|
||||||
it "has a default content type" do
|
it "has a default content type" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
"Hello"
|
"Hello"
|
||||||
end
|
end
|
||||||
|
@ -13,7 +13,7 @@ describe "Context" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets content type" do
|
it "sets content type" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
env.response.content_type = "application/json"
|
env.response.content_type = "application/json"
|
||||||
"Hello"
|
"Hello"
|
||||||
|
@ -25,7 +25,7 @@ describe "Context" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "parses headers" do
|
it "parses headers" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
name = env.request.headers["name"]
|
name = env.request.headers["name"]
|
||||||
"Hello #{name}"
|
"Hello #{name}"
|
||||||
|
@ -39,7 +39,7 @@ describe "Context" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets response headers" do
|
it "sets response headers" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
env.response.headers.add "Accept-Language", "tr"
|
env.response.headers.add "Accept-Language", "tr"
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,19 +5,145 @@ describe "Kemal::Middleware::Filters" do
|
||||||
test_filter = FilterTest.new
|
test_filter = FilterTest.new
|
||||||
test_filter.modified = "false"
|
test_filter.modified = "false"
|
||||||
|
|
||||||
filter = Kemal::Middleware::Filter.new
|
filter_middleware = Kemal::Middleware::Filter.new
|
||||||
filter.add :before, "/greetings", {} of Symbol => String { test_filter.modified = "true" }
|
filter_middleware._add_route_filter("GET", "/greetings", :before) { test_filter.modified = "true" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
test_filter.modified.should eq("false")
|
test_filter.modified.should eq("false")
|
||||||
request = HTTP::Request.new("GET", "/greetings")
|
request = HTTP::Request.new("GET", "/greetings")
|
||||||
create_request_and_return_io(filter, request)
|
create_request_and_return_io(filter_middleware, request)
|
||||||
io_with_context = create_request_and_return_io(kemal, request)
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
client_response.body.should eq("true")
|
client_response.body.should eq("true")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "executes code before GET home request but not POST home request" do
|
||||||
|
test_filter = FilterTest.new
|
||||||
|
test_filter.modified = "false"
|
||||||
|
|
||||||
|
filter_middleware = Kemal::Middleware::Filter.new
|
||||||
|
filter_middleware._add_route_filter("GET", "/greetings", :before) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
|
||||||
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
test_filter.modified.should eq("false")
|
||||||
|
|
||||||
|
request = HTTP::Request.new("GET", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("true")
|
||||||
|
|
||||||
|
request = HTTP::Request.new("POST", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("true")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes code before all GET/POST home request" do
|
||||||
|
test_filter = FilterTest.new
|
||||||
|
test_filter.modified = "false"
|
||||||
|
|
||||||
|
filter_middleware = Kemal::Middleware::Filter.new
|
||||||
|
filter_middleware._add_route_filter("ALL", "/greetings", :before) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
filter_middleware._add_route_filter("GET", "/greetings", :before) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
filter_middleware._add_route_filter("POST", "/greetings", :before) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
|
||||||
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
test_filter.modified.should eq("false")
|
||||||
|
|
||||||
|
request = HTTP::Request.new("GET", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("false")
|
||||||
|
|
||||||
|
request = HTTP::Request.new("POST", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("false")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes code after home request" do
|
||||||
|
test_filter = FilterTest.new
|
||||||
|
test_filter.modified = "false"
|
||||||
|
|
||||||
|
filter_middleware = Kemal::Middleware::Filter.new
|
||||||
|
filter_middleware._add_route_filter("GET", "/greetings", :after) { test_filter.modified = "true" }
|
||||||
|
|
||||||
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
test_filter.modified.should eq("false")
|
||||||
|
request = HTTP::Request.new("GET", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("true")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes code after GET home request but not POST home request" do
|
||||||
|
test_filter = FilterTest.new
|
||||||
|
test_filter.modified = "false"
|
||||||
|
|
||||||
|
filter_middleware = Kemal::Middleware::Filter.new
|
||||||
|
filter_middleware._add_route_filter("GET", "/greetings", :after) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
|
||||||
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
test_filter.modified.should eq("false")
|
||||||
|
|
||||||
|
request = HTTP::Request.new("GET", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("true")
|
||||||
|
|
||||||
|
request = HTTP::Request.new("POST", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("true")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "executes code after all GET/POST home request" do
|
||||||
|
test_filter = FilterTest.new
|
||||||
|
test_filter.modified = "false"
|
||||||
|
|
||||||
|
filter_middleware = Kemal::Middleware::Filter.new
|
||||||
|
filter_middleware._add_route_filter("ALL", "/greetings", :after) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
filter_middleware._add_route_filter("GET", "/greetings", :after) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
filter_middleware._add_route_filter("POST", "/greetings", :after) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
|
||||||
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
test_filter.modified.should eq("false")
|
||||||
|
request = HTTP::Request.new("GET", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("false")
|
||||||
|
|
||||||
|
request = HTTP::Request.new("POST", "/greetings")
|
||||||
|
create_request_and_return_io(filter_middleware, request)
|
||||||
|
io_with_context = create_request_and_return_io(kemal, request)
|
||||||
|
client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
client_response.body.should eq("false")
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class FilterTest
|
class FilterTest
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe "ParamParser" do
|
||||||
"Hello #{hasan}"
|
"Hello #{hasan}"
|
||||||
end
|
end
|
||||||
request = HTTP::Request.new("POST", "/?hasan=cemal")
|
request = HTTP::Request.new("POST", "/?hasan=cemal")
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
params = Kemal::ParamParser.new(request).parse
|
||||||
params["hasan"].should eq "cemal"
|
params["hasan"].should eq "cemal"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ describe "ParamParser" do
|
||||||
headers: HTTP::Headers{"Content-Type": "application/x-www-form-urlencoded"},
|
headers: HTTP::Headers{"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
)
|
)
|
||||||
|
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
params = Kemal::ParamParser.new(request).parse
|
||||||
params.should eq({"hasan" => "cemal", "name" => "serdar", "age" => "99"})
|
params.should eq({"hasan" => "cemal", "name" => "serdar", "age" => "99"})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ describe "ParamParser" do
|
||||||
headers: HTTP::Headers{"Content-Type": "application/json"},
|
headers: HTTP::Headers{"Content-Type": "application/json"},
|
||||||
)
|
)
|
||||||
|
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
params = Kemal::ParamParser.new(request).parse
|
||||||
params.should eq({"name": "Serdar"})
|
params.should eq({"name": "Serdar"})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ describe "ParamParser" do
|
||||||
headers: HTTP::Headers{"Content-Type": "application/json"},
|
headers: HTTP::Headers{"Content-Type": "application/json"},
|
||||||
)
|
)
|
||||||
|
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
params = Kemal::ParamParser.new(request).parse
|
||||||
params.should eq({"_json": [1]})
|
params.should eq({"_json": [1]})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ describe "ParamParser" do
|
||||||
headers: HTTP::Headers{"Content-Type": "application/json"},
|
headers: HTTP::Headers{"Content-Type": "application/json"},
|
||||||
)
|
)
|
||||||
|
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
params = Kemal::ParamParser.new(request).parse
|
||||||
params.should eq({"foo": "bar", "_json": [1]})
|
params.should eq({"foo": "bar", "_json": [1]})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ describe "ParamParser" do
|
||||||
headers: HTTP::Headers{"Content-Type": "application/json"},
|
headers: HTTP::Headers{"Content-Type": "application/json"},
|
||||||
)
|
)
|
||||||
|
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
params = Kemal::ParamParser.new(request).parse
|
||||||
params.should eq({} of String => AllParamTypes)
|
params.should eq({} of String => AllParamTypes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -103,7 +103,7 @@ describe "ParamParser" do
|
||||||
headers: HTTP::Headers{"Content-Type": "text/plain"},
|
headers: HTTP::Headers{"Content-Type": "text/plain"},
|
||||||
)
|
)
|
||||||
|
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
params = Kemal::ParamParser.new(request).parse
|
||||||
params.should eq({"hasan" => "cemal"})
|
params.should eq({"hasan" => "cemal"})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,7 @@ require "./spec_helper"
|
||||||
|
|
||||||
describe "Kemal::RouteHandler" do
|
describe "Kemal::RouteHandler" do
|
||||||
it "routes" do
|
it "routes" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do
|
kemal.add_route "GET", "/" do
|
||||||
"hello"
|
"hello"
|
||||||
end
|
end
|
||||||
|
@ -13,7 +13,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "routes request with query string" do
|
it "routes request with query string" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
"hello #{env.params["message"]}"
|
"hello #{env.params["message"]}"
|
||||||
end
|
end
|
||||||
|
@ -24,7 +24,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "routes request with multiple query strings" do
|
it "routes request with multiple query strings" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
"hello #{env.params["message"]} time #{env.params["time"]}"
|
"hello #{env.params["message"]} time #{env.params["time"]}"
|
||||||
end
|
end
|
||||||
|
@ -35,7 +35,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "route parameter has more precedence than query string arguments" do
|
it "route parameter has more precedence than query string arguments" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/:message" do |env|
|
kemal.add_route "GET", "/:message" do |env|
|
||||||
"hello #{env.params["message"]}"
|
"hello #{env.params["message"]}"
|
||||||
end
|
end
|
||||||
|
@ -46,7 +46,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "parses simple JSON body" do
|
it "parses simple JSON body" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "POST", "/" do |env|
|
kemal.add_route "POST", "/" do |env|
|
||||||
name = env.params["name"]
|
name = env.params["name"]
|
||||||
age = env.params["age"]
|
age = env.params["age"]
|
||||||
|
@ -66,7 +66,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "parses JSON with string array" do
|
it "parses JSON with string array" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "POST", "/" do |env|
|
kemal.add_route "POST", "/" do |env|
|
||||||
skills = env.params["skills"] as Array
|
skills = env.params["skills"] as Array
|
||||||
"Skills #{skills.each.join(',')}"
|
"Skills #{skills.each.join(',')}"
|
||||||
|
@ -85,7 +85,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "parses JSON with json object array" do
|
it "parses JSON with json object array" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "POST", "/" do |env|
|
kemal.add_route "POST", "/" do |env|
|
||||||
skills = env.params["skills"] as Array
|
skills = env.params["skills"] as Array
|
||||||
skills_from_languages = skills.map do |skill|
|
skills_from_languages = skills.map do |skill|
|
||||||
|
@ -110,7 +110,7 @@ describe "Kemal::RouteHandler" do
|
||||||
|
|
||||||
# Removed until there is a way to test multiple middlewares
|
# Removed until there is a way to test multiple middlewares
|
||||||
# it "renders 404 on not found" do
|
# it "renders 404 on not found" do
|
||||||
# kemal = Kemal::RouteHandler.new
|
# kemal = Kemal::RouteHandler::INSTANCE
|
||||||
# request = HTTP::Request.new("GET", "/?message=world")
|
# request = HTTP::Request.new("GET", "/?message=world")
|
||||||
# io_with_context = create_request_and_return_io(kemal, request)
|
# io_with_context = create_request_and_return_io(kemal, request)
|
||||||
# client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
# client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
@ -118,7 +118,7 @@ describe "Kemal::RouteHandler" do
|
||||||
# end
|
# end
|
||||||
|
|
||||||
# it "renders 500 on exception" do
|
# it "renders 500 on exception" do
|
||||||
# kemal = Kemal::RouteHandler.new
|
# kemal = Kemal::RouteHandler::INSTANCE
|
||||||
# kemal.add_route "GET", "/" do
|
# kemal.add_route "GET", "/" do
|
||||||
# raise "Exception"
|
# raise "Exception"
|
||||||
# end
|
# end
|
||||||
|
@ -130,7 +130,7 @@ describe "Kemal::RouteHandler" do
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
it "checks for _method param in POST request to simulate PUT" do
|
it "checks for _method param in POST request to simulate PUT" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "PUT", "/" do |env|
|
kemal.add_route "PUT", "/" do |env|
|
||||||
"Hello World from PUT"
|
"Hello World from PUT"
|
||||||
end
|
end
|
||||||
|
@ -146,7 +146,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "checks for _method param in POST request to simulate PATCH" do
|
it "checks for _method param in POST request to simulate PATCH" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "PATCH", "/" do |env|
|
kemal.add_route "PATCH", "/" do |env|
|
||||||
"Hello World from PATCH"
|
"Hello World from PATCH"
|
||||||
end
|
end
|
||||||
|
@ -162,7 +162,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "checks for _method param in POST request to simulate DELETE" do
|
it "checks for _method param in POST request to simulate DELETE" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "DELETE", "/" do |env|
|
kemal.add_route "DELETE", "/" do |env|
|
||||||
"Hello World from DELETE"
|
"Hello World from DELETE"
|
||||||
end
|
end
|
||||||
|
@ -179,7 +179,7 @@ describe "Kemal::RouteHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can process HTTP HEAD requests for defined GET routes" do
|
it "can process HTTP HEAD requests for defined GET routes" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
"Hello World from GET"
|
"Hello World from GET"
|
||||||
end
|
end
|
||||||
|
@ -191,7 +191,7 @@ describe "Kemal::RouteHandler" do
|
||||||
|
|
||||||
# Removed until there is a way to test multiple middlewares
|
# Removed until there is a way to test multiple middlewares
|
||||||
# it "can't process HTTP HEAD requests for undefined GET routes" do
|
# it "can't process HTTP HEAD requests for undefined GET routes" do
|
||||||
# kemal = Kemal::RouteHandler.new
|
# kemal = Kemal::RouteHandler::INSTANCE
|
||||||
# request = HTTP::Request.new("HEAD", "/")
|
# request = HTTP::Request.new("HEAD", "/")
|
||||||
# io_with_context = create_request_and_return_io(kemal, request)
|
# io_with_context = create_request_and_return_io(kemal, request)
|
||||||
# client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
# client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false)
|
||||||
|
@ -199,7 +199,7 @@ describe "Kemal::RouteHandler" do
|
||||||
# end
|
# end
|
||||||
|
|
||||||
it "redirects user to provided url" do
|
it "redirects user to provided url" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/" do |env|
|
kemal.add_route "GET", "/" do |env|
|
||||||
env.redirect "/login"
|
env.redirect "/login"
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ require "./spec_helper"
|
||||||
describe "Route" do
|
describe "Route" do
|
||||||
describe "match?" do
|
describe "match?" do
|
||||||
it "matches the correct route" do
|
it "matches the correct route" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/route1" do |env|
|
kemal.add_route "GET", "/route1" do |env|
|
||||||
"Route 1"
|
"Route 1"
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,4 +40,5 @@ Spec.before_each do
|
||||||
config.env = "development"
|
config.env = "development"
|
||||||
config.setup_logging
|
config.setup_logging
|
||||||
config.handlers.clear
|
config.handlers.clear
|
||||||
|
Kemal::RouteHandler::INSTANCE.tree = Radix::Tree.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ end
|
||||||
|
|
||||||
describe "Views" do
|
describe "Views" do
|
||||||
it "renders file" do
|
it "renders file" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/view/:name" do |env|
|
kemal.add_route "GET", "/view/:name" do |env|
|
||||||
name = env.params["name"]
|
name = env.params["name"]
|
||||||
render "spec/asset/hello.ecr"
|
render "spec/asset/hello.ecr"
|
||||||
|
@ -18,7 +18,7 @@ describe "Views" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders file with dynamic variables" do
|
it "renders file with dynamic variables" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/view/:name" do |env|
|
kemal.add_route "GET", "/view/:name" do |env|
|
||||||
name = env.params["name"]
|
name = env.params["name"]
|
||||||
render_with_base_and_layout "hello.ecr"
|
render_with_base_and_layout "hello.ecr"
|
||||||
|
@ -30,7 +30,7 @@ describe "Views" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders layout" do
|
it "renders layout" do
|
||||||
kemal = Kemal::RouteHandler.new
|
kemal = Kemal::RouteHandler::INSTANCE
|
||||||
kemal.add_route "GET", "/view/:name" do |env|
|
kemal.add_route "GET", "/view/:name" do |env|
|
||||||
name = env.params["name"]
|
name = env.params["name"]
|
||||||
render "spec/asset/hello.ecr", "spec/asset/layout.ecr"
|
render "spec/asset/hello.ecr", "spec/asset/layout.ecr"
|
||||||
|
|
|
@ -3,12 +3,21 @@
|
||||||
class HTTP::Server
|
class HTTP::Server
|
||||||
class Context
|
class Context
|
||||||
def params
|
def params
|
||||||
@params ||= Kemal::ParamParser.new(@route, @request).parse
|
@params ||= Kemal::ParamParser.new(@request).parse
|
||||||
end
|
end
|
||||||
|
|
||||||
def redirect(url, status_code = 302)
|
def redirect(url, status_code = 302)
|
||||||
@response.headers.add "Location", url
|
@response.headers.add "Location", url
|
||||||
@response.status_code = status_code
|
@response.status_code = status_code
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def route_lookup
|
||||||
|
@route_lookup ||= Kemal::RouteHandler::INSTANCE.lookup_route(@request.override_method as String, @request.path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def route_defined?
|
||||||
|
route_lookup.found?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,47 +2,72 @@ module Kemal::Middleware
|
||||||
# Kemal::Filter handle all code that should be evaluated before and after
|
# Kemal::Filter handle all code that should be evaluated before and after
|
||||||
# every request
|
# every request
|
||||||
class Filter < HTTP::Handler
|
class Filter < HTTP::Handler
|
||||||
|
INSTANCE = new
|
||||||
|
|
||||||
|
# This middleware is lazily instantiated and added to the handlers as soon as a call to `after_X` or `before_X` is made.
|
||||||
def initialize
|
def initialize
|
||||||
@tree = Radix::Tree.new
|
@tree = Radix::Tree.new
|
||||||
|
Kemal.config.add_handler(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add(type, path, options, &block : HTTP::Server::Context -> _)
|
# The call order of the filters is before_all -> before_x -> X -> after_x -> after_all
|
||||||
node = radix_path type, path
|
|
||||||
@tree.add node, Block.new &block
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(context)
|
def call(context)
|
||||||
process_filter(context, :before)
|
return call_next(context) unless context.route_defined?
|
||||||
|
call_block_for_path_type("ALL", context.request.path, :before, context)
|
||||||
|
call_block_for_path_type(context.request.override_method, context.request.path, :before, context)
|
||||||
call_next(context)
|
call_next(context)
|
||||||
process_filter(context, :after)
|
call_block_for_path_type(context.request.override_method, context.request.path, :after, context)
|
||||||
|
call_block_for_path_type("ALL", context.request.path, :after, context)
|
||||||
|
context
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_for_path_type_defined?(path, type)
|
# This checks is filter is already defined for the verb/path/type combination
|
||||||
lookup = @tree.find radix_path(type, path)
|
def filter_for_path_type_defined?(verb, path, type)
|
||||||
|
lookup = @tree.find radix_path(verb, path, type)
|
||||||
lookup.found? && lookup.payload.is_a? Block
|
lookup.found? && lookup.payload.is_a? Block
|
||||||
end
|
end
|
||||||
|
|
||||||
private def process_filter(context, type)
|
# :nodoc: This shouldn't be called directly, it's not private because I need to call it for testing purpose since I can't call the macros in the spec.
|
||||||
lookup = @tree.find radix_path(type, context.request.path)
|
# It adds the block for the corresponding verb/path/type combination to the tree.
|
||||||
|
def _add_route_filter(verb, path, type, &block : HTTP::Server::Context -> _)
|
||||||
|
node = radix_path(verb, path, type)
|
||||||
|
@tree.add node, Block.new &block
|
||||||
|
end
|
||||||
|
|
||||||
|
# This can be called directly but it's simpler to just use the macros, it will check if another filter is not already defined for this verb/path/type and proceed to call `add_route_filter`
|
||||||
|
def before(verb, path = "*", &block : HTTP::Server::Context -> _)
|
||||||
|
raise Kemal::Middleware::Filter::BeforeFilterAlreadyDefinedException.new(verb, path) if filter_for_path_type_defined?(verb, path, :before)
|
||||||
|
_add_route_filter verb, path, :before, &block
|
||||||
|
end
|
||||||
|
|
||||||
|
# This can be called directly but it's simpler to just use the macros, it will check if another filter is not already defined for this verb/path/type and proceed to call `add_route_filter`
|
||||||
|
def after(verb, path = "*", &block : HTTP::Server::Context -> _)
|
||||||
|
raise Kemal::Middleware::Filter::AfterFilterAlreadyDefinedException.new(verb, path) if filter_for_path_type_defined?(verb, path, :after)
|
||||||
|
_add_route_filter verb, path, :after, &block
|
||||||
|
end
|
||||||
|
|
||||||
|
# This will fetch the block for the verb/path/type from the tree and call it.
|
||||||
|
private def call_block_for_path_type(verb, path, type, context)
|
||||||
|
lookup = @tree.find radix_path(verb, path, type)
|
||||||
if lookup.found? && lookup.payload.is_a? Block
|
if lookup.found? && lookup.payload.is_a? Block
|
||||||
block = lookup.payload as Block
|
block = lookup.payload as Block
|
||||||
block.block.call(context)
|
block.block.call(context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def radix_path(type : Symbol, path)
|
private def radix_path(verb, path, type : Symbol)
|
||||||
"/#{type}#{path}"
|
"#{type}/#{verb}/#{path}"
|
||||||
end
|
end
|
||||||
|
|
||||||
class BeforeFilterAlreadyDefinedException < Exception
|
class BeforeFilterAlreadyDefinedException < Exception
|
||||||
def initialize(path)
|
def initialize(verb, path)
|
||||||
super "A before-filter is already defined for path: '#{path}'."
|
super "A before-filter is already defined for path: '#{verb}:#{path}'."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class AfterFilterAlreadyDefinedException < Exception
|
class AfterFilterAlreadyDefinedException < Exception
|
||||||
def initialize(path)
|
def initialize(verb, path)
|
||||||
super "An after-filter is already defined for path: '#{path}'."
|
super "An after-filter is already defined for path: '#{verb}:#{path}'."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -55,22 +80,15 @@ module Kemal::Middleware
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_filters
|
# All the helper methods available are:
|
||||||
unless filter = Kemal.config.handlers.any? { |handler| handler.is_a? Kemal::Middleware::Filter }
|
# - before_all, before_get, before_post, before_put, before_patch, before_delete
|
||||||
filter = Kemal::Middleware::Filter.new
|
# - after_all, after_get, after_post, after_put, after_patch, after_delete
|
||||||
Kemal.config.add_handler filter
|
|
||||||
end
|
|
||||||
filter
|
|
||||||
end
|
|
||||||
|
|
||||||
def before(path = "*", options = {} of Symbol => String, &block : HTTP::Server::Context -> _)
|
ALL_METHODS = %w(get post put patch delete all)
|
||||||
filter = (Kemal.config.handlers.find { |handler| handler.is_a? Kemal::Middleware::Filter } || add_filters) as Kemal::Middleware::Filter
|
{% for type in ["before", "after"]%}
|
||||||
raise Kemal::Middleware::Filter::BeforeFilterAlreadyDefinedException.new(path) if filter.filter_for_path_type_defined?(path, :before)
|
{% for method in ALL_METHODS %}
|
||||||
filter.add :before, path, options, &block
|
def {{type.id}}_{{method.id}}(path = "*", &block : HTTP::Server::Context -> _)
|
||||||
end
|
Kemal::Middleware::Filter::INSTANCE.{{type.id}}({{method}}.upcase, path, &block)
|
||||||
|
|
||||||
def after(path = "*", options = {} of Symbol => String, &block : HTTP::Server::Context -> _)
|
|
||||||
filter = (Kemal.config.handlers.find { |handler| handler.is_a? Kemal::Middleware::Filter } || add_filters) as Kemal::Middleware::Filter
|
|
||||||
raise Kemal::Middleware::Filter::AfterFilterAlreadyDefinedException.new(path) if filter.filter_for_path_type_defined?(path, :after)
|
|
||||||
filter.add :after, path, options, &block
|
|
||||||
end
|
end
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
|
|
@ -9,7 +9,7 @@ class Kemal::ParamParser
|
||||||
URL_ENCODED_FORM = "application/x-www-form-urlencoded"
|
URL_ENCODED_FORM = "application/x-www-form-urlencoded"
|
||||||
APPLICATION_JSON = "application/json"
|
APPLICATION_JSON = "application/json"
|
||||||
|
|
||||||
def initialize(@route, @request)
|
def initialize(@request)
|
||||||
@params = {} of String => AllParamTypes
|
@params = {} of String => AllParamTypes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,4 +2,28 @@
|
||||||
class HTTP::Request
|
class HTTP::Request
|
||||||
property override_method
|
property override_method
|
||||||
property url_params
|
property url_params
|
||||||
|
|
||||||
|
def override_method
|
||||||
|
@override_method ||= check_for_method_override!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Checks if request params contain _method param to override request incoming method
|
||||||
|
private def check_for_method_override!
|
||||||
|
@override_method = @method
|
||||||
|
if @method == "POST"
|
||||||
|
params = Kemal::ParamParser.new(self).parse_request
|
||||||
|
if params.has_key?("_method") && HTTP::Request.override_method_valid?(params["_method"])
|
||||||
|
@override_method = params["_method"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@override_method
|
||||||
|
end
|
||||||
|
|
||||||
|
# Checks if method contained in _method param is valid one
|
||||||
|
def self.override_method_valid?(override_method)
|
||||||
|
return false unless override_method.is_a?(String)
|
||||||
|
override_method = override_method.upcase
|
||||||
|
override_method == "PUT" || override_method == "PATCH" || override_method == "DELETE"
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,21 +8,5 @@ class Kemal::Route
|
||||||
def initialize(@method, @path, &@handler : HTTP::Server::Context -> _)
|
def initialize(@method, @path, &@handler : HTTP::Server::Context -> _)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Checks if request params contain _method param to override request incoming method
|
|
||||||
def self.check_for_method_override!(request)
|
|
||||||
request.override_method = request.method
|
|
||||||
if request.method == "POST"
|
|
||||||
params = Kemal::ParamParser.new(self, request).parse_request
|
|
||||||
if params.has_key?("_method") && self.override_method_valid?(params["_method"])
|
|
||||||
request.override_method = params["_method"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Checks if method contained in _method param is valid one
|
|
||||||
def self.override_method_valid?(override_method)
|
|
||||||
return false unless override_method.is_a?(String)
|
|
||||||
override_method = override_method.upcase
|
|
||||||
return (override_method == "PUT" || override_method == "PATCH" || override_method == "DELETE")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,8 @@ require "radix"
|
||||||
class Kemal::RouteHandler < HTTP::Handler
|
class Kemal::RouteHandler < HTTP::Handler
|
||||||
INSTANCE = new
|
INSTANCE = new
|
||||||
|
|
||||||
|
property tree
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@tree = Radix::Tree.new
|
@tree = Radix::Tree.new
|
||||||
end
|
end
|
||||||
|
@ -22,13 +24,16 @@ class Kemal::RouteHandler < HTTP::Handler
|
||||||
add_to_radix_tree("HEAD", path, Route.new("HEAD", path, &handler)) if method == "GET"
|
add_to_radix_tree("HEAD", path, Route.new("HEAD", path, &handler)) if method == "GET"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Check if a route is defined and returns the lookup
|
||||||
|
def lookup_route(verb, path)
|
||||||
|
@tree.find radix_path(verb, path)
|
||||||
|
end
|
||||||
|
|
||||||
# Processes the route if it's a match. Otherwise renders 404.
|
# Processes the route if it's a match. Otherwise renders 404.
|
||||||
def process_request(context)
|
def process_request(context)
|
||||||
Kemal::Route.check_for_method_override!(context.request)
|
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_defined?
|
||||||
lookup = @tree.find radix_path(context.request.override_method as String, context.request.path)
|
route = context.route_lookup.payload as Route
|
||||||
raise Kemal::Exceptions::RouteNotFound.new(context) unless lookup.found?
|
context.request.url_params = context.route_lookup.params
|
||||||
route = lookup.payload as Route
|
|
||||||
context.request.url_params = lookup.params
|
|
||||||
context.response.print(route.handler.call(context).to_s)
|
context.response.print(route.handler.call(context).to_s)
|
||||||
context
|
context
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue