From 0972589bc4fac2d673d122acf5866e2b7416ca25 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Sat, 16 Jul 2016 22:17:12 -0400 Subject: refactor etag and magic handling --- src/guff/context.cr | 3 ++- src/guff/etag.cr | 14 ++++++++++++ src/guff/handlers.cr | 61 +++++----------------------------------------------- 3 files changed, 21 insertions(+), 57 deletions(-) create mode 100644 src/guff/etag.cr diff --git a/src/guff/context.cr b/src/guff/context.cr index 7ab7b1e..6bb756e 100644 --- a/src/guff/context.cr +++ b/src/guff/context.cr @@ -1,8 +1,9 @@ class Guff::Context - getter :config, :dbs + getter :config, :dbs, :magic def initialize(@config : Config) @dbs = DatabasePair.new(@config.db_path, development?) + @magic = Magic.new end def models diff --git a/src/guff/etag.cr b/src/guff/etag.cr new file mode 100644 index 0000000..db24a88 --- /dev/null +++ b/src/guff/etag.cr @@ -0,0 +1,14 @@ +module Guff::ETag + def self.get_file_etag(path : String) + st = File.stat(path) + + # FIXME: rather than a hash this should be an HMAC + d = OpenSSL::Digest.new("SHA1") + + # FIXME: should this be inode rather than path? + d << "%s-%d-%d" % [path, st.size, st.mtime.epoch_ms] + + # return digest + d.hexdigest + end +end diff --git a/src/guff/handlers.cr b/src/guff/handlers.cr index 3ff58d0..a0cb335 100644 --- a/src/guff/handlers.cr +++ b/src/guff/handlers.cr @@ -140,11 +140,6 @@ module Guff::Handlers end class AssetsHandler < Handler - def initialize(context : Context) - super(context) - @etags = {} of String => String - end - def call(context : HTTP::Server::Context) req_path = context.request.path.not_nil! @@ -153,7 +148,7 @@ module Guff::Handlers # get expanded path to file if abs_path = expand_path(req_path) # get file digest - etag = get_file_etag(abs_path) + etag = ETag.get_file_etag(abs_path) # check for cache header if context.request.headers["if-none-match"]? == etag @@ -206,11 +201,6 @@ module Guff::Handlers # return path if file exists, or nil otherwise File.file?(r) ? r : nil end - - private def get_file_etag(path : String) : String - # FIXME: rather than a hash this should be an HMAC - @etags[path] ||= OpenSSL::Digest.new("SHA1").file(path).hexdigest - end end class AdminPageHandler < AuthenticatedHandler @@ -546,11 +536,6 @@ module Guff::Handlers # FIXME: this is very similar to AssetsHandler, so maybe combine them? class FilesHandler < Handler - def initialize(context : Context) - super(context) - @magic = Magic.new - end - def call(context : HTTP::Server::Context) req_path = context.request.path.not_nil! @@ -559,7 +544,7 @@ module Guff::Handlers # get expanded path to file if abs_path = expand_path(req_path) # get file digest - etag = get_file_etag(abs_path) + etag = ETag.get_file_etag(abs_path) # check for cache header if context.request.headers["if-none-match"]? == etag @@ -569,7 +554,7 @@ module Guff::Handlers # not cached, set code and send headers context.response.headers["x-frame-options"] = "SAMEORIGIN" context.response.status_code = 200 - context.response.content_type = get_mime_type(abs_path) + context.response.content_type = @context.magic.file(abs_path) context.response.content_length = File.size(abs_path) context.response.headers["etag"] = etag @@ -613,23 +598,6 @@ module Guff::Handlers # return path if file exists, or nil otherwise File.file?(r) ? r : nil end - - private def get_file_etag(path : String) : String - st = File.stat(path) - - # FIXME: rather than a hash this should be an HMAC - d = OpenSSL::Digest.new("SHA1") - - # FIXME: should this be inode rather than path? - d << "%s-%d-%d" % [path, st.size, st.mtime.epoch_ms] - - # return digest - d.hexdigest - end - - private def get_mime_type(path : String) : String - @magic.file(path) - end end # FIXME: this is very similar to FilesHandler and AssetsHandler, so @@ -637,7 +605,6 @@ module Guff::Handlers class FileAPIHandler < AuthenticatedHandler def initialize(context : Context) super(context, %w{admin editor}) - @magic = Magic.new end def authenticated_call(context : HTTP::Server::Context) @@ -648,7 +615,7 @@ module Guff::Handlers # get expanded path to file if abs_path = expand_path(req_path) # get file digest - etag = get_file_etag(abs_path) + etag = ETag.get_file_etag(abs_path) # check for cache header if context.request.headers["if-none-match"]? == etag @@ -658,7 +625,7 @@ module Guff::Handlers # not cached, set code and send headers context.response.headers["x-frame-options"] = "SAMEORIGIN" context.response.status_code = 200 - context.response.content_type = get_mime_type(abs_path) + context.response.content_type = @context.magic.file(abs_path) context.response.content_length = File.size(abs_path) context.response.headers["etag"] = etag context.response.headers["content-disposition"] = "attachment" @@ -702,26 +669,8 @@ module Guff::Handlers # return path if file exists, or nil otherwise File.file?(r) ? r : nil end - - private def get_file_etag(path : String) : String - st = File.stat(path) - - # FIXME: rather than a hash this should be an HMAC - d = OpenSSL::Digest.new("SHA1") - - # FIXME: should this be inode rather than path? - d << "%s-%d-%d" % [path, st.size, st.mtime.epoch_ms] - - # return digest - d.hexdigest - end - - private def get_mime_type(path : String) : String - @magic.file(path) - end end - HANDLERS = [{ :dev => true, :id => :stub, -- cgit v1.2.3