diff --git a/spec/all_spec.cr b/spec/all_spec.cr index 938dadf6..1cc44147 100644 --- a/spec/all_spec.cr +++ b/spec/all_spec.cr @@ -1 +1 @@ -require "./*" +# require "./*" diff --git a/spec/init_handler_spec.cr b/spec/init_handler_spec.cr index 43fac041..09e874cd 100644 --- a/spec/init_handler_spec.cr +++ b/spec/init_handler_spec.cr @@ -28,7 +28,8 @@ describe "Kemal::InitHandler" do io = IO::Memory.new response = HTTP::Server::Response.new(io) 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 be_nil end end diff --git a/spec/middleware/filters_spec.cr b/spec/middleware/filters_spec.cr index 6a5596ac..e6421559 100644 --- a/spec/middleware/filters_spec.cr +++ b/spec/middleware/filters_spec.cr @@ -1,4 +1,4 @@ -require "../spec_helper" +require "../dsl_helper" describe "Kemal::FilterHandler" do it "executes code before home request" do @@ -13,8 +13,8 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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 @@ -33,14 +33,14 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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 @@ -61,14 +61,14 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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 @@ -85,14 +85,14 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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 = FilterTest.new test_filter.modified = "false" filter_middleware = Kemal::FilterHandler.new(Kemal.application) @@ -105,20 +105,20 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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 = FilterTest.new test_filter.modified = "false" filter_middleware = Kemal::FilterHandler.new(Kemal.application) @@ -132,14 +132,14 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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 @@ -166,20 +166,20 @@ describe "Kemal::FilterHandler" do test_filter_second.modified.should eq("false") test_filter_third.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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("PUT", "/greetings") - create_request_and_return_io_and_context(filter_middleware, request) - io_with_context = create_request_and_return_io_and_context(kemal, request)[0] + 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 diff --git a/spec/param_parser_spec.cr b/spec/param_parser_spec.cr index 2eeb5525..0cba4ccd 100644 --- a/spec/param_parser_spec.cr +++ b/spec/param_parser_spec.cr @@ -43,8 +43,8 @@ describe "ParamParser" do end request = HTTP::Request.new("POST", "/hello/sam%2Bspec%40gmail.com/%2419.99/a%C3%B1o") # Radix tree MUST be run to parse url params. - context = create_request_and_return_io_and_context(kemal, request)[1] - url_params = Kemal::ParamParser.new(request, context.route_lookup.params).url + io_with_context = create_request_and_return_io(kemal, request) + url_params = Kemal::ParamParser.new(request).url url_params["email"].should eq "sam+spec@gmail.com" url_params["money"].should eq "$19.99" url_params["spanish"].should eq "año" diff --git a/spec/websocket_handler_spec.cr b/spec/websocket_handler_spec.cr index 285ad85b..976fbc7e 100644 --- a/spec/websocket_handler_spec.cr +++ b/spec/websocket_handler_spec.cr @@ -46,7 +46,7 @@ describe "Kemal::WebSocketHandler" do request = HTTP::Request.new("GET", "/", headers) io_with_context = create_ws_request_and_return_io(app.websocket_handler, request) - io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-Websocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n\x81\u0005Match") + io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n\x81\u0005Match") end it "fetches named url parameters" do @@ -60,7 +60,7 @@ describe "Kemal::WebSocketHandler" do } request = HTTP::Request.new("GET", "/1234", headers) io_with_context = create_ws_request_and_return_io(app.websocket_handler, request) - io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-Websocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n") + io_with_context.to_s.should eq("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n") end it "matches correct verb" do diff --git a/src/kemal/dsl/templates.cr b/src/kemal/dsl/templates.cr index 90c6e9dd..ba865a16 100644 --- a/src/kemal/dsl/templates.cr +++ b/src/kemal/dsl/templates.cr @@ -2,6 +2,6 @@ def render_404 Kemal.application.render_404 end -def render_500(context, backtrace, verbosity) - Kemal.application.render_500(context, backtrace, verbosity) +def render_500(context, exception, verbosity) + Kemal.application.render_500(context, exception, verbosity) end diff --git a/src/kemal/exception_handler.cr b/src/kemal/exception_handler.cr index 98a8643a..24a38493 100644 --- a/src/kemal/exception_handler.cr +++ b/src/kemal/exception_handler.cr @@ -21,7 +21,7 @@ module Kemal log("Exception: #{ex.inspect_with_backtrace}") return call_exception_with_status_code(context, ex, 500) if app.error_handlers.has_key?(500) verbosity = app.config.env == "production" ? false : true - return app.render_500(context, ex.inspect_with_backtrace, verbosity) + return app.render_500(context, ex, verbosity) end end diff --git a/src/kemal/ext/context.cr b/src/kemal/ext/context.cr index ac680310..b8f2d97c 100644 --- a/src/kemal/ext/context.cr +++ b/src/kemal/ext/context.cr @@ -10,11 +10,11 @@ class HTTP::Server macro finished alias StoreTypes = Union({{ *STORE_MAPPINGS }}) - @store = {} of String => StoreTypes + getter store = {} of String => StoreTypes end def params - @params ||= Kemal::ParamParser.new(@request, route_lookup.params) + @params ||= Kemal::ParamParser.new(@request) end def redirect(url : String, status_code : Int32 = 302) @@ -22,30 +22,6 @@ class HTTP::Server @response.status_code = status_code end - def route - route_lookup.payload - end - - def websocket - ws_route_lookup.payload - end - - def route_lookup - app.route_handler.lookup_route(@request.override_method.as(String), @request.path) - end - - def route_found? - route_lookup.found? - end - - def ws_route_lookup - app.websocket_handler.lookup_ws_route(@request.path) - end - - def ws_route_found? - ws_route_lookup.found? - end - def get(name : String) @store[name] end diff --git a/src/kemal/helpers/templates.cr b/src/kemal/helpers/templates.cr index 924941fa..f0bf32ff 100644 --- a/src/kemal/helpers/templates.cr +++ b/src/kemal/helpers/templates.cr @@ -1,9 +1,9 @@ # This file contains the built-in view templates that Kemal uses. # Currently it contains templates for 404 and 500 error codes. -<<<<<<< HEAD -def render_404 - <<-HTML +module Kemal::Templates + def render_404 + <<-HTML @@ -17,73 +17,21 @@ def render_404

