Rebased to master and update to Crystal 0.27.0

This commit is contained in:
sdogruyol 2018-12-17 22:20:21 +03:00
parent 4fefd9cb5c
commit 678adaa375
12 changed files with 71 additions and 136 deletions

View file

@ -1 +1 @@
require "./*" # require "./*"

View file

@ -28,7 +28,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 be_nil context.response.headers["X-Powered-By"]?.should be_nil
end end
end end

View file

@ -1,4 +1,4 @@
require "../spec_helper" require "../dsl_helper"
describe "Kemal::FilterHandler" do describe "Kemal::FilterHandler" do
it "executes code before home request" do it "executes code before home request" do
@ -13,8 +13,8 @@ describe "Kemal::FilterHandler" do
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_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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
@ -33,14 +33,14 @@ describe "Kemal::FilterHandler" do
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_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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")
request = HTTP::Request.new("POST", "/greetings") request = HTTP::Request.new("POST", "/greetings")
create_request_and_return_io_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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
@ -61,14 +61,14 @@ describe "Kemal::FilterHandler" do
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_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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("false") client_response.body.should eq("false")
request = HTTP::Request.new("POST", "/greetings") request = HTTP::Request.new("POST", "/greetings")
create_request_and_return_io_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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("false") client_response.body.should eq("false")
end end
@ -85,14 +85,14 @@ describe "Kemal::FilterHandler" do
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_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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 after GET home request but not POST home request" do 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" test_filter.modified = "false"
filter_middleware = Kemal::FilterHandler.new(Kemal.application) filter_middleware = Kemal::FilterHandler.new(Kemal.application)
@ -105,20 +105,20 @@ describe "Kemal::FilterHandler" do
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_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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")
request = HTTP::Request.new("POST", "/greetings") request = HTTP::Request.new("POST", "/greetings")
create_request_and_return_io_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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 after all GET/POST home request" do it "executes code after all GET/POST home request" do
test_filter = FilterTest.new test_filter = FilterTest.new
test_filter.modified = "false" test_filter.modified = "false"
filter_middleware = Kemal::FilterHandler.new(Kemal.application) filter_middleware = Kemal::FilterHandler.new(Kemal.application)
@ -132,14 +132,14 @@ describe "Kemal::FilterHandler" do
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_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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("false") client_response.body.should eq("false")
request = HTTP::Request.new("POST", "/greetings") request = HTTP::Request.new("POST", "/greetings")
create_request_and_return_io_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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("false") client_response.body.should eq("false")
end end
@ -166,20 +166,20 @@ describe "Kemal::FilterHandler" do
test_filter_second.modified.should eq("false") test_filter_second.modified.should eq("false")
test_filter_third.modified.should eq("false") test_filter_third.modified.should eq("false")
request = HTTP::Request.new("GET", "/greetings") request = HTTP::Request.new("GET", "/greetings")
create_request_and_return_io_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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")
request = HTTP::Request.new("POST", "/greetings") request = HTTP::Request.new("POST", "/greetings")
create_request_and_return_io_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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("false") client_response.body.should eq("false")
request = HTTP::Request.new("PUT", "/greetings") request = HTTP::Request.new("PUT", "/greetings")
create_request_and_return_io_and_context(filter_middleware, request) create_request_and_return_io(filter_middleware, request)
io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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

View file

@ -43,8 +43,8 @@ describe "ParamParser" do
end end
request = HTTP::Request.new("POST", "/hello/sam%2Bspec%40gmail.com/%2419.99/a%C3%B1o") request = HTTP::Request.new("POST", "/hello/sam%2Bspec%40gmail.com/%2419.99/a%C3%B1o")
# Radix tree MUST be run to parse url params. # Radix tree MUST be run to parse url params.
context = create_request_and_return_io_and_context(kemal, request)[1] io_with_context = create_request_and_return_io(kemal, request)
url_params = Kemal::ParamParser.new(request, context.route_lookup.params).url url_params = Kemal::ParamParser.new(request).url
url_params["email"].should eq "sam+spec@gmail.com" url_params["email"].should eq "sam+spec@gmail.com"
url_params["money"].should eq "$19.99" url_params["money"].should eq "$19.99"
url_params["spanish"].should eq "año" url_params["spanish"].should eq "año"

View file

@ -46,7 +46,7 @@ describe "Kemal::WebSocketHandler" do
request = HTTP::Request.new("GET", "/", headers) request = HTTP::Request.new("GET", "/", headers)
io_with_context = create_ws_request_and_return_io(app.websocket_handler, request) 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 end
it "fetches named url parameters" do it "fetches named url parameters" do
@ -60,7 +60,7 @@ describe "Kemal::WebSocketHandler" do
} }
request = HTTP::Request.new("GET", "/1234", headers) request = HTTP::Request.new("GET", "/1234", headers)
io_with_context = create_ws_request_and_return_io(app.websocket_handler, request) 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 end
it "matches correct verb" do it "matches correct verb" do

View file

@ -2,6 +2,6 @@ def render_404
Kemal.application.render_404 Kemal.application.render_404
end end
def render_500(context, backtrace, verbosity) def render_500(context, exception, verbosity)
Kemal.application.render_500(context, backtrace, verbosity) Kemal.application.render_500(context, exception, verbosity)
end end

View file

@ -21,7 +21,7 @@ module Kemal
log("Exception: #{ex.inspect_with_backtrace}") log("Exception: #{ex.inspect_with_backtrace}")
return call_exception_with_status_code(context, ex, 500) if app.error_handlers.has_key?(500) return call_exception_with_status_code(context, ex, 500) if app.error_handlers.has_key?(500)
verbosity = app.config.env == "production" ? false : true 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
end end

View file

@ -10,11 +10,11 @@ class HTTP::Server
macro finished macro finished
alias StoreTypes = Union({{ *STORE_MAPPINGS }}) alias StoreTypes = Union({{ *STORE_MAPPINGS }})
@store = {} of String => StoreTypes getter store = {} of String => StoreTypes
end end
def params def params
@params ||= Kemal::ParamParser.new(@request, route_lookup.params) @params ||= Kemal::ParamParser.new(@request)
end end
def redirect(url : String, status_code : Int32 = 302) def redirect(url : String, status_code : Int32 = 302)
@ -22,30 +22,6 @@ class HTTP::Server
@response.status_code = status_code @response.status_code = status_code
end 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) def get(name : String)
@store[name] @store[name]
end end

File diff suppressed because one or more lines are too long

View file

@ -1,28 +1,27 @@
require "http" require "http"
require "json" require "json"
require "uri" require "uri"
require "./ext/*"
require "./helpers/*"
require "./application" require "./application"
require "./base_log_handler" require "./base_log_handler"
require "./cli" require "./cli"
require "./exception_handler" require "./exception_handler"
require "./log_handler" require "./log_handler"
require "./config" require "./config"
require "./exceptions"
require "./file_upload" require "./file_upload"
require "./filter_handler" require "./filter_handler"
require "./handler" require "./handler"
require "./init_handler" require "./init_handler"
require "./null_log_handler" require "./null_log_handler"
require "./param_parser" require "./param_parser"
require "./response"
require "./route" require "./route"
require "./route_handler" require "./route_handler"
require "./ssl" require "./ssl"
require "./static_file_handler" require "./static_file_handler"
require "./websocket" require "./websocket"
require "./websocket_handler" require "./websocket_handler"
require "./ext/*"
require "./helpers/*"
module Kemal module Kemal
def self.application def self.application
@ -35,7 +34,7 @@ module Kemal
# Overload of `self.run` with the default startup logging. # Overload of `self.run` with the default startup logging.
def self.run(port : Int32? = nil) def self.run(port : Int32? = nil)
CLI.new(config) CLI.new(ARGV, config)
application.run(port) application.run(port)
end end
@ -44,7 +43,7 @@ module Kemal
# The port can be given to `#run` but is optional. # The port can be given to `#run` but is optional.
# If not given Kemal will use `Kemal::Config#port` # If not given Kemal will use `Kemal::Config#port`
def self.run(port : Int32? = nil) def self.run(port : Int32? = nil)
CLI.new(config) CLI.new(ARGV, config)
application.run(port) do |application| application.run(port) do |application|
yield application yield application

View file

@ -10,8 +10,9 @@ module Kemal
# :nodoc: # :nodoc:
alias AllParamTypes = Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Any) | Array(JSON::Any) alias AllParamTypes = Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Any) | Array(JSON::Any)
getter files 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)) @query = HTTP::Params.new({} of String => Array(String))
@body = HTTP::Params.new({} of String => Array(String)) @body = HTTP::Params.new({} of String => Array(String))
@json = {} of String => AllParamTypes @json = {} of String => AllParamTypes
@ -21,6 +22,7 @@ module Kemal
@body_parsed = false @body_parsed = false
@json_parsed = false @json_parsed = false
@files_parsed = false @files_parsed = false
@url = {} of String => String
end end
private def unescape_url_param(value : String) private def unescape_url_param(value : String)
@ -61,7 +63,12 @@ module Kemal
end end
private def parse_url 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 end
private def parse_files private def parse_files

View file

@ -54,8 +54,11 @@ module Kemal
# Processes the route if it's a match. Otherwise renders 404. # Processes the route if it's a match. Otherwise renders 404.
private def process_request(context) private def process_request(context)
raise Kemal::Exceptions::RouteNotFound.new(context) unless context.route_found? raise Kemal::Exceptions::RouteNotFound.new(context) unless route_defined?(context.request)
content = context.route.handler.call(context)
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) if !app.error_handlers.empty? && app.error_handlers.has_key?(context.response.status_code)
raise Kemal::Exceptions::CustomException.new(context) raise Kemal::Exceptions::CustomException.new(context)
@ -76,6 +79,7 @@ module Kemal
def clear def clear
@routes = Radix::Tree(Route).new @routes = Radix::Tree(Route).new
@cached_routes = Hash(String, Radix::Result(Route)).new
end end
end end
end end