From ad5dc053c4e69cd09ce0cd331843ea88a7925017 Mon Sep 17 00:00:00 2001 From: Serdar Dogruyol Date: Sat, 30 Jun 2018 15:12:13 +0300 Subject: [PATCH 1/6] Remove _method override --- spec/route_handler_spec.cr | 42 --------------------------------- src/kemal/ext/context.cr | 9 +++---- src/kemal/ext/request.cr | 25 -------------------- src/kemal/filter_handler.cr | 4 ++-- src/kemal/helpers/exceptions.cr | 2 +- 5 files changed, 6 insertions(+), 76 deletions(-) diff --git a/spec/route_handler_spec.cr b/spec/route_handler_spec.cr index 5705618..a6db5e1 100644 --- a/spec/route_handler_spec.cr +++ b/spec/route_handler_spec.cr @@ -102,48 +102,6 @@ describe "Kemal::RouteHandler" do client_response.body.should eq("Skills ruby,crystal") end - it "checks for _method param in POST request to simulate PUT" do - put "/" do - "Hello World from PUT" - end - request = HTTP::Request.new( - "POST", - "/", - body: "_method=PUT", - headers: HTTP::Headers{"Content-Type" => "application/x-www-form-urlencoded"} - ) - client_response = call_request_on_app(request) - client_response.body.should eq("Hello World from PUT") - end - - it "checks for _method param in POST request to simulate PATCH" do - patch "/" do - "Hello World from PATCH" - end - request = HTTP::Request.new( - "POST", - "/", - body: "_method=PATCH", - headers: HTTP::Headers{"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8"} - ) - client_response = call_request_on_app(request) - client_response.body.should eq("Hello World from PATCH") - end - - it "checks for _method param in POST request to simulate DELETE" do - delete "/" do - "Hello World from DELETE" - end - request = HTTP::Request.new( - "POST", - "/", - body: "_method=DELETE", - headers: HTTP::Headers{"Content-Type" => "application/x-www-form-urlencoded; charset=UTF-8"} - ) - client_response = call_request_on_app(request) - client_response.body.should eq("Hello World from DELETE") - end - it "can process HTTP HEAD requests for defined GET routes" do get "/" do "Hello World from GET" diff --git a/src/kemal/ext/context.cr b/src/kemal/ext/context.cr index bd8c208..5bad0cd 100644 --- a/src/kemal/ext/context.cr +++ b/src/kemal/ext/context.cr @@ -15,11 +15,8 @@ class HTTP::Server def params @request.url_params ||= route_lookup.params - @params ||= if @request.param_parser - @request.param_parser.not_nil! - else - Kemal::ParamParser.new(@request) - end + @params ||= Kemal::ParamParser.new(@request) + end def redirect(url : String, status_code : Int32 = 302) @@ -36,7 +33,7 @@ class HTTP::Server end def route_lookup - Kemal::RouteHandler::INSTANCE.lookup_route(@request.override_method.as(String), @request.path) + Kemal::RouteHandler::INSTANCE.lookup_route(@request.method.as(String), @request.path) end def route_defined? diff --git a/src/kemal/ext/request.cr b/src/kemal/ext/request.cr index bc0569b..a5791d9 100644 --- a/src/kemal/ext/request.cr +++ b/src/kemal/ext/request.cr @@ -1,32 +1,7 @@ class HTTP::Request - property override_method property url_params : Hash(String, String)? - getter param_parser : Kemal::ParamParser? - - def override_method - @override_method ||= check_for_method_override! - end def content_type @headers["Content-Type"]? end - - # Checks if method contained in _method param is valid one - def self.override_method_valid?(override_method : String) - override_method = override_method.upcase - override_method == "PUT" || override_method == "PATCH" || override_method == "DELETE" - end - - # Checks if request params contain _method param to override request incoming method - private def check_for_method_override! - @override_method = @method - if @method == "POST" - @param_parser = Kemal::ParamParser.new(self) - params = @param_parser.not_nil!.body - if params.has_key?("_method") && HTTP::Request.override_method_valid?(params["_method"]) - @override_method = params["_method"] - end - end - @override_method - end end diff --git a/src/kemal/filter_handler.cr b/src/kemal/filter_handler.cr index 1d842f2..716e25e 100644 --- a/src/kemal/filter_handler.cr +++ b/src/kemal/filter_handler.cr @@ -14,12 +14,12 @@ module Kemal def call(context : HTTP::Server::Context) return call_next(context) unless context.route_defined? call_block_for_path_type("ALL", context.request.path, :before, context) - call_block_for_path_type(context.request.override_method, context.request.path, :before, context) + call_block_for_path_type(context.request.method, context.request.path, :before, context) if Kemal.config.error_handlers.has_key?(context.response.status_code) raise Kemal::Exceptions::CustomException.new(context) end call_next(context) - call_block_for_path_type(context.request.override_method, context.request.path, :after, context) + call_block_for_path_type(context.request.method, context.request.path, :after, context) call_block_for_path_type("ALL", context.request.path, :after, context) context end diff --git a/src/kemal/helpers/exceptions.cr b/src/kemal/helpers/exceptions.cr index 327a9d1..53520b3 100644 --- a/src/kemal/helpers/exceptions.cr +++ b/src/kemal/helpers/exceptions.cr @@ -8,7 +8,7 @@ module Kemal::Exceptions class RouteNotFound < Exception def initialize(context : HTTP::Server::Context) - super "Requested path: '#{context.request.override_method}:#{context.request.path}' was not found." + super "Requested path: '#{context.request.method}:#{context.request.path}' was not found." end end From d2ef57a12808d01dd8407d84fe88b1a7b665b899 Mon Sep 17 00:00:00 2001 From: Serdar Dogruyol Date: Sat, 30 Jun 2018 16:49:04 +0300 Subject: [PATCH 2/6] Improve param parsing and remove url_params from HTTP::Request --- spec/middleware/filters_spec.cr | 52 ++++++++++++++++----------------- spec/param_parser_spec.cr | 8 ++--- spec/spec_helper.cr | 7 +++-- spec/websocket_handler_spec.cr | 6 ++-- src/kemal/ext/context.cr | 4 +-- src/kemal/ext/request.cr | 7 ----- src/kemal/param_parser.cr | 11 ++----- src/kemal/websocket_handler.cr | 1 - 8 files changed, 41 insertions(+), 55 deletions(-) delete mode 100644 src/kemal/ext/request.cr diff --git a/spec/middleware/filters_spec.cr b/spec/middleware/filters_spec.cr index 41853be..9bc2564 100644 --- a/spec/middleware/filters_spec.cr +++ b/spec/middleware/filters_spec.cr @@ -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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false) client_response.body.should eq("false") end @@ -85,8 +85,8 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false) client_response.body.should eq("true") end @@ -105,14 +105,14 @@ describe "Kemal::FilterHandler" do test_filter.modified.should eq("false") request = HTTP::Request.new("GET", "/greetings") - create_request_and_return_io(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] client_response = HTTP::Client::Response.from_io(io_with_context, decompress: false) client_response.body.should eq("true") end @@ -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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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(filter_middleware, request) - io_with_context = create_request_and_return_io(kemal, request) + create_request_and_return_io_and_context(filter_middleware, request) + io_with_context = create_request_and_return_io_and_context(kemal, request)[0] 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 305a0a3..d63a229 100644 --- a/spec/param_parser_spec.cr +++ b/spec/param_parser_spec.cr @@ -28,8 +28,8 @@ describe "ParamParser" do end request = HTTP::Request.new("POST", "/hello/cemal") # Radix tree MUST be run to parse url params. - create_request_and_return_io(kemal, request) - url_params = Kemal::ParamParser.new(request).url + context = create_request_and_return_io_and_context(kemal, request)[1] + url_params = Kemal::ParamParser.new(request, context.route_lookup.params).url url_params["hasan"].should eq "cemal" end @@ -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. - create_request_and_return_io(kemal, request) - url_params = Kemal::ParamParser.new(request).url + context = create_request_and_return_io_and_context(kemal, request)[1] + url_params = Kemal::ParamParser.new(request, context.route_lookup.params).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/spec_helper.cr b/spec/spec_helper.cr index a4876c2..4d27003 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -29,17 +29,17 @@ end add_context_storage_type(TestContextStorageType) add_context_storage_type(AnotherContextStorageType) -def create_request_and_return_io(handler, request) +def create_request_and_return_io_and_context(handler, request) io = IO::Memory.new response = HTTP::Server::Response.new(io) context = HTTP::Server::Context.new(request, response) handler.call(context) response.close io.rewind - io + {io, context} end -def create_ws_request_and_return_io(handler, request) +def create_ws_request_and_return_io_and_context(handler, request) io = IO::Memory.new response = HTTP::Server::Response.new(io) context = HTTP::Server::Context.new(request, response) @@ -49,6 +49,7 @@ def create_ws_request_and_return_io(handler, request) # Raises because the IO::Memory is empty end io.rewind + {io, context} end def call_request_on_app(request) diff --git a/spec/websocket_handler_spec.cr b/spec/websocket_handler_spec.cr index bb867b2..bc02d3c 100644 --- a/spec/websocket_handler_spec.cr +++ b/spec/websocket_handler_spec.cr @@ -32,13 +32,13 @@ describe "Kemal::WebSocketHandler" do } request = HTTP::Request.new("GET", "/", headers) - io_with_context = create_ws_request_and_return_io(handler, request) + io_with_context = create_ws_request_and_return_io_and_context(handler, request)[0] 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 handler = Kemal::WebSocketHandler::INSTANCE - ws "/:id" { |_, c| c.params.url["id"] } + ws "/:id" { |_, c| c.ws_route_lookup.params["id"] } headers = HTTP::Headers{ "Upgrade" => "websocket", "Connection" => "Upgrade", @@ -46,7 +46,7 @@ describe "Kemal::WebSocketHandler" do "Sec-WebSocket-Version" => "13", } request = HTTP::Request.new("GET", "/1234", headers) - io_with_context = create_ws_request_and_return_io(handler, request) + io_with_context = create_ws_request_and_return_io_and_context(handler, request)[0] 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 diff --git a/src/kemal/ext/context.cr b/src/kemal/ext/context.cr index 5bad0cd..9f2d3c0 100644 --- a/src/kemal/ext/context.cr +++ b/src/kemal/ext/context.cr @@ -14,9 +14,7 @@ class HTTP::Server end def params - @request.url_params ||= route_lookup.params - @params ||= Kemal::ParamParser.new(@request) - + @params ||= Kemal::ParamParser.new(@request, route_lookup.params) end def redirect(url : String, status_code : Int32 = 302) diff --git a/src/kemal/ext/request.cr b/src/kemal/ext/request.cr deleted file mode 100644 index a5791d9..0000000 --- a/src/kemal/ext/request.cr +++ /dev/null @@ -1,7 +0,0 @@ -class HTTP::Request - property url_params : Hash(String, String)? - - def content_type - @headers["Content-Type"]? - end -end diff --git a/src/kemal/param_parser.cr b/src/kemal/param_parser.cr index 65834e4..18bf281 100644 --- a/src/kemal/param_parser.cr +++ b/src/kemal/param_parser.cr @@ -11,8 +11,7 @@ module Kemal alias AllParamTypes = Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Any) | Array(JSON::Any) getter files - def initialize(@request : HTTP::Request) - @url = {} of String => String + def initialize(@request : HTTP::Request, @url : Hash(String, String) = {} of String => String) @query = HTTP::Params.new({} of String => Array(String)) @body = HTTP::Params.new({} of String => Array(String)) @json = {} of String => AllParamTypes @@ -42,7 +41,7 @@ module Kemal {% end %} private def parse_body - content_type = @request.content_type + content_type = @request.headers["Content-Type"]? return unless content_type if content_type.try(&.starts_with?(URL_ENCODED_FORM)) @body = parse_part(@request.body) @@ -59,11 +58,7 @@ module Kemal end private def parse_url - if params = @request.url_params - params.each do |key, value| - @url[key] = unescape_url_param(value) - end - end + @url.each { |key, value| @url[key] = unescape_url_param(value) } end private def parse_file_upload diff --git a/src/kemal/websocket_handler.cr b/src/kemal/websocket_handler.cr index dd31bf8..9550bef 100644 --- a/src/kemal/websocket_handler.cr +++ b/src/kemal/websocket_handler.cr @@ -11,7 +11,6 @@ module Kemal def call(context : HTTP::Server::Context) return call_next(context) unless context.ws_route_defined? && websocket_upgrade_request?(context) - context.request.url_params ||= context.ws_route_lookup.params content = context.websocket.call(context) context.response.print(content) context From 4a58bc9690b8c03de79c7437c79e65b897ee6edd Mon Sep 17 00:00:00 2001 From: Serdar Dogruyol Date: Wed, 4 Jul 2018 21:42:58 +0300 Subject: [PATCH 3/6] Remove env.params.files and FileUpload --- src/kemal/file_upload.cr | 25 ------------------------- src/kemal/param_parser.cr | 18 ------------------ 2 files changed, 43 deletions(-) delete mode 100644 src/kemal/file_upload.cr diff --git a/src/kemal/file_upload.cr b/src/kemal/file_upload.cr deleted file mode 100644 index 562c18b..0000000 --- a/src/kemal/file_upload.cr +++ /dev/null @@ -1,25 +0,0 @@ -module Kemal - # :nodoc: - struct FileUpload - getter tmpfile : Tempfile - getter filename : String? - getter headers : HTTP::Headers - getter creation_time : Time? - getter modification_time : Time? - getter read_time : Time? - getter size : UInt64? - - def initialize(upload) - @tmpfile = Tempfile.new(filename) - ::File.open(@tmpfile.path, "w") do |file| - IO.copy(upload.body, file) - end - @filename = upload.filename - @headers = upload.headers - @creation_time = upload.creation_time - @modification_time = upload.modification_time - @read_time = upload.read_time - @size = upload.size - end - end -end diff --git a/src/kemal/param_parser.cr b/src/kemal/param_parser.cr index 18bf281..66626b4 100644 --- a/src/kemal/param_parser.cr +++ b/src/kemal/param_parser.cr @@ -9,13 +9,11 @@ module Kemal PARTS = %w(url query body json) # :nodoc: alias AllParamTypes = Nil | String | Int64 | Float64 | Bool | Hash(String, JSON::Any) | Array(JSON::Any) - getter files def initialize(@request : HTTP::Request, @url : Hash(String, String) = {} of String => String) @query = HTTP::Params.new({} of String => Array(String)) @body = HTTP::Params.new({} of String => Array(String)) @json = {} of String => AllParamTypes - @files = [] of FileUpload @url_parsed = false @query_parsed = false @body_parsed = false @@ -47,10 +45,6 @@ module Kemal @body = parse_part(@request.body) return end - if content_type.try(&.starts_with?(MULTIPART_FORM)) - parse_file_upload - return - end end private def parse_query @@ -61,18 +55,6 @@ module Kemal @url.each { |key, value| @url[key] = unescape_url_param(value) } end - private def parse_file_upload - HTTP::FormData.parse(@request) do |upload| - next unless upload - filename = upload.filename - if !filename.nil? - @files << FileUpload.new(upload: upload) - else - @body.add(upload.name, upload.body.gets_to_end) - end - end - end - # 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`. From ffaf6ff1f924b33f767fe55274c8d68593b3afb0 Mon Sep 17 00:00:00 2001 From: Serdar Dogruyol Date: Wed, 4 Jul 2018 22:04:22 +0300 Subject: [PATCH 4/6] Update CHANGELOG --- CHANGELOG.md | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1062d7..f041528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,23 +1,34 @@ # Next -- `env.params.files` is now an `Array(FileUpload)`. You can iterate over to access the images. +- *[breaking change]* Removed `env.params.files`. You can use Crystal's built-in `HTTP::FormData.parse` instead ```ruby -env.params.files.each do |file| +post "/upload" do |env| + HTTP::FormData.parse(env.request) do |upload| + filename = file.filename - filename = file.filename - - if !filename.is_a?(String) - "No filename included in upload" - else - file_path = ::File.join [Kemal.config.public_folder, "uploads/", filename] - File.open(file_path, "w") do |f| - IO.copy(file.tmpfile, f) + if !filename.is_a?(String) + "No filename included in upload" + else + file_path = ::File.join [Kemal.config.public_folder, "uploads/", filename] + File.open(file_path, "w") do |f| + IO.copy(file.tmpfile, f) + end + "Upload OK" end - "Upload OK" end ``` +- *[breaking change]* From now on to access dynamic url params in a WebSocket route you have to use + +```ruby +ws "/:id" do |socket, context| + id = context.ws_route_lookup.params["id"] +end +``` + +- *[breaking change]* Removed `_method` magic param + # 0.23.0 (17-06-2018) - Crystal 0.25.0 support 🎉 From 1e18389f5fa7b25ccf016b01dafbc06bc260ee95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Wojsznis?= Date: Mon, 16 Jul 2018 04:54:36 +0200 Subject: [PATCH 5/6] Remove etag logic as it's not implemented in Crystal 0.25.1 (#470) --- spec/static_file_handler_spec.cr | 1 + src/kemal/static_file_handler.cr | 18 +++++++----------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/spec/static_file_handler_spec.cr b/spec/static_file_handler_spec.cr index 6da77a3..1aac161 100644 --- a/spec/static_file_handler_spec.cr +++ b/spec/static_file_handler_spec.cr @@ -30,6 +30,7 @@ describe Kemal::StaticFileHandler do headers = HTTP::Headers{"If-None-Match" => etag} response = handle HTTP::Request.new("GET", "/dir/test.txt", headers) + response.headers["Content-Type"]?.should be_nil response.status_code.should eq(304) response.body.should eq "" end diff --git a/src/kemal/static_file_handler.cr b/src/kemal/static_file_handler.cr index fc9e036..8fa802e 100644 --- a/src/kemal/static_file_handler.cr +++ b/src/kemal/static_file_handler.cr @@ -50,21 +50,17 @@ module Kemal return call_next(context) end elsif File.exists?(file_path) - return if etag(context, file_path) + last_modified = modification_time(file_path) + add_cache_headers(context.response.headers, last_modified) + + if cache_request?(context, last_modified) + context.response.status_code = 304 + return + end send_file(context, file_path) else call_next(context) end end - - private def etag(context : HTTP::Server::Context, file_path : String) - etag = %{W/"#{File.info(file_path).modification_time.epoch.to_s}"} - context.response.headers["ETag"] = etag - return false if !context.request.headers["If-None-Match"]? || context.request.headers["If-None-Match"] != etag - context.response.headers.delete "Content-Type" - context.response.content_length = 0 - context.response.status_code = 304 # not modified - return true - end end end From 09bb1fcd4073a374b3a61c99e48e05a866b23c08 Mon Sep 17 00:00:00 2001 From: "Lewis E. Bogan" Date: Sun, 15 Jul 2018 19:55:53 -0700 Subject: [PATCH 6/6] add a VERSION constant (#471) --- spec/config_spec.cr | 8 ++++++++ src/kemal/config.cr | 2 ++ 2 files changed, 10 insertions(+) diff --git a/spec/config_spec.cr b/spec/config_spec.cr index 9ea27bc..65c44e7 100644 --- a/spec/config_spec.cr +++ b/spec/config_spec.cr @@ -54,4 +54,12 @@ describe "Config" do Kemal::CLI.new test_option.should eq("FOOBAR") end + + it "returns a string" do + Kemal::VERSION.should be_a(String) + end + + it "gets the version from shards.yml" do + Kemal::VERSION.should eq("0.23.0") + end end diff --git a/src/kemal/config.cr b/src/kemal/config.cr index d865c5e..508ec36 100644 --- a/src/kemal/config.cr +++ b/src/kemal/config.cr @@ -1,4 +1,6 @@ module Kemal + VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }} + # Stores all the configuration options for a Kemal application. # It's a singleton and you can access it like. #