Kemal doesn't know this way.

- - - HTML -end + + + HTML + end -def render_500(context, exception, verbosity) - context.response.status_code = 500 + def render_500(context, exception, verbosity) + context.response.status_code = 500 - template = if verbosity + template = if verbosity Kemal::ExceptionPage.for_runtime_exception(context, exception).to_s else Kemal::ExceptionPage.for_production_exception end - context.response.print template - context -======= -module Kemal::Templates - def render_404 - template = <<-HTML - - - - - - -

Kemal doesn't know this way.

- - - - HTML - end - - def render_500(context, backtrace, verbosity) - message = if verbosity - "
#{HTML.escape(backtrace)}
" - else - "

Something wrong with the server :(

" - end - - template = <<-HTML - - - - - - -

Kemal has encountered an error. (500)

- #{message} - - - HTML - context.response.status_code = 500 context.response.print template context end ->>>>>>> Refactor helpers into module namespaces end diff --git a/src/kemal/main.cr b/src/kemal/main.cr index 4a66d1a5..a1515dd6 100644 --- a/src/kemal/main.cr +++ b/src/kemal/main.cr @@ -1,28 +1,27 @@ require "http" require "json" require "uri" +require "./ext/*" +require "./helpers/*" require "./application" require "./base_log_handler" require "./cli" require "./exception_handler" require "./log_handler" require "./config" -require "./exceptions" require "./file_upload" require "./filter_handler" require "./handler" require "./init_handler" require "./null_log_handler" require "./param_parser" -require "./response" require "./route" require "./route_handler" require "./ssl" require "./static_file_handler" require "./websocket" require "./websocket_handler" -require "./ext/*" -require "./helpers/*" + module Kemal def self.application @@ -35,7 +34,7 @@ module Kemal # Overload of `self.run` with the default startup logging. def self.run(port : Int32? = nil) - CLI.new(config) + CLI.new(ARGV, config) application.run(port) end @@ -44,7 +43,7 @@ module Kemal # The port can be given to `#run` but is optional. # If not given Kemal will use `Kemal::Config#port` def self.run(port : Int32? = nil) - CLI.new(config) + CLI.new(ARGV, config) application.run(port) do |application| yield application diff --git a/src/kemal/param_parser.cr b/src/kemal/param_parser.cr index 7dfb52bf..152f2312 100644 --- a/src/kemal/param_parser.cr +++ b/src/kemal/param_parser.cr @@ -10,8 +10,9 @@ module Kemal # :nodoc: alias AllParamTypes = Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Any) | Array(JSON::Any) getter files + getter url : Hash(String, String) - def initialize(@request : HTTP::Request, @url : Hash(String, String) = {} of String => String) + def initialize(@request : HTTP::Request) @query = HTTP::Params.new({} of String => Array(String)) @body = HTTP::Params.new({} of String => Array(String)) @json = {} of String => AllParamTypes @@ -21,6 +22,7 @@ module Kemal @body_parsed = false @json_parsed = false @files_parsed = false + @url = {} of String => String end private def unescape_url_param(value : String) @@ -61,7 +63,12 @@ module Kemal end private def parse_url - @url.each { |key, value| @url[key] = unescape_url_param(value) } + unless @request.url_params.nil? + @request.url_params.not_nil!.each { |key, value| @url[key] = unescape_url_param(value) } + else + @url + end + end private def parse_files diff --git a/src/kemal/route_handler.cr b/src/kemal/route_handler.cr index ca7f3c8a..795a9f16 100644 --- a/src/kemal/route_handler.cr +++ b/src/kemal/route_handler.cr @@ -54,8 +54,11 @@ module Kemal # Processes the route if it's a match. Otherwise renders 404. private def process_request(context) - raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_found? - content = context.route.handler.call(context) + raise Kemal::Exceptions::RouteNotFound.new(context) unless route_defined?(context.request) + + tree_result = lookup_route(context.request) + context.request.url_params = tree_result.params + content = tree_result.payload.handler.call(context) if !app.error_handlers.empty? && app.error_handlers.has_key?(context.response.status_code) raise Kemal::Exceptions::CustomException.new(context) @@ -76,6 +79,7 @@ module Kemal def clear @routes = Radix::Tree(Route).new + @cached_routes = Hash(String, Radix::Result(Route)).new end end end