From ab711c22fd486fce8af45203b802428835e4bdef Mon Sep 17 00:00:00 2001 From: Werner Date: Sun, 7 Feb 2016 09:49:38 -0430 Subject: [PATCH] Basic filter implementation, similar to Sinatra. --- spec/middleware/filters_spec.cr | 25 ++++++++++++++++ src/kemal/middleware/filters.cr | 52 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 spec/middleware/filters_spec.cr create mode 100644 src/kemal/middleware/filters.cr diff --git a/spec/middleware/filters_spec.cr b/spec/middleware/filters_spec.cr new file mode 100644 index 0000000..f0f2264 --- /dev/null +++ b/spec/middleware/filters_spec.cr @@ -0,0 +1,25 @@ +require "../spec_helper" + +describe "Kemal::Middleware::Filters" do + it "executes code before home request" 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" } + + kemal = Kemal::RouteHandler.new + 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) + 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 +end + +class FilterTest + property modified +end diff --git a/src/kemal/middleware/filters.cr b/src/kemal/middleware/filters.cr new file mode 100644 index 0000000..0f91a44 --- /dev/null +++ b/src/kemal/middleware/filters.cr @@ -0,0 +1,52 @@ +module Kemal::Middleware + # Kemal::Filter handle all code that should be evaluated before and after + # every request + class Filter < HTTP::Handler + def initialize + @tree = Radix::Tree.new + end + + def add(type, path, options, &block : HTTP::Server::Context -> _) + node = radix_path type, path + @tree.add node, Block.new &block + end + + def call(context) + process_filter(context, :before) + call_next(context) + process_filter(context, :after) + end + + private def process_filter(context, type) + lookup = @tree.find radix_path(type, context.request.path) + 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}" + end + end + + class Block + property block + def initialize(&@block : HTTP::Server::Context -> _) + end + end +end + +def add_filters + Kemal.config.add_handler Kemal::Filters::Filter.new +end + +def before(path = "*", options = {} of Symbol => String, &block : HTTP::Server::Context -> _) + filter = Kemal.config.handlers.first as Kemal::Filters::Filter + filter.add :before, path, options, &block +end + +def after(path = "*", options = {} of Symbol => String, &block : HTTP::Server::Context -> _) + filter = Kemal.config.handlers.first as Kemal::Filters::Filter + filter.add :after, path, options, &block +end