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