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 |     request = HTTP::Request.new("GET", "/") | ||||||
|       get "/" { } |     io = IO::Memory.new | ||||||
| 
 |     response = HTTP::Server::Response.new(io) | ||||||
|       request = HTTP::Request.new("GET", "/") |     context = HTTP::Server::Context.new(request, response) | ||||||
|       io = IO::Memory.new |     context.app = Kemal.application | ||||||
|       response = HTTP::Server::Response.new(io) |     Kemal.application.filter_handler.call(context) | ||||||
|       context = HTTP::Server::Context.new(request, response) |     Kemal.application.route_handler.call(context) | ||||||
|       Kemal::FilterHandler::INSTANCE.call(context) |     context.store["key"].should eq "value" | ||||||
|       Kemal::RouteHandler::INSTANCE.call(context) |     context.store["before_get"].should eq "Kemal" | ||||||
| 
 |     context.store["before_get_int"].should eq 123 | ||||||
|       context.get?("non_existent_key").should be_nil |     context.store["before_get_float"].should eq 3.5 | ||||||
|       context.get?("another_non_existent_key").should be_nil |     context.store["before_get_context_test"].as(TestContextStorageType).id.should eq 32 | ||||||
|     end |  | ||||||
|   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 |     make_me_true.should be_true | ||||||
|       CR |  | ||||||
|   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 |     Kemal.application.running?.should be_true | ||||||
|       puts Kemal.config.running |     Kemal.stop | ||||||
|       CR |  | ||||||
|   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 | ||||||
| 
 |  | ||||||
|     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 | 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,25 +2,26 @@ 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) | ||||||
|       call_next(context) |       begin | ||||||
|     rescue ex : Kemal::Exceptions::RouteNotFound |         call_next(context) | ||||||
|       call_exception_with_status_code(context, ex, 404) |       rescue ex : Kemal::Exceptions::RouteNotFound | ||||||
|     rescue ex : Kemal::Exceptions::CustomException |         call_exception_with_status_code(context, ex, 404) | ||||||
|       call_exception_with_status_code(context, ex, context.response.status_code) |       rescue ex : Kemal::Exceptions::CustomException | ||||||
|     rescue ex : Exception |         call_exception_with_status_code(context, ex, context.response.status_code) | ||||||
|       log("Exception: #{ex.inspect_with_backtrace}") |       rescue ex : Exception | ||||||
|       return call_exception_with_status_code(context, ex, 500) if Kemal.config.error_handlers.has_key?(500) |         log("Exception: #{ex.inspect_with_backtrace}") | ||||||
|       verbosity = Kemal.config.env == "production" ? false : true |         return call_exception_with_status_code(context, ex, 500) if context.app.error_handlers.has_key?(500) | ||||||
|       return render_500(context, ex, verbosity) |         verbosity = context.app.config.env == "production" ? false : true | ||||||
|  |         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