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