mirror of
https://gitea.invidious.io/iv-org/shard-kemal.git
synced 2024-08-15 00:53:36 +00:00
commit
54f25c5880
6 changed files with 30 additions and 68 deletions
|
@ -2,25 +2,6 @@ require "./spec_helper"
|
||||||
|
|
||||||
describe "Route" do
|
describe "Route" do
|
||||||
describe "match?" do
|
describe "match?" do
|
||||||
it "doesn't match because of route" do
|
|
||||||
route = Route.new("GET", "/foo/bar") { "" }
|
|
||||||
request = HTTP::Request.new("GET", "/world?message=coco")
|
|
||||||
route.match?(request).should be_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't match because of method" do
|
|
||||||
route = Route.new("GET", "/foo/bar") { "" }
|
|
||||||
request = HTTP::Request.new("POST", "/foo/bar")
|
|
||||||
route.match?(request).should be_nil
|
|
||||||
end
|
|
||||||
|
|
||||||
it "matches" do
|
|
||||||
route = Route.new("GET", "/foo/:one/path/:two") { "" }
|
|
||||||
request = HTTP::Request.new("GET", "/foo/uno/path/dos")
|
|
||||||
match = route.match?(request)
|
|
||||||
match.should eq true
|
|
||||||
end
|
|
||||||
|
|
||||||
it "matches the correct route" do
|
it "matches the correct route" do
|
||||||
kemal = Kemal::Handler.new
|
kemal = Kemal::Handler.new
|
||||||
kemal.add_route "GET", "/route1" do |env|
|
kemal.add_route "GET", "/route1" do |env|
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
class Kemal::Context
|
class Kemal::Context
|
||||||
getter request
|
getter request
|
||||||
getter response
|
getter response
|
||||||
getter params
|
getter route
|
||||||
getter content_type
|
getter content_type
|
||||||
|
|
||||||
def initialize(@request, @params)
|
def initialize(@request, @route)
|
||||||
@response = Kemal::Response.new
|
@response = Kemal::Response.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ class Kemal::Context
|
||||||
@response.content_type
|
@response.content_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def params
|
||||||
|
Kemal::ParamParser.new(@route, @request).parse
|
||||||
|
end
|
||||||
|
|
||||||
delegate headers, @request
|
delegate headers, @request
|
||||||
delegate status_code, :"status_code=", :"content_type=", @response
|
delegate status_code, :"status_code=", :"content_type=", @response
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
require "http/server"
|
require "http/server"
|
||||||
require "uri"
|
|
||||||
|
|
||||||
# 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.
|
||||||
|
@ -24,11 +23,11 @@ class Kemal::Handler < HTTP::Handler
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_request(request)
|
def process_request(request)
|
||||||
|
url = request.path.not_nil!
|
||||||
@routes.each do |route|
|
@routes.each do |route|
|
||||||
match = route.match?(request)
|
url.match(route.pattern as Regex) do |url_params|
|
||||||
if match
|
request.url_params = url_params
|
||||||
params = Kemal::ParamParser.new(route, request).parse
|
context = Context.new(request, route)
|
||||||
context = Context.new(request, params)
|
|
||||||
begin
|
begin
|
||||||
body = route.handler.call(context).to_s
|
body = route.handler.call(context).to_s
|
||||||
return HTTP::Response.new(context.status_code, body, context.response_headers)
|
return HTTP::Response.new(context.status_code, body, context.response_headers)
|
||||||
|
|
|
@ -11,17 +11,15 @@ class Kemal::ParamParser
|
||||||
APPLICATION_JSON = "application/json"
|
APPLICATION_JSON = "application/json"
|
||||||
|
|
||||||
def initialize(@route, @request)
|
def initialize(@route, @request)
|
||||||
@route_components = route.components
|
|
||||||
@request_components = request.path.not_nil!.split "/"
|
|
||||||
@params = {} of String => AllParamTypes
|
@params = {} of String => AllParamTypes
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse
|
def parse
|
||||||
parse_components
|
|
||||||
parse_request
|
parse_request
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_request
|
def parse_request
|
||||||
|
parse_url_params
|
||||||
parse_query
|
parse_query
|
||||||
parse_body
|
parse_body
|
||||||
parse_json
|
parse_json
|
||||||
|
@ -37,6 +35,18 @@ class Kemal::ParamParser
|
||||||
parse_part(@request.query)
|
parse_part(@request.query)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Ditto: This needs memoization without the huge AllParamTypes union :|
|
||||||
|
def parse_url_params
|
||||||
|
if @request.url_params
|
||||||
|
url_params = @request.url_params.not_nil!
|
||||||
|
name_table = url_params.regex.name_table
|
||||||
|
url_params.size.times do |i|
|
||||||
|
name = (name_table.fetch(i + 1) { i + 1 }) as String
|
||||||
|
@params[name] = url_params[i + 1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Parses JSON request body if Content-Type is `application/json`.
|
# Parses JSON request body if Content-Type is `application/json`.
|
||||||
# If request body is a JSON Hash then all the params are parsed and added into `params`.
|
# If request body is a JSON Hash then all the params are parsed and added into `params`.
|
||||||
# If request body is a JSON Array it's added into `params` as `_json` and can be accessed
|
# If request body is a JSON Array it's added into `params` as `_json` and can be accessed
|
||||||
|
@ -45,7 +55,6 @@ class Kemal::ParamParser
|
||||||
return unless @request.body && @request.headers["Content-Type"]? == APPLICATION_JSON
|
return unless @request.body && @request.headers["Content-Type"]? == APPLICATION_JSON
|
||||||
|
|
||||||
body = @request.body as String
|
body = @request.body as String
|
||||||
|
|
||||||
case json = JSON.parse(body).raw
|
case json = JSON.parse(body).raw
|
||||||
when Hash
|
when Hash
|
||||||
json.each do |k, v|
|
json.each do |k, v|
|
||||||
|
@ -63,13 +72,4 @@ class Kemal::ParamParser
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_components
|
|
||||||
@route_components.zip(@request_components) do |route_component, req_component|
|
|
||||||
if route_component.starts_with? ':'
|
|
||||||
@params[route_component[1..-1]] = req_component
|
|
||||||
else
|
|
||||||
return nil unless route_component == req_component
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# Opening HTTP::Request to add override_method property
|
# Opening HTTP::Request to add override_method property
|
||||||
class HTTP::Request
|
class HTTP::Request
|
||||||
property override_method
|
property override_method
|
||||||
|
property url_params
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,40 +3,17 @@
|
||||||
# what action to be done if the route is matched.
|
# what action to be done if the route is matched.
|
||||||
class Kemal::Route
|
class Kemal::Route
|
||||||
getter handler
|
getter handler
|
||||||
getter components
|
getter pattern
|
||||||
|
|
||||||
def initialize(@method, path, &@handler : Kemal::Context -> _)
|
def initialize(@method, path, &@handler : Kemal::Context -> _)
|
||||||
@components = path.split "/"
|
@pattern = pattern_to_regex path
|
||||||
end
|
end
|
||||||
|
|
||||||
def match?(request)
|
private def pattern_to_regex(pattern)
|
||||||
check_for_method_override!(request)
|
pattern = pattern.gsub(/\:(?<param>\w+)/) do |_, match|
|
||||||
return nil unless request.override_method == @method
|
"(?<#{match["param"]}>.*)"
|
||||||
components = request.path.not_nil!.split "/"
|
|
||||||
return nil unless components.size == @components.size
|
|
||||||
@components.zip(components) do |route_component, req_component|
|
|
||||||
unless route_component.starts_with? ':'
|
|
||||||
return nil unless route_component == req_component
|
|
||||||
end
|
end
|
||||||
end
|
Regex.new "^#{pattern}/?$"
|
||||||
true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Checks if request params contain _method param to override request incoming method
|
|
||||||
def 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 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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue