From 17c5a4420f5d2acc2e733bd5efa693b16436e9bf Mon Sep 17 00:00:00 2001 From: Mikhail Arzhaev Date: Tue, 16 Mar 2021 20:17:01 +0300 Subject: [PATCH 1/2] Move head_object_output to the dedicated folder. Add frequently used etag and meta accessors. --- src/awscr-s3/client.cr | 2 ++ src/awscr-s3/{ => responses}/head_object_output.cr | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) rename src/awscr-s3/{ => responses}/head_object_output.cr (69%) diff --git a/src/awscr-s3/client.cr b/src/awscr-s3/client.cr index f2bdd69..b790bd8 100644 --- a/src/awscr-s3/client.cr +++ b/src/awscr-s3/client.cr @@ -268,6 +268,8 @@ module Awscr::S3 # p resp.size # => 123 # p resp.status # => HTTP::Status::OK # p resp.last_modified # => "Wed, 19 Jun 2019 11:55:33 GMT" + # p resp.etag # => "" + # p resp.meta # => {"my_tag" => "my_value"} # ``` def head_object(bucket, object : String, headers : Hash(String, String) = Hash(String, String).new) resp = http.head("/#{bucket}/#{Util.encode(object)}", headers: headers) diff --git a/src/awscr-s3/head_object_output.cr b/src/awscr-s3/responses/head_object_output.cr similarity index 69% rename from src/awscr-s3/head_object_output.cr rename to src/awscr-s3/responses/head_object_output.cr index 99b02c4..b7e34ed 100644 --- a/src/awscr-s3/head_object_output.cr +++ b/src/awscr-s3/responses/head_object_output.cr @@ -9,10 +9,18 @@ module Awscr::S3::Response getter content_type : String getter last_modified : Time getter size : UInt64 + getter etag : String + getter meta : Hash(String, String) # Create a `GetObjectOutput` response from an # `HTTP::Client::Response` object - def self.from_response(response) + def self.from_response(response : HTTP::Client::Response) + meta = {} of String => String + response.headers.each do |k, v| + next unless k.starts_with?("x-amz-meta-") + meta[k.lchop("x-amz-meta-")] = v.first + end + new( status: response.status, status_message: response.status_message, @@ -20,10 +28,12 @@ module Awscr::S3::Response content_type: response.headers["Content-Type"], last_modified: self.parse_date(response.headers["Last-Modified"]), size: response.headers["Content-Length"].to_u64, + etag: response.headers["ETag"].strip('"'), + meta: meta ) end - def initialize(@status, @status_message, @headers, @content_type, @last_modified, @size) + def initialize(@status, @status_message, @headers, @content_type, @last_modified, @size, @etag, @meta) end private def self.parse_date(date : String) From 8c5aabc15eff05f1861d6fe450e09b4b1a043ec6 Mon Sep 17 00:00:00 2001 From: Mikhail Arzhaev Date: Tue, 16 Mar 2021 20:33:41 +0300 Subject: [PATCH 2/2] Move frequently accessed response data from class init to class's instance methods. --- src/awscr-s3/responses/head_object_output.cr | 49 ++++++++++++-------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/awscr-s3/responses/head_object_output.cr b/src/awscr-s3/responses/head_object_output.cr index b7e34ed..204b55e 100644 --- a/src/awscr-s3/responses/head_object_output.cr +++ b/src/awscr-s3/responses/head_object_output.cr @@ -6,37 +6,48 @@ module Awscr::S3::Response getter status : HTTP::Status getter status_message : String | Nil getter headers : HTTP::Headers - getter content_type : String - getter last_modified : Time - getter size : UInt64 - getter etag : String - getter meta : Hash(String, String) # Create a `GetObjectOutput` response from an # `HTTP::Client::Response` object def self.from_response(response : HTTP::Client::Response) - meta = {} of String => String - response.headers.each do |k, v| - next unless k.starts_with?("x-amz-meta-") - meta[k.lchop("x-amz-meta-")] = v.first - end - new( status: response.status, status_message: response.status_message, - headers: response.headers, - content_type: response.headers["Content-Type"], - last_modified: self.parse_date(response.headers["Last-Modified"]), - size: response.headers["Content-Length"].to_u64, - etag: response.headers["ETag"].strip('"'), - meta: meta + headers: response.headers ) end - def initialize(@status, @status_message, @headers, @content_type, @last_modified, @size, @etag, @meta) + def initialize(@status, @status_message, @headers) + end + + {% for f in ["Cache-Control", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-Type",] %} + def {{ f.id.stringify.underscore.gsub(/-/, "_").id }} : String? + headers["{{ f.id }}"]? + end + {% end %} + + def last_modified : Time + parse_date(headers["Last-Modified"]) + end + + def size : UInt64 + headers["Content-Length"].to_u64 + end + + def etag : String? + headers["ETag"].try{|v| v.strip('"')} + end + + def meta : Hash(String, String) + meta = {} of String => String + response.headers.each do |k, v| + next unless k.starts_with?("x-amz-meta-") + meta[k.lchop("x-amz-meta-")] = v.first + end + meta end - private def self.parse_date(date : String) + private def parse_date(date : String) Time.parse!(date.gsub(/\s{2,}/, ' '), DATE_FORMAT) end end