mirror of
https://gitea.invidious.io/iv-org/shard-kemal.git
synced 2024-08-15 00:53:36 +00:00
Refactor global namespace DSL into OOP Kemal::Base
This commit is contained in:
parent
a5d8df7382
commit
aaa2109837
25 changed files with 420 additions and 387 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
||||||
|
/doc/
|
||||||
|
/bin/
|
||||||
/lib/
|
/lib/
|
||||||
/.crystal/
|
|
||||||
/.shards/
|
/.shards/
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,17 @@ require "./spec_helper"
|
||||||
|
|
||||||
describe "Config" do
|
describe "Config" do
|
||||||
it "sets default port to 3000" do
|
it "sets default port to 3000" do
|
||||||
Kemal::Config.new.port.should eq 3000
|
config = Kemal::Config.new
|
||||||
|
config.port.should eq 3000
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets default environment to development" do
|
it "sets default environment to development" do
|
||||||
Kemal::Config.new.env.should eq "development"
|
config = Kemal::Config.new
|
||||||
|
config.env.should eq "development"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets environment to production" do
|
it "sets environment to production" do
|
||||||
config = Kemal.config
|
config = Kemal::Config.new
|
||||||
config.env = "production"
|
config.env = "production"
|
||||||
config.env.should eq "production"
|
config.env.should eq "production"
|
||||||
end
|
end
|
||||||
|
@ -20,28 +22,28 @@ describe "Config" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets host binding" do
|
it "sets host binding" do
|
||||||
config = Kemal.config
|
config = Kemal::Config.new
|
||||||
config.host_binding = "127.0.0.1"
|
config.host_binding = "127.0.0.1"
|
||||||
config.host_binding.should eq "127.0.0.1"
|
config.host_binding.should eq "127.0.0.1"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds a custom handler" do
|
it "adds a custom handler" do
|
||||||
config = Kemal.config
|
application = Kemal::Base.new
|
||||||
config.add_handler CustomTestHandler.new
|
application.add_handler CustomTestHandler.new
|
||||||
Kemal.config.setup
|
application.setup
|
||||||
config.handlers.size.should eq(7)
|
application.handlers.size.should eq(8)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "toggles the shutdown message" do
|
it "toggles the shutdown message" do
|
||||||
config = Kemal.config
|
config = Kemal::Config.new
|
||||||
config.shutdown_message = false
|
config.shutdown_message = false
|
||||||
config.shutdown_message.should eq false
|
config.shutdown_message?.should be_false
|
||||||
config.shutdown_message = true
|
config.shutdown_message = true
|
||||||
config.shutdown_message.should eq true
|
config.shutdown_message?.should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adds custom options" do
|
it "adds custom options" do
|
||||||
config = Kemal.config
|
config = Kemal::Config.new
|
||||||
ARGV.push("--test")
|
ARGV.push("--test")
|
||||||
ARGV.push("FOOBAR")
|
ARGV.push("FOOBAR")
|
||||||
test_option = nil
|
test_option = nil
|
||||||
|
@ -51,7 +53,8 @@ describe "Config" do
|
||||||
test_option = opt
|
test_option = opt
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Kemal::CLI.new ARGV
|
|
||||||
|
Kemal::CLI.new(ARGV, config)
|
||||||
test_option.should eq("FOOBAR")
|
test_option.should eq("FOOBAR")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -90,18 +90,17 @@ describe "Context" do
|
||||||
context.get("another_context_test").as(AnotherContextStorageType).name.should eq "kemal-context"
|
context.get("another_context_test").as(AnotherContextStorageType).name.should eq "kemal-context"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fetches non-existent keys from store with get?" do
|
|
||||||
get "/" { }
|
|
||||||
|
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::FilterHandler::INSTANCE.call(context)
|
context.app = Kemal.application
|
||||||
Kemal::RouteHandler::INSTANCE.call(context)
|
Kemal.application.filter_handler.call(context)
|
||||||
|
Kemal.application.route_handler.call(context)
|
||||||
context.get?("non_existent_key").should be_nil
|
context.store["key"].should eq "value"
|
||||||
context.get?("another_non_existent_key").should be_nil
|
context.store["before_get"].should eq "Kemal"
|
||||||
end
|
context.store["before_get_int"].should eq 123
|
||||||
|
context.store["before_get_float"].should eq 3.5
|
||||||
|
context.store["before_get_context_test"].as(TestContextStorageType).id.should eq 32
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require "./spec_helper"
|
require "./spec_helper"
|
||||||
|
|
||||||
|
private INSTANCE = Kemal::ExceptionHandler.new
|
||||||
|
|
||||||
describe "Kemal::ExceptionHandler" do
|
describe "Kemal::ExceptionHandler" do
|
||||||
it "renders 404 on route not found" do
|
it "renders 404 on route not found" do
|
||||||
get "/" do
|
get "/" do
|
||||||
|
@ -10,7 +12,7 @@ describe "Kemal::ExceptionHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::ExceptionHandler::INSTANCE.call(context)
|
INSTANCE.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -28,8 +30,9 @@ describe "Kemal::ExceptionHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::ExceptionHandler::INSTANCE.next = Kemal::RouteHandler::INSTANCE
|
context.app = Kemal.application
|
||||||
Kemal::ExceptionHandler::INSTANCE.call(context)
|
INSTANCE.next = Kemal::RouteHandler.new
|
||||||
|
INSTANCE.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -49,8 +52,9 @@ describe "Kemal::ExceptionHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::ExceptionHandler::INSTANCE.next = Kemal::RouteHandler::INSTANCE
|
context.app = Kemal.application
|
||||||
Kemal::ExceptionHandler::INSTANCE.call(context)
|
INSTANCE.next = Kemal::RouteHandler.new
|
||||||
|
INSTANCE.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -71,8 +75,9 @@ describe "Kemal::ExceptionHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::ExceptionHandler::INSTANCE.next = Kemal::RouteHandler::INSTANCE
|
context.app = Kemal.application
|
||||||
Kemal::ExceptionHandler::INSTANCE.call(context)
|
INSTANCE.next = Kemal::RouteHandler.new
|
||||||
|
INSTANCE.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
@ -93,8 +98,9 @@ describe "Kemal::ExceptionHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::ExceptionHandler::INSTANCE.next = Kemal::RouteHandler::INSTANCE
|
context.app = Kemal.application
|
||||||
Kemal::ExceptionHandler::INSTANCE.call(context)
|
INSTANCE.next = Kemal::RouteHandler.new
|
||||||
|
INSTANCE.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
response = HTTP::Client::Response.from_io(io, decompress: false)
|
response = HTTP::Client::Response.from_io(io, decompress: false)
|
||||||
|
|
|
@ -70,6 +70,7 @@ end
|
||||||
describe "Handler" do
|
describe "Handler" do
|
||||||
it "adds custom handler before before_*" do
|
it "adds custom handler before before_*" do
|
||||||
filter_middleware = Kemal::FilterHandler.new
|
filter_middleware = Kemal::FilterHandler.new
|
||||||
|
Kemal.application.add_filter_handler filter_middleware
|
||||||
filter_middleware._add_route_filter("GET", "/", :before) do |env|
|
filter_middleware._add_route_filter("GET", "/", :before) do |env|
|
||||||
env.response << " is"
|
env.response << " is"
|
||||||
end
|
end
|
||||||
|
@ -77,6 +78,8 @@ describe "Handler" do
|
||||||
filter_middleware._add_route_filter("GET", "/", :before) do |env|
|
filter_middleware._add_route_filter("GET", "/", :before) do |env|
|
||||||
env.response << " so"
|
env.response << " so"
|
||||||
end
|
end
|
||||||
|
Kemal.application.add_filter_handler filter_middleware
|
||||||
|
|
||||||
add_handler CustomTestHandler.new
|
add_handler CustomTestHandler.new
|
||||||
|
|
||||||
get "/" do
|
get "/" do
|
||||||
|
@ -141,21 +144,21 @@ describe "Handler" do
|
||||||
it "adds a handler at given position" do
|
it "adds a handler at given position" do
|
||||||
post_handler = PostOnlyHandler.new
|
post_handler = PostOnlyHandler.new
|
||||||
add_handler post_handler, 1
|
add_handler post_handler, 1
|
||||||
Kemal.config.setup
|
Kemal.application.setup
|
||||||
Kemal.config.handlers[1].should eq post_handler
|
Kemal.application.handlers[1].should eq post_handler
|
||||||
end
|
end
|
||||||
|
|
||||||
it "assigns custom handlers" do
|
it "assigns custom handlers" do
|
||||||
post_only_handler = PostOnlyHandler.new
|
post_only_handler = PostOnlyHandler.new
|
||||||
post_exclude_handler = PostExcludeHandler.new
|
post_exclude_handler = PostExcludeHandler.new
|
||||||
Kemal.config.handlers = [post_only_handler, post_exclude_handler]
|
Kemal.application.handlers = [post_only_handler, post_exclude_handler]
|
||||||
Kemal.config.handlers.should eq [post_only_handler, post_exclude_handler]
|
Kemal.application.handlers.should eq [post_only_handler, post_exclude_handler]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is able to use %w in macros" do
|
it "is able to use %w in macros" do
|
||||||
post_only_handler = PostOnlyHandlerPercentW.new
|
post_only_handler = PostOnlyHandlerPercentW.new
|
||||||
exclude_handler = ExcludeHandlerPercentW.new
|
exclude_handler = ExcludeHandlerPercentW.new
|
||||||
Kemal.config.handlers = [post_only_handler, exclude_handler]
|
Kemal.application.handlers = [post_only_handler, exclude_handler]
|
||||||
Kemal.config.handlers.should eq [post_only_handler, exclude_handler]
|
Kemal.application.handlers.should eq [post_only_handler, exclude_handler]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,21 +11,21 @@ describe "Macros" do
|
||||||
describe "#add_handler" do
|
describe "#add_handler" do
|
||||||
it "adds a custom handler" do
|
it "adds a custom handler" do
|
||||||
add_handler CustomTestHandler.new
|
add_handler CustomTestHandler.new
|
||||||
Kemal.config.setup
|
Kemal.application.setup
|
||||||
Kemal.config.handlers.size.should eq 7
|
Kemal.application.handlers.size.should eq 7
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#logging" do
|
describe "#logging" do
|
||||||
it "sets logging status" do
|
it "sets logging status" do
|
||||||
logging false
|
logging false
|
||||||
Kemal.config.logging.should eq false
|
Kemal.config.logging?.should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets a custom logger" do
|
it "sets a custom logger" do
|
||||||
config = Kemal::Config::INSTANCE
|
config = Kemal.config
|
||||||
logger CustomLogHandler.new
|
logger CustomLogHandler.new
|
||||||
config.logger.should be_a(CustomLogHandler)
|
Kemal.application.logger.should be_a(CustomLogHandler)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -119,24 +119,24 @@ describe "Macros" do
|
||||||
describe "#gzip" do
|
describe "#gzip" do
|
||||||
it "adds HTTP::CompressHandler to handlers" do
|
it "adds HTTP::CompressHandler to handlers" do
|
||||||
gzip true
|
gzip true
|
||||||
Kemal.config.setup
|
Kemal.application.setup
|
||||||
Kemal.config.handlers[4].should be_a(HTTP::CompressHandler)
|
Kemal.application.handlers[4].should be_a(HTTP::CompressHandler)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#serve_static" do
|
describe "#serve_static" do
|
||||||
it "should disable static file hosting" do
|
it "should disable static file hosting" do
|
||||||
serve_static false
|
serve_static false
|
||||||
Kemal.config.serve_static.should eq false
|
Kemal.config.serve_static.should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should disble enable gzip and dir_listing" do
|
it "should disble enable gzip and dir_listing" do
|
||||||
serve_static({"gzip" => true, "dir_listing" => true})
|
serve_static({"gzip" => true, "dir_listing" => true})
|
||||||
conf = Kemal.config.serve_static
|
conf = Kemal.config.serve_static
|
||||||
conf.is_a?(Hash).should eq true
|
conf.is_a?(Hash).should be_true # Can't use be_a(Hash) because Hash can't be used as generic argument
|
||||||
if conf.is_a?(Hash)
|
if conf.is_a?(Hash)
|
||||||
conf["gzip"].should eq true
|
conf["gzip"].should be_true
|
||||||
conf["dir_listing"].should eq true
|
conf["dir_listing"].should be_true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,8 +6,9 @@ describe "Kemal::InitHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::InitHandler::INSTANCE.next = ->(_context : HTTP::Server::Context) {}
|
init_handler = Kemal::InitHandler.new(Kemal::Base.new)
|
||||||
Kemal::InitHandler::INSTANCE.call(context)
|
init_handler.next = ->(context : HTTP::Server::Context) {}
|
||||||
|
init_handler.call(context)
|
||||||
context.response.headers["Content-Type"].should eq "text/html"
|
context.response.headers["Content-Type"].should eq "text/html"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,7 +17,8 @@ describe "Kemal::InitHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
Kemal::InitHandler::INSTANCE.call(context)
|
init_handler = Kemal::InitHandler.new(Kemal::Base.new)
|
||||||
|
init_handler.call(context)
|
||||||
context.response.headers["X-Powered-By"].should eq "Kemal"
|
context.response.headers["X-Powered-By"].should eq "Kemal"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe "Kemal::FilterHandler" do
|
||||||
filter_middleware = Kemal::FilterHandler.new
|
filter_middleware = Kemal::FilterHandler.new
|
||||||
filter_middleware._add_route_filter("GET", "/greetings", :before) { test_filter.modified = "true" }
|
filter_middleware._add_route_filter("GET", "/greetings", :before) { test_filter.modified = "true" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
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")
|
||||||
|
@ -26,7 +26,7 @@ describe "Kemal::FilterHandler" do
|
||||||
filter_middleware = Kemal::FilterHandler.new
|
filter_middleware = Kemal::FilterHandler.new
|
||||||
filter_middleware._add_route_filter("GET", "/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" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ describe "Kemal::FilterHandler" do
|
||||||
filter_middleware._add_route_filter("GET", "/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" }
|
filter_middleware._add_route_filter("POST", "/greetings", :before) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ describe "Kemal::FilterHandler" do
|
||||||
filter_middleware = Kemal::FilterHandler.new
|
filter_middleware = Kemal::FilterHandler.new
|
||||||
filter_middleware._add_route_filter("GET", "/greetings", :after) { test_filter.modified = "true" }
|
filter_middleware._add_route_filter("GET", "/greetings", :after) { test_filter.modified = "true" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
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")
|
||||||
|
@ -98,7 +98,7 @@ describe "Kemal::FilterHandler" do
|
||||||
filter_middleware = Kemal::FilterHandler.new
|
filter_middleware = Kemal::FilterHandler.new
|
||||||
filter_middleware._add_route_filter("GET", "/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" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ describe "Kemal::FilterHandler" do
|
||||||
filter_middleware._add_route_filter("GET", "/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" }
|
filter_middleware._add_route_filter("POST", "/greetings", :after) { test_filter.modified = test_filter.modified == "true" ? "false" : "true" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
kemal.add_route "POST", "/greetings" { test_filter.modified }
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ describe "Kemal::FilterHandler" do
|
||||||
filter_middleware._add_route_filter("ALL", "/greetings", :before) { test_filter_second.modified = test_filter_second.modified == "true" ? "false" : "true" }
|
filter_middleware._add_route_filter("ALL", "/greetings", :before) { test_filter_second.modified = test_filter_second.modified == "true" ? "false" : "true" }
|
||||||
filter_middleware._add_route_filter("ALL", "/greetings", :before) { test_filter_third.modified = test_filter_third.modified == "true" ? "false" : "true" }
|
filter_middleware._add_route_filter("ALL", "/greetings", :before) { test_filter_third.modified = test_filter_third.modified == "true" ? "false" : "true" }
|
||||||
|
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
kemal.add_route "GET", "/greetings" { test_filter.modified }
|
||||||
kemal.add_route "POST", "/greetings" { test_filter_second.modified }
|
kemal.add_route "POST", "/greetings" { test_filter_second.modified }
|
||||||
kemal.add_route "PUT", "/greetings" { test_filter_third.modified }
|
kemal.add_route "PUT", "/greetings" { test_filter_third.modified }
|
||||||
|
|
|
@ -22,7 +22,7 @@ describe "ParamParser" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "parses url params" do
|
it "parses url params" do
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
kemal.add_route "POST", "/hello/:hasan" do |env|
|
kemal.add_route "POST", "/hello/:hasan" do |env|
|
||||||
"hello #{env.params.url["hasan"]}"
|
"hello #{env.params.url["hasan"]}"
|
||||||
end
|
end
|
||||||
|
@ -34,7 +34,7 @@ describe "ParamParser" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "decodes url params" do
|
it "decodes url params" do
|
||||||
kemal = Kemal::RouteHandler::INSTANCE
|
kemal = Kemal.application.route_handler
|
||||||
kemal.add_route "POST", "/hello/:email/:money/:spanish" do |env|
|
kemal.add_route "POST", "/hello/:email/:money/:spanish" do |env|
|
||||||
email = env.params.url["email"]
|
email = env.params.url["email"]
|
||||||
money = env.params.url["money"]
|
money = env.params.url["money"]
|
||||||
|
|
|
@ -17,32 +17,19 @@ end
|
||||||
|
|
||||||
describe "Run" do
|
describe "Run" do
|
||||||
it "runs a code block after starting" do
|
it "runs a code block after starting" do
|
||||||
run(<<-CR).should eq "started\nstopped\n"
|
|
||||||
Kemal.config.env = "test"
|
Kemal.config.env = "test"
|
||||||
|
make_me_true = false
|
||||||
Kemal.run do
|
Kemal.run do
|
||||||
puts "started"
|
make_me_true = true
|
||||||
Kemal.stop
|
Kemal.stop
|
||||||
puts "stopped"
|
|
||||||
end
|
end
|
||||||
CR
|
make_me_true.should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "runs without a block being specified" do
|
it "runs without a block being specified" do
|
||||||
run(<<-CR).should eq "[test] Kemal is ready to lead at http://0.0.0.0:3000\ntrue\n"
|
|
||||||
Kemal.config.env = "test"
|
Kemal.config.env = "test"
|
||||||
Kemal.run
|
Kemal.run
|
||||||
puts Kemal.config.running
|
Kemal.application.running?.should be_true
|
||||||
CR
|
Kemal.stop
|
||||||
end
|
|
||||||
|
|
||||||
it "allows custom HTTP::Server bind" do
|
|
||||||
run(<<-CR).should eq "[test] Kemal is ready to lead at http://127.0.0.1:3000, http://0.0.0.0:3001\n"
|
|
||||||
Kemal.config.env = "test"
|
|
||||||
Kemal.run do |config|
|
|
||||||
server = config.server.not_nil!
|
|
||||||
server.bind_tcp "127.0.0.1", 3000, reuse_port: true
|
|
||||||
server.bind_tcp "0.0.0.0", 3001, reuse_port: true
|
|
||||||
end
|
|
||||||
CR
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require "spec"
|
require "spec"
|
||||||
require "../src/*"
|
require "../src/**"
|
||||||
|
require "../src/kemal/base"
|
||||||
|
require "../src/kemal/dsl"
|
||||||
|
|
||||||
include Kemal
|
include Kemal
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ def create_request_and_return_io_and_context(handler, request)
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
|
context.app = Kemal.application
|
||||||
handler.call(context)
|
handler.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
|
@ -43,6 +46,7 @@ def create_ws_request_and_return_io_and_context(handler, request)
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
|
context.app = Kemal.application
|
||||||
begin
|
begin
|
||||||
handler.call context
|
handler.call context
|
||||||
rescue IO::Error
|
rescue IO::Error
|
||||||
|
@ -64,10 +68,10 @@ def call_request_on_app(request)
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_main_handler
|
def build_main_handler
|
||||||
Kemal.config.setup
|
Kemal.application.setup
|
||||||
main_handler = Kemal.config.handlers.first
|
main_handler = Kemal.application.handlers.first
|
||||||
current_handler = main_handler
|
current_handler = main_handler
|
||||||
Kemal.config.handlers.each do |handler|
|
Kemal.application.handlers.each_with_index do |handler, index|
|
||||||
current_handler.next = handler
|
current_handler.next = handler
|
||||||
current_handler = handler
|
current_handler = handler
|
||||||
end
|
end
|
||||||
|
@ -81,8 +85,5 @@ Spec.before_each do
|
||||||
end
|
end
|
||||||
|
|
||||||
Spec.after_each do
|
Spec.after_each do
|
||||||
Kemal.config.clear
|
Kemal.application.clear
|
||||||
Kemal::RouteHandler::INSTANCE.routes = Radix::Tree(Route).new
|
|
||||||
Kemal::RouteHandler::INSTANCE.cached_routes = Hash(String, Radix::Result(Route)).new
|
|
||||||
Kemal::WebSocketHandler::INSTANCE.routes = Radix::Tree(WebSocket).new
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,8 @@ require "./spec_helper"
|
||||||
|
|
||||||
describe "Kemal::WebSocketHandler" do
|
describe "Kemal::WebSocketHandler" do
|
||||||
it "doesn't match on wrong route" do
|
it "doesn't match on wrong route" do
|
||||||
handler = Kemal::WebSocketHandler::INSTANCE
|
handler = Kemal::WebSocketHandler.new
|
||||||
handler.next = Kemal::RouteHandler::INSTANCE
|
handler.next = Kemal::RouteHandler.new
|
||||||
ws "/" { }
|
ws "/" { }
|
||||||
headers = HTTP::Headers{
|
headers = HTTP::Headers{
|
||||||
"Upgrade" => "websocket",
|
"Upgrade" => "websocket",
|
||||||
|
@ -14,6 +14,7 @@ describe "Kemal::WebSocketHandler" do
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
|
context.app = Kemal.application
|
||||||
|
|
||||||
expect_raises(Kemal::Exceptions::RouteNotFound) do
|
expect_raises(Kemal::Exceptions::RouteNotFound) do
|
||||||
handler.call context
|
handler.call context
|
||||||
|
@ -21,9 +22,9 @@ describe "Kemal::WebSocketHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "matches on given route" do
|
it "matches on given route" do
|
||||||
handler = Kemal::WebSocketHandler::INSTANCE
|
handler = Kemal::WebSocketHandler.new
|
||||||
ws "/" { |socket| socket.send("Match") }
|
ws "/" { |socket, context| socket.send("Match") }
|
||||||
ws "/no_match" { |socket| socket.send "No Match" }
|
ws "/no_match" { |socket, context| socket.send "No Match" }
|
||||||
headers = HTTP::Headers{
|
headers = HTTP::Headers{
|
||||||
"Upgrade" => "websocket",
|
"Upgrade" => "websocket",
|
||||||
"Connection" => "Upgrade",
|
"Connection" => "Upgrade",
|
||||||
|
@ -37,8 +38,8 @@ describe "Kemal::WebSocketHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fetches named url parameters" do
|
it "fetches named url parameters" do
|
||||||
handler = Kemal::WebSocketHandler::INSTANCE
|
handler = Kemal::WebSocketHandler.new
|
||||||
ws "/:id" { |_, c| c.ws_route_lookup.params["id"] }
|
ws "/:id" { |s, c| c.params.url["id"] }
|
||||||
headers = HTTP::Headers{
|
headers = HTTP::Headers{
|
||||||
"Upgrade" => "websocket",
|
"Upgrade" => "websocket",
|
||||||
"Connection" => "Upgrade",
|
"Connection" => "Upgrade",
|
||||||
|
@ -51,14 +52,15 @@ describe "Kemal::WebSocketHandler" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "matches correct verb" do
|
it "matches correct verb" do
|
||||||
handler = Kemal::WebSocketHandler::INSTANCE
|
handler = Kemal::WebSocketHandler.new
|
||||||
handler.next = Kemal::RouteHandler::INSTANCE
|
handler.next = Kemal::RouteHandler.new
|
||||||
ws "/" { }
|
ws "/" { }
|
||||||
get "/" { "get" }
|
get "/" { "get" }
|
||||||
request = HTTP::Request.new("GET", "/")
|
request = HTTP::Request.new("GET", "/")
|
||||||
io = IO::Memory.new
|
io = IO::Memory.new
|
||||||
response = HTTP::Server::Response.new(io)
|
response = HTTP::Server::Response.new(io)
|
||||||
context = HTTP::Server::Context.new(request, response)
|
context = HTTP::Server::Context.new(request, response)
|
||||||
|
context.app = Kemal.application
|
||||||
handler.call(context)
|
handler.call(context)
|
||||||
response.close
|
response.close
|
||||||
io.rewind
|
io.rewind
|
||||||
|
|
100
src/kemal.cr
100
src/kemal.cr
|
@ -1,98 +1,2 @@
|
||||||
require "http"
|
require "./kemal/base"
|
||||||
require "json"
|
require "./kemal/dsl"
|
||||||
require "uri"
|
|
||||||
require "./kemal/*"
|
|
||||||
require "./kemal/ext/*"
|
|
||||||
require "./kemal/helpers/*"
|
|
||||||
|
|
||||||
module Kemal
|
|
||||||
# Overload of `self.run` with the default startup logging.
|
|
||||||
def self.run(port : Int32?, args = ARGV)
|
|
||||||
self.run(port, args) { }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Overload of `self.run` without port.
|
|
||||||
def self.run(args = ARGV)
|
|
||||||
self.run(nil, args: args)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Overload of `self.run` to allow just a block.
|
|
||||||
def self.run(args = ARGV, &block)
|
|
||||||
self.run(nil, args: args, &block)
|
|
||||||
end
|
|
||||||
|
|
||||||
# The command to run a `Kemal` application.
|
|
||||||
#
|
|
||||||
# If *port* is not given Kemal will use `Kemal::Config#port`
|
|
||||||
#
|
|
||||||
# To use custom command line arguments, set args to nil
|
|
||||||
#
|
|
||||||
def self.run(port : Int32? = nil, args = ARGV, &block)
|
|
||||||
Kemal::CLI.new args
|
|
||||||
config = Kemal.config
|
|
||||||
config.setup
|
|
||||||
config.port = port if port
|
|
||||||
|
|
||||||
# Test environment doesn't need to have signal trap and logging.
|
|
||||||
if config.env != "test"
|
|
||||||
setup_404
|
|
||||||
setup_trap_signal
|
|
||||||
end
|
|
||||||
|
|
||||||
server = config.server ||= HTTP::Server.new(config.handlers)
|
|
||||||
|
|
||||||
config.running = true
|
|
||||||
|
|
||||||
yield config
|
|
||||||
|
|
||||||
# Abort if block called `Kemal.stop`
|
|
||||||
return unless config.running
|
|
||||||
|
|
||||||
unless server.each_address { |_| break true }
|
|
||||||
{% if flag?(:without_openssl) %}
|
|
||||||
server.bind_tcp(config.host_binding, config.port)
|
|
||||||
{% else %}
|
|
||||||
if ssl = config.ssl
|
|
||||||
server.bind_tls(config.host_binding, config.port, ssl)
|
|
||||||
else
|
|
||||||
server.bind_tcp(config.host_binding, config.port)
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
end
|
|
||||||
|
|
||||||
display_startup_message(config, server)
|
|
||||||
|
|
||||||
server.listen unless config.env == "test"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.display_startup_message(config, server)
|
|
||||||
addresses = server.addresses.map { |address| "#{config.scheme}://#{address}" }.join ", "
|
|
||||||
log "[#{config.env}] Kemal is ready to lead at #{addresses}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.stop
|
|
||||||
raise "Kemal is already stopped." if !config.running
|
|
||||||
if server = config.server
|
|
||||||
server.close unless server.closed?
|
|
||||||
config.running = false
|
|
||||||
else
|
|
||||||
raise "Kemal.config.server is not set. Please use Kemal.run to set the server."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def self.setup_404
|
|
||||||
unless Kemal.config.error_handlers.has_key?(404)
|
|
||||||
error 404 do
|
|
||||||
render_404
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def self.setup_trap_signal
|
|
||||||
Signal::INT.trap do
|
|
||||||
log "Kemal is going to take a rest!" if Kemal.config.shutdown_message
|
|
||||||
Kemal.stop
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
227
src/kemal/base.cr
Normal file
227
src/kemal/base.cr
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
# Kemal Base
|
||||||
|
# The DSL currently consists of
|
||||||
|
# - get post put patch delete options
|
||||||
|
# - WebSocket(ws)
|
||||||
|
# - before_*
|
||||||
|
# - error
|
||||||
|
class Kemal::Base
|
||||||
|
HTTP_METHODS = %w(get post put patch delete options)
|
||||||
|
FILTER_METHODS = %w(get post put patch delete options all)
|
||||||
|
|
||||||
|
getter route_handler = Kemal::RouteHandler.new
|
||||||
|
getter filter_handler = Kemal::FilterHandler.new
|
||||||
|
getter websocket_handler = Kemal::WebSocketHandler.new
|
||||||
|
|
||||||
|
getter handlers = [] of HTTP::Handler
|
||||||
|
getter custom_handlers = [] of Tuple(Nil | Int32, HTTP::Handler)
|
||||||
|
getter filter_handlers = [] of HTTP::Handler
|
||||||
|
getter error_handlers = {} of Int32 => HTTP::Server::Context, Exception -> String
|
||||||
|
@handler_position = 0
|
||||||
|
|
||||||
|
getter config : Config
|
||||||
|
|
||||||
|
property! logger : Kemal::BaseLogHandler
|
||||||
|
property! server : HTTP::Server
|
||||||
|
property? running = false
|
||||||
|
|
||||||
|
def initialize(@config = Config.new)
|
||||||
|
@logger = if @config.logging?
|
||||||
|
Kemal::LogHandler.new
|
||||||
|
else
|
||||||
|
Kemal::NullLogHandler.new
|
||||||
|
end
|
||||||
|
add_filter_handler(filter_handler)
|
||||||
|
end
|
||||||
|
|
||||||
|
{% for method in HTTP_METHODS %}
|
||||||
|
def {{method.id}}(path, &block : HTTP::Server::Context -> _)
|
||||||
|
raise Kemal::Exceptions::InvalidPathStartException.new({{method}}, path) unless Kemal::Utils.path_starts_with_slash?(path)
|
||||||
|
route_handler.add_route({{method}}.upcase, path, &block)
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
def ws(path, &block : HTTP::WebSocket, HTTP::Server::Context -> Void)
|
||||||
|
raise Kemal::Exceptions::InvalidPathStartException.new("ws", path) unless Kemal::Utils.path_starts_with_slash?(path)
|
||||||
|
websocket_handler.add_route path, &block
|
||||||
|
end
|
||||||
|
|
||||||
|
def error(status_code, &block : HTTP::Server::Context, Exception -> _)
|
||||||
|
add_error_handler status_code, &block
|
||||||
|
end
|
||||||
|
|
||||||
|
# All the helper methods available are:
|
||||||
|
# - before_all, before_get, before_post, before_put, before_patch, before_delete, before_options
|
||||||
|
# - after_all, after_get, after_post, after_put, after_patch, after_delete, after_options
|
||||||
|
{% for type in ["before", "after"] %}
|
||||||
|
{% for method in FILTER_METHODS %}
|
||||||
|
def {{type.id}}_{{method.id}}(path = "*", &block : HTTP::Server::Context -> _)
|
||||||
|
filter_handler.{{type.id}}({{method}}.upcase, path, &block)
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
def clear
|
||||||
|
@router_included = false
|
||||||
|
@handler_position = 0
|
||||||
|
@default_handlers_setup = false
|
||||||
|
|
||||||
|
handlers.clear
|
||||||
|
custom_handlers.clear
|
||||||
|
filter_handlers.clear
|
||||||
|
error_handlers.clear
|
||||||
|
|
||||||
|
route_handler.clear
|
||||||
|
websocket_handler.clear
|
||||||
|
end
|
||||||
|
|
||||||
|
def handlers=(handlers : Array(HTTP::Handler))
|
||||||
|
clear
|
||||||
|
@handlers.replace(handlers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_handler(handler : HTTP::Handler)
|
||||||
|
@custom_handlers << {nil, handler}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_handler(handler : HTTP::Handler, position : Int32)
|
||||||
|
@custom_handlers << {position, handler}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_filter_handler(handler : HTTP::Handler)
|
||||||
|
@filter_handlers << handler
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_error_handler(status_code, &handler : HTTP::Server::Context, Exception -> _)
|
||||||
|
@error_handlers[status_code] = ->(context : HTTP::Server::Context, error : Exception) { handler.call(context, error).to_s }
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
unless @default_handlers_setup && @router_included
|
||||||
|
setup_init_handler
|
||||||
|
setup_log_handler
|
||||||
|
setup_error_handler
|
||||||
|
setup_static_file_handler
|
||||||
|
setup_custom_handlers
|
||||||
|
setup_filter_handlers
|
||||||
|
@default_handlers_setup = true
|
||||||
|
@router_included = true
|
||||||
|
handlers.insert(handlers.size, websocket_handler)
|
||||||
|
handlers.insert(handlers.size, route_handler)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def setup_init_handler
|
||||||
|
@handlers.insert(@handler_position, Kemal::InitHandler.new(self))
|
||||||
|
@handler_position += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
private def setup_log_handler
|
||||||
|
@handlers.insert(@handler_position, logger)
|
||||||
|
@handler_position += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
private def setup_error_handler
|
||||||
|
if @config.always_rescue?
|
||||||
|
@error_handler ||= Kemal::ExceptionHandler.new
|
||||||
|
@handlers.insert(@handler_position, @error_handler.not_nil!)
|
||||||
|
@handler_position += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def setup_static_file_handler
|
||||||
|
if @config.serve_static.is_a?(Hash)
|
||||||
|
@handlers.insert(@handler_position, Kemal::StaticFileHandler.new(@config.public_folder))
|
||||||
|
@handler_position += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def setup_custom_handlers
|
||||||
|
@custom_handlers.each do |ch|
|
||||||
|
position = ch[0]
|
||||||
|
if !position
|
||||||
|
@handlers.insert(@handler_position, ch[1])
|
||||||
|
@handler_position += 1
|
||||||
|
else
|
||||||
|
@handlers.insert(position, ch[1])
|
||||||
|
@handler_position += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def setup_filter_handlers
|
||||||
|
@filter_handlers.each do |h|
|
||||||
|
@handlers.insert(@handler_position, h)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Overload of self.run with the default startup logging
|
||||||
|
def run(port = nil)
|
||||||
|
run port do
|
||||||
|
log "[#{config.env}] Kemal is ready to lead at #{config.scheme}://#{config.host_binding}:#{config.port}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Overload of self.run to allow just a block
|
||||||
|
def run(&block)
|
||||||
|
run nil, &block
|
||||||
|
end
|
||||||
|
|
||||||
|
# The command to run a `Kemal` application.
|
||||||
|
# The port can be given to `#run` but is optional.
|
||||||
|
# If not given Kemal will use `Kemal::Config#port`
|
||||||
|
def run(port = nil, &block)
|
||||||
|
@config.port = port if port
|
||||||
|
|
||||||
|
setup
|
||||||
|
|
||||||
|
@server = server = HTTP::Server.new(@config.host_binding, @config.port, @handlers)
|
||||||
|
{% if !flag?(:without_openssl) %}
|
||||||
|
server.tls = config.ssl
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
unless error_handlers.has_key?(404)
|
||||||
|
error 404 do |env|
|
||||||
|
render_404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test environment doesn't need to have signal trap, built-in images, and logging.
|
||||||
|
unless config.env == "test"
|
||||||
|
Signal::INT.trap do
|
||||||
|
log "Kemal is going to take a rest!" if config.shutdown_message?
|
||||||
|
Kemal.stop if running?
|
||||||
|
exit
|
||||||
|
end
|
||||||
|
|
||||||
|
# This route serves the built-in images for not_found and exceptions.
|
||||||
|
get "/__kemal__/:image" do |env|
|
||||||
|
image = env.params.url["image"]
|
||||||
|
file_path = File.expand_path("lib/kemal/images/#{image}", Dir.current)
|
||||||
|
if File.exists? file_path
|
||||||
|
send_file env, file_path
|
||||||
|
else
|
||||||
|
halt env, 404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@running = true
|
||||||
|
|
||||||
|
yield self
|
||||||
|
|
||||||
|
server.listen if @config.env != "test"
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop
|
||||||
|
if @running
|
||||||
|
if server = @server
|
||||||
|
server.close
|
||||||
|
@running = false
|
||||||
|
else
|
||||||
|
raise "server is not set. Please use run to set the server."
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise "Kemal is already stopped."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,3 +1,5 @@
|
||||||
|
require "http"
|
||||||
|
|
||||||
module Kemal
|
module Kemal
|
||||||
# All loggers must inherit from `Kemal::BaseLogHandler`.
|
# All loggers must inherit from `Kemal::BaseLogHandler`.
|
||||||
abstract class BaseLogHandler
|
abstract class BaseLogHandler
|
||||||
|
|
|
@ -3,11 +3,10 @@ require "option_parser"
|
||||||
module Kemal
|
module Kemal
|
||||||
# Handles all the initialization from the command line.
|
# Handles all the initialization from the command line.
|
||||||
class CLI
|
class CLI
|
||||||
def initialize(args)
|
def initialize(args, @config : Config = Kemal.config)
|
||||||
@ssl_enabled = false
|
@ssl_enabled = false
|
||||||
@key_file = ""
|
@key_file = ""
|
||||||
@cert_file = ""
|
@cert_file = ""
|
||||||
@config = Kemal.config
|
|
||||||
read_env
|
read_env
|
||||||
if args
|
if args
|
||||||
parse args
|
parse args
|
||||||
|
|
|
@ -8,161 +8,50 @@ module Kemal
|
||||||
# Kemal.config
|
# Kemal.config
|
||||||
# ```
|
# ```
|
||||||
class Config
|
class Config
|
||||||
INSTANCE = Config.new
|
property host_binding = "0.0.0.0"
|
||||||
HANDLERS = [] of HTTP::Handler
|
property port = 3000
|
||||||
CUSTOM_HANDLERS = [] of Tuple(Nil | Int32, HTTP::Handler)
|
|
||||||
FILTER_HANDLERS = [] of HTTP::Handler
|
|
||||||
ERROR_HANDLERS = {} of Int32 => HTTP::Server::Context, Exception -> String
|
|
||||||
|
|
||||||
{% if flag?(:without_openssl) %}
|
{% if flag?(:without_openssl) %}
|
||||||
@ssl : Bool?
|
property ssl : Bool?
|
||||||
{% else %}
|
{% else %}
|
||||||
@ssl : OpenSSL::SSL::Context::Server?
|
property ssl : OpenSSL::SSL::Context::Server?
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
property host_binding, ssl, port, env, public_folder, logging, running
|
|
||||||
property always_rescue, server : HTTP::Server?, extra_options, shutdown_message
|
|
||||||
property serve_static : (Bool | Hash(String, Bool))
|
property serve_static : (Bool | Hash(String, Bool))
|
||||||
property static_headers : (HTTP::Server::Response, String, File::Info -> Void)?
|
property static_headers : (HTTP::Server::Response, String, File::Info -> Void)?
|
||||||
property powered_by_header : Bool = true
|
property powered_by_header : Bool = true
|
||||||
|
property env = "development"
|
||||||
|
property serve_static : Hash(String, Bool) | Bool = {"dir_listing" => false, "gzip" => true}
|
||||||
|
property public_folder = "./public"
|
||||||
|
property? logging = true
|
||||||
|
property? always_rescue = true
|
||||||
|
property? shutdown_message = true
|
||||||
|
property extra_options : (OptionParser ->)?
|
||||||
|
|
||||||
def initialize
|
# Creates a config with default values.
|
||||||
@host_binding = "0.0.0.0"
|
def initialize(
|
||||||
@port = 3000
|
@host_binding = "0.0.0.0",
|
||||||
@env = "development"
|
@port = 3000,
|
||||||
@serve_static = {"dir_listing" => false, "gzip" => true}
|
@ssl = nil,
|
||||||
@public_folder = "./public"
|
@env = "development",
|
||||||
@logging = true
|
@serve_static = {"dir_listing" => false, "gzip" => true},
|
||||||
@logger = nil
|
@public_folder = "./public",
|
||||||
@error_handler = nil
|
@logging = true,
|
||||||
@always_rescue = true
|
@always_rescue = true,
|
||||||
@router_included = false
|
@shutdown_message = true,
|
||||||
@default_handlers_setup = false
|
@extra_options = nil,
|
||||||
@running = false
|
static_headers = nil)
|
||||||
@shutdown_message = true
|
|
||||||
@handler_position = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def logger
|
|
||||||
@logger.not_nil!
|
|
||||||
end
|
|
||||||
|
|
||||||
def logger=(logger : Kemal::BaseLogHandler)
|
|
||||||
@logger = logger
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def scheme
|
def scheme
|
||||||
ssl ? "https" : "http"
|
ssl ? "https" : "http"
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear
|
|
||||||
@powered_by_header = true
|
|
||||||
@router_included = false
|
|
||||||
@handler_position = 0
|
|
||||||
@default_handlers_setup = false
|
|
||||||
HANDLERS.clear
|
|
||||||
CUSTOM_HANDLERS.clear
|
|
||||||
FILTER_HANDLERS.clear
|
|
||||||
ERROR_HANDLERS.clear
|
|
||||||
end
|
|
||||||
|
|
||||||
def handlers
|
|
||||||
HANDLERS
|
|
||||||
end
|
|
||||||
|
|
||||||
def handlers=(handlers : Array(HTTP::Handler))
|
|
||||||
clear
|
|
||||||
HANDLERS.replace(handlers)
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_handler(handler : HTTP::Handler)
|
|
||||||
CUSTOM_HANDLERS << {nil, handler}
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_handler(handler : HTTP::Handler, position : Int32)
|
|
||||||
CUSTOM_HANDLERS << {position, handler}
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_filter_handler(handler : HTTP::Handler)
|
|
||||||
FILTER_HANDLERS << handler
|
|
||||||
end
|
|
||||||
|
|
||||||
def error_handlers
|
|
||||||
ERROR_HANDLERS
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_error_handler(status_code : Int32, &handler : HTTP::Server::Context, Exception -> _)
|
|
||||||
ERROR_HANDLERS[status_code] = ->(context : HTTP::Server::Context, error : Exception) { handler.call(context, error).to_s }
|
|
||||||
end
|
|
||||||
|
|
||||||
def extra_options(&@extra_options : OptionParser ->)
|
def extra_options(&@extra_options : OptionParser ->)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup
|
def serve_static?(key)
|
||||||
unless @default_handlers_setup && @router_included
|
config = @serve_static
|
||||||
setup_init_handler
|
config.try(&.[key]?) || config == true
|
||||||
setup_log_handler
|
|
||||||
setup_error_handler
|
|
||||||
setup_static_file_handler
|
|
||||||
setup_custom_handlers
|
|
||||||
setup_filter_handlers
|
|
||||||
@default_handlers_setup = true
|
|
||||||
@router_included = true
|
|
||||||
HANDLERS.insert(HANDLERS.size, Kemal::WebSocketHandler::INSTANCE)
|
|
||||||
HANDLERS.insert(HANDLERS.size, Kemal::RouteHandler::INSTANCE)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def setup_init_handler
|
|
||||||
HANDLERS.insert(@handler_position, Kemal::InitHandler::INSTANCE)
|
|
||||||
@handler_position += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
private def setup_log_handler
|
|
||||||
@logger ||= if @logging
|
|
||||||
Kemal::LogHandler.new
|
|
||||||
else
|
|
||||||
Kemal::NullLogHandler.new
|
|
||||||
end
|
|
||||||
HANDLERS.insert(@handler_position, @logger.not_nil!)
|
|
||||||
@handler_position += 1
|
|
||||||
end
|
|
||||||
|
|
||||||
private def setup_error_handler
|
|
||||||
if @always_rescue
|
|
||||||
@error_handler ||= Kemal::ExceptionHandler.new
|
|
||||||
HANDLERS.insert(@handler_position, @error_handler.not_nil!)
|
|
||||||
@handler_position += 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def setup_static_file_handler
|
|
||||||
if @serve_static.is_a?(Hash)
|
|
||||||
HANDLERS.insert(@handler_position, Kemal::StaticFileHandler.new(@public_folder))
|
|
||||||
@handler_position += 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def setup_custom_handlers
|
|
||||||
CUSTOM_HANDLERS.each do |ch0, ch1|
|
|
||||||
position = ch0
|
|
||||||
HANDLERS.insert (position || @handler_position), ch1
|
|
||||||
@handler_position += 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def setup_filter_handlers
|
|
||||||
FILTER_HANDLERS.each do |h|
|
|
||||||
HANDLERS.insert(@handler_position, h)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.config
|
|
||||||
yield Config::INSTANCE
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.config
|
|
||||||
Config::INSTANCE
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,32 +6,28 @@
|
||||||
# - WebSocket(ws)
|
# - WebSocket(ws)
|
||||||
# - before_*
|
# - before_*
|
||||||
# - error
|
# - error
|
||||||
HTTP_METHODS = %w(get post put patch delete options)
|
|
||||||
FILTER_METHODS = %w(get post put patch delete options all)
|
|
||||||
|
|
||||||
{% for method in HTTP_METHODS %}
|
{% for method in Kemal::Base::HTTP_METHODS %}
|
||||||
def {{method.id}}(path : String, &block : HTTP::Server::Context -> _)
|
def {{method.id}}(path, &block : HTTP::Server::Context -> _)
|
||||||
raise Kemal::Exceptions::InvalidPathStartException.new({{method}}, path) unless Kemal::Utils.path_starts_with_slash?(path)
|
Kemal.application.{{method.id}}(path, &block)
|
||||||
Kemal::RouteHandler::INSTANCE.add_route({{method}}.upcase, path, &block)
|
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
def ws(path : String, &block : HTTP::WebSocket, HTTP::Server::Context -> Void)
|
def ws(path, &block : HTTP::WebSocket, HTTP::Server::Context -> Void)
|
||||||
raise Kemal::Exceptions::InvalidPathStartException.new("ws", path) unless Kemal::Utils.path_starts_with_slash?(path)
|
Kemal.application.ws(path, &block)
|
||||||
Kemal::WebSocketHandler::INSTANCE.add_route path, &block
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def error(status_code : Int32, &block : HTTP::Server::Context, Exception -> _)
|
def error(status_code, &block : HTTP::Server::Context, Exception -> _)
|
||||||
Kemal.config.add_error_handler status_code, &block
|
Kemal.application.add_error_handler status_code, &block
|
||||||
end
|
end
|
||||||
|
|
||||||
# All the helper methods available are:
|
# All the helper methods available are:
|
||||||
# - before_all, before_get, before_post, before_put, before_patch, before_delete, before_options
|
# - before_all, before_get, before_post, before_put, before_patch, before_delete, before_options
|
||||||
# - after_all, after_get, after_post, after_put, after_patch, after_delete, after_options
|
# - after_all, after_get, after_post, after_put, after_patch, after_delete, after_options
|
||||||
{% for type in ["before", "after"] %}
|
{% for type in ["before", "after"] %}
|
||||||
{% for method in FILTER_METHODS %}
|
{% for method in Kemal::Base::FILTER_METHODS %}
|
||||||
def {{type.id}}_{{method.id}}(path : String = "*", &block : HTTP::Server::Context -> _)
|
def {{type.id}}_{{method.id}}(path = "*", &block : HTTP::Server::Context -> _)
|
||||||
Kemal::FilterHandler::INSTANCE.{{type.id}}({{method}}.upcase, path, &block)
|
Kemal.application.{{type.id}}_{{method.id}}(path, &block)
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
|
@ -2,9 +2,9 @@ module Kemal
|
||||||
# Handles all the exceptions, including 404, custom errors and 500.
|
# Handles all the exceptions, including 404, custom errors and 500.
|
||||||
class ExceptionHandler
|
class ExceptionHandler
|
||||||
include HTTP::Handler
|
include HTTP::Handler
|
||||||
INSTANCE = new
|
|
||||||
|
|
||||||
def call(context : HTTP::Server::Context)
|
def call(context : HTTP::Server::Context)
|
||||||
|
begin
|
||||||
call_next(context)
|
call_next(context)
|
||||||
rescue ex : Kemal::Exceptions::RouteNotFound
|
rescue ex : Kemal::Exceptions::RouteNotFound
|
||||||
call_exception_with_status_code(context, ex, 404)
|
call_exception_with_status_code(context, ex, 404)
|
||||||
|
@ -12,15 +12,16 @@ module Kemal
|
||||||
call_exception_with_status_code(context, ex, context.response.status_code)
|
call_exception_with_status_code(context, ex, context.response.status_code)
|
||||||
rescue ex : Exception
|
rescue ex : Exception
|
||||||
log("Exception: #{ex.inspect_with_backtrace}")
|
log("Exception: #{ex.inspect_with_backtrace}")
|
||||||
return call_exception_with_status_code(context, ex, 500) if Kemal.config.error_handlers.has_key?(500)
|
return call_exception_with_status_code(context, ex, 500) if context.app.error_handlers.has_key?(500)
|
||||||
verbosity = Kemal.config.env == "production" ? false : true
|
verbosity = context.app.config.env == "production" ? false : true
|
||||||
return render_500(context, ex, verbosity)
|
return render_500(context, ex.inspect_with_backtrace, verbosity)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def call_exception_with_status_code(context : HTTP::Server::Context, exception : Exception, status_code : Int32)
|
private def call_exception_with_status_code(context, exception, status_code)
|
||||||
if !Kemal.config.error_handlers.empty? && Kemal.config.error_handlers.has_key?(status_code)
|
if context.app.error_handlers.has_key?(status_code)
|
||||||
context.response.content_type = "text/html" unless context.response.headers.has_key?("Content-Type")
|
context.response.content_type = "text/html" unless context.response.headers.has_key?("Content-Type")
|
||||||
context.response.print Kemal.config.error_handlers[status_code].call(context, exception)
|
context.response.print context.app.error_handlers[status_code].call(context, exception)
|
||||||
context.response.status_code = status_code
|
context.response.status_code = status_code
|
||||||
context
|
context
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,6 +8,8 @@ class HTTP::Server
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
STORE_MAPPINGS = [Nil, String, Int32, Int64, Float64, Bool]
|
STORE_MAPPINGS = [Nil, String, Int32, Int64, Float64, Bool]
|
||||||
|
|
||||||
|
property! app : Kemal::Base
|
||||||
|
|
||||||
macro finished
|
macro finished
|
||||||
alias StoreTypes = Union({{ *STORE_MAPPINGS }})
|
alias StoreTypes = Union({{ *STORE_MAPPINGS }})
|
||||||
@store = {} of String => StoreTypes
|
@store = {} of String => StoreTypes
|
||||||
|
@ -31,7 +33,7 @@ class HTTP::Server
|
||||||
end
|
end
|
||||||
|
|
||||||
def route_lookup
|
def route_lookup
|
||||||
Kemal::RouteHandler::INSTANCE.lookup_route(@request.method.as(String), @request.path)
|
app.route_handler.lookup_route(@request.override_method.as(String), @request.path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def route_found?
|
def route_found?
|
||||||
|
@ -39,7 +41,7 @@ class HTTP::Server
|
||||||
end
|
end
|
||||||
|
|
||||||
def ws_route_lookup
|
def ws_route_lookup
|
||||||
Kemal::WebSocketHandler::INSTANCE.lookup_ws_route(@request.path)
|
app.websocket_handler.lookup_ws_route(@request.path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def ws_route_found?
|
def ws_route_found?
|
||||||
|
|
|
@ -2,20 +2,18 @@ module Kemal
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
class FilterHandler
|
class FilterHandler
|
||||||
include HTTP::Handler
|
include 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.
|
# 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(Array(FilterBlock)).new
|
@tree = Radix::Tree(Array(FilterBlock)).new
|
||||||
Kemal.config.add_filter_handler(self)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# The call order of the filters is `before_all -> before_x -> X -> after_x -> after_all`.
|
# The call order of the filters is `before_all -> before_x -> X -> after_x -> after_all`.
|
||||||
def call(context : HTTP::Server::Context)
|
def call(context : HTTP::Server::Context)
|
||||||
return call_next(context) unless context.route_found?
|
return call_next(context) unless context.route_found?
|
||||||
call_block_for_path_type("ALL", context.request.path, :before, context)
|
call_block_for_path_type("ALL", context.request.path, :before, context)
|
||||||
call_block_for_path_type(context.request.method, context.request.path, :before, context)
|
call_block_for_path_type(context.request.override_method, context.request.path, :before, context)
|
||||||
if Kemal.config.error_handlers.has_key?(context.response.status_code)
|
if context.app.error_handlers.has_key?(context.response.status_code)
|
||||||
raise Kemal::Exceptions::CustomException.new(context)
|
raise Kemal::Exceptions::CustomException.new(context)
|
||||||
end
|
end
|
||||||
call_next(context)
|
call_next(context)
|
||||||
|
|
|
@ -7,13 +7,13 @@
|
||||||
# - `Kemal::ExceptionHandler`
|
# - `Kemal::ExceptionHandler`
|
||||||
# - `Kemal::StaticFileHandler`
|
# - `Kemal::StaticFileHandler`
|
||||||
# - Here goes custom handlers
|
# - Here goes custom handlers
|
||||||
# - `Kemal::RouteHandler`
|
# - Kemal::RouteHandler
|
||||||
def add_handler(handler : HTTP::Handler)
|
def add_handler(handler : HTTP::Handler)
|
||||||
Kemal.config.add_handler handler
|
Kemal.application.add_handler handler
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_handler(handler : HTTP::Handler, position : Int32)
|
def add_handler(handler : HTTP::Handler, position : Int32)
|
||||||
Kemal.config.add_handler handler, position
|
Kemal.application.add_handler handler, position
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sets public folder from which the static assets will be served.
|
# Sets public folder from which the static assets will be served.
|
||||||
|
@ -26,7 +26,7 @@ end
|
||||||
# Logs the output via `logger`.
|
# Logs the output via `logger`.
|
||||||
# This is the built-in `Kemal::LogHandler` by default which uses STDOUT.
|
# This is the built-in `Kemal::LogHandler` by default which uses STDOUT.
|
||||||
def log(message : String)
|
def log(message : String)
|
||||||
Kemal.config.logger.write "#{message}\n"
|
Kemal.application.logger.write "#{message}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enables / Disables logging.
|
# Enables / Disables logging.
|
||||||
|
@ -64,8 +64,8 @@ end
|
||||||
# logger MyCustomLogger.new
|
# logger MyCustomLogger.new
|
||||||
# ```
|
# ```
|
||||||
def logger(logger : Kemal::BaseLogHandler)
|
def logger(logger : Kemal::BaseLogHandler)
|
||||||
Kemal.config.logger = logger
|
Kemal.application.logger = logger
|
||||||
Kemal.config.add_handler logger
|
Kemal.application.add_handler logger
|
||||||
end
|
end
|
||||||
|
|
||||||
# Enables / Disables static file serving.
|
# Enables / Disables static file serving.
|
||||||
|
|
|
@ -4,11 +4,15 @@ module Kemal
|
||||||
class InitHandler
|
class InitHandler
|
||||||
include HTTP::Handler
|
include HTTP::Handler
|
||||||
|
|
||||||
INSTANCE = new
|
getter app : Kemal::Base
|
||||||
|
|
||||||
|
def initialize(@app)
|
||||||
|
end
|
||||||
|
|
||||||
def call(context : HTTP::Server::Context)
|
def call(context : HTTP::Server::Context)
|
||||||
context.response.headers.add "X-Powered-By", "Kemal" if Kemal.config.powered_by_header
|
context.response.headers.add "X-Powered-By", "Kemal" if Kemal.config.powered_by_header
|
||||||
context.response.content_type = "text/html" unless context.response.headers.has_key?("Content-Type")
|
context.response.content_type = "text/html" unless context.response.headers.has_key?("Content-Type")
|
||||||
|
context.app = app
|
||||||
call_next context
|
call_next context
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,7 +47,7 @@ module Kemal
|
||||||
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_found?
|
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_found?
|
||||||
content = context.route.handler.call(context)
|
content = context.route.handler.call(context)
|
||||||
|
|
||||||
if !Kemal.config.error_handlers.empty? && Kemal.config.error_handlers.has_key?(context.response.status_code)
|
if context.app.error_handlers.has_key?(context.response.status_code)
|
||||||
raise Kemal::Exceptions::CustomException.new(context)
|
raise Kemal::Exceptions::CustomException.new(context)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,5 +63,9 @@ module Kemal
|
||||||
node = radix_path method, path
|
node = radix_path method, path
|
||||||
@routes.add node, route
|
@routes.add node, route
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear
|
||||||
|
@routes = Radix::Tree(Route).new
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,6 @@ module Kemal
|
||||||
class WebSocketHandler
|
class WebSocketHandler
|
||||||
include HTTP::Handler
|
include HTTP::Handler
|
||||||
|
|
||||||
INSTANCE = new
|
|
||||||
property routes
|
property routes
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
@ -39,5 +38,9 @@ module Kemal
|
||||||
|
|
||||||
context.request.headers.includes_word?("Connection", "Upgrade")
|
context.request.headers.includes_word?("Connection", "Upgrade")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear
|
||||||
|
@routes = Radix::Tree(WebSocket).new
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue