Implement radix algorithm for routing (thanks to beryl)

This commit is contained in:
Fatih Kadir Akın 2016-01-22 22:14:22 +02:00
parent 2cc4c17c80
commit 7d0d5add84
4 changed files with 31 additions and 8 deletions

8
.gitignore vendored
View file

@ -1,2 +1,8 @@
.crystal /libs/
/.crystal/
/.shards/
*.log *.log
# Libraries don't need dependency lock
# Dependencies will be locked in application that uses them
/shard.lock

View file

@ -1,5 +1,9 @@
name: kemal name: kemal
version: 0.7.0 version: 0.7.0
dependencies:
beryl:
github: luislavena/beryl
author: author:
- Serdar Dogruyol <dogruyolserdar@gmail.com> - Serdar Dogruyol <dogruyolserdar@gmail.com>

View file

@ -1,4 +1,5 @@
require "http/server" require "http/server"
require "beryl/beryl/routing/tree"
# Kemal::Handler is the main handler which handles all the HTTP requests. Routing, parsing, rendering e.g # Kemal::Handler is the main handler which handles all the HTTP requests. Routing, parsing, rendering e.g
# are done in this handler. # are done in this handler.
@ -7,7 +8,7 @@ class Kemal::Handler < HTTP::Handler
INSTANCE = new INSTANCE = new
def initialize def initialize
@routes = [] of Route @tree = Beryl::Routing::Tree.new
end end
def call(request) def call(request)
@ -16,15 +17,18 @@ class Kemal::Handler < HTTP::Handler
end end
def add_route(method, path, &handler : Kemal::Context -> _) def add_route(method, path, &handler : Kemal::Context -> _)
@routes << Route.new(method, path, &handler) add_to_radix_tree method, path, Route.new(method, path, &handler)
# Registering HEAD route for defined GET routes. # Registering HEAD route for defined GET routes.
@routes << Route.new("HEAD", path, &handler) if method == "GET" add_to_radix_tree("HEAD", path, Route.new("HEAD", path, &handler)) if method == "GET"
end end
def process_request(request) def process_request(request)
url = request.path.not_nil! url = request.path.not_nil!
@routes.each do |route| Kemal::Route.check_for_method_override!(request)
lookup = @tree.find radix_path(request.override_method, request.path)
if lookup.found?
route = lookup.payload as Route
if route.match?(request) if route.match?(request)
context = Context.new(request, route) context = Context.new(request, route)
begin begin
@ -39,4 +43,13 @@ class Kemal::Handler < HTTP::Handler
# Render 404 unless a route matches # Render 404 unless a route matches
return render_404 return render_404
end end
private def radix_path(method, path)
"#{method} #{path}"
end
private def add_to_radix_tree(method, path, route)
node = radix_path method, path
@tree.add node, route
end
end end

View file

@ -10,7 +10,7 @@ class Kemal::Route
end end
def match?(request) def match?(request)
check_for_method_override!(request) self.class.check_for_method_override!(request)
return nil unless request.override_method == @method return nil unless request.override_method == @method
return true if request.path.not_nil!.includes?(':') && request.path.not_nil! == @path return true if request.path.not_nil!.includes?(':') && request.path.not_nil! == @path
request.path.not_nil!.match(@compiled_regex) do |url_params| request.path.not_nil!.match(@compiled_regex) do |url_params|
@ -20,7 +20,7 @@ class Kemal::Route
end end
# Checks if request params contain _method param to override request incoming method # Checks if request params contain _method param to override request incoming method
def check_for_method_override!(request) def self.check_for_method_override!(request)
request.override_method = request.method request.override_method = request.method
if request.method == "POST" if request.method == "POST"
params = Kemal::ParamParser.new(self, request).parse_request params = Kemal::ParamParser.new(self, request).parse_request
@ -31,7 +31,7 @@ class Kemal::Route
end end
# Checks if method contained in _method param is valid one # Checks if method contained in _method param is valid one
def override_method_valid?(override_method) def self.override_method_valid?(override_method)
return false unless override_method.is_a?(String) return false unless override_method.is_a?(String)
override_method = override_method.upcase override_method = override_method.upcase
return (override_method == "PUT" || override_method == "PATCH" || override_method == "DELETE") return (override_method == "PUT" || override_method == "PATCH" || override_method == "DELETE")