From 9edc34ef39f39922927bb920fb1d0cd0750158ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Celizna?= Date: Sun, 31 Mar 2024 14:57:26 +0200 Subject: [PATCH 1/7] Rack 3 compat --- lib/shrine/plugins/derivation_endpoint.rb | 57 +++++++-- lib/shrine/plugins/download_endpoint.rb | 19 ++- lib/shrine/plugins/presign_endpoint.rb | 19 ++- lib/shrine/plugins/rack_response.rb | 10 +- lib/shrine/plugins/upload_endpoint.rb | 19 ++- shrine.gemspec | 2 +- test/plugin/derivation_endpoint_test.rb | 146 +++++++++++----------- test/plugin/download_endpoint_test.rb | 34 ++--- test/plugin/presign_endpoint_test.rb | 26 ++-- test/plugin/rack_response_test.rb | 80 ++++++------ test/plugin/upload_endpoint_test.rb | 28 ++--- test/support/ext.rb | 16 +++ test/test_helper.rb | 9 ++ 13 files changed, 285 insertions(+), 180 deletions(-) diff --git a/lib/shrine/plugins/derivation_endpoint.rb b/lib/shrine/plugins/derivation_endpoint.rb index d175a8660..38b9226df 100644 --- a/lib/shrine/plugins/derivation_endpoint.rb +++ b/lib/shrine/plugins/derivation_endpoint.rb @@ -365,9 +365,20 @@ def call(env) handle_request(request) end - headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + headers ||= {} - [status, headers, body] + if Rack.release >= "3" + headers["content-length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s : + body.map(&:bytesize).inject(0, :+).to_s + else + headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + end + + if Rack.release >= "3" + [status, headers.transform_keys(&:downcase), body] + else + [status, headers, body] + end end # Verifies validity of the URL, then extracts parameters from it (such as @@ -411,7 +422,11 @@ def handle_request(request) headers["Cache-Control"] = derivation.option(:cache_control) end - [status, headers, body] + if Rack.release >= "3" + [status, headers.transform_keys(&:downcase), body] + else + [status, headers, body] + end end def inspect @@ -444,7 +459,11 @@ def expires_in(request) # Halts the request with the error message. def error!(status, message) - throw :halt, [status, { "Content-Type" => "text/plain" }, [message]] + if Rack.release >= "3" + throw :halt, [status, { "content-type" => "text/plain" }, [message]] + else + throw :halt, [status, { "Content-Type" => "text/plain" }, [message]] + end end def secret_key @@ -485,19 +504,33 @@ def file_response(file, env) status = response[0] - headers = { - "Content-Type" => type || response[1]["Content-Type"], - "Content-Length" => response[1]["Content-Length"], - "Content-Disposition" => content_disposition(file), - "Content-Range" => response[1]["Content-Range"], - "Accept-Ranges" => "bytes", - }.compact + headers = if Rack.release >= "3" + { + "content-type" => type || response[1]["content-type"], + "content-length" => response[1]["content-length"], + "content-disposition" => content_disposition(file), + "content-range" => response[1]["content-range"], + "accept-ranges" => "bytes", + }.compact + else + { + "Content-Type" => type || response[1]["Content-Type"], + "Content-Length" => response[1]["Content-Length"], + "Content-Disposition" => content_disposition(file), + "Content-Range" => response[1]["Content-Range"], + "Accept-Ranges" => "bytes", + }.compact + end body = Rack::BodyProxy.new(response[2]) { File.delete(file.path) } file.close - [status, headers, body] + if Rack.release >= "3" + [status, headers.transform_keys(&:downcase), body] + else + [status, headers, body] + end end # This is called when `:upload` is enabled. Checks the storage for already diff --git a/lib/shrine/plugins/download_endpoint.rb b/lib/shrine/plugins/download_endpoint.rb index 722c47437..75866696d 100644 --- a/lib/shrine/plugins/download_endpoint.rb +++ b/lib/shrine/plugins/download_endpoint.rb @@ -113,9 +113,18 @@ def call(env) handle_request(request) end - headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + if Rack.release >= "3" + headers["content-length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s : + body.map(&:bytesize).inject(0, :+).to_s + else + headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + end - [status, headers, body] + if Rack.release >= "3" + [status, headers.transform_keys(&:downcase), body] + else + [status, headers, body] + end end def inspect @@ -197,7 +206,11 @@ def bad_request!(message) # Halts the request with the error message. def error!(status, message) - throw :halt, [status, { "Content-Type" => "text/plain" }, [message]] + if Rack.release >= "3" + throw :halt, [status, { "content-type" => "text/plain" }, [message]] + else + throw :halt, [status, { "Content-Type" => "text/plain" }, [message]] + end end end end diff --git a/lib/shrine/plugins/presign_endpoint.rb b/lib/shrine/plugins/presign_endpoint.rb index 34e72025e..f2f295830 100644 --- a/lib/shrine/plugins/presign_endpoint.rb +++ b/lib/shrine/plugins/presign_endpoint.rb @@ -91,9 +91,18 @@ def call(env) end end - headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + if Rack.release >= "3" + headers["content-length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s : + body.map(&:bytesize).inject(0, :+).to_s + else + headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + end - [status, headers, body] + if Rack.release >= "3" + [status, headers.transform_keys(&:downcase), body] + else + [status, headers, body] + end end def inspect @@ -172,7 +181,11 @@ def make_response(object, request) # Used for early returning an error response. def error!(status, message) - throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]] + if Rack.release >= "3" + throw :halt, [status, { "content-type" => CONTENT_TYPE_TEXT }, [message]] + else + throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]] + end end # Returns the uploader around the specified storage. diff --git a/lib/shrine/plugins/rack_response.rb b/lib/shrine/plugins/rack_response.rb index e307fd64a..c5eb47301 100644 --- a/lib/shrine/plugins/rack_response.rb +++ b/lib/shrine/plugins/rack_response.rb @@ -32,7 +32,11 @@ def call(**options) headers = rack_headers(**options) body = rack_body(**options) - [status, headers, body] + if Rack.release >= "3" + [status, headers.transform_keys(&:downcase), body] + else + [status, headers, body] + end end private @@ -141,6 +145,10 @@ def close file.close end + def bytesize + each.inject(0) { |sum, chunk| sum += chunk.length } + end + # Rack::Sendfile is activated when response body responds to #to_path. def respond_to_missing?(name, include_private = false) name == :to_path && path diff --git a/lib/shrine/plugins/upload_endpoint.rb b/lib/shrine/plugins/upload_endpoint.rb index 84235fdcd..488f2ed71 100644 --- a/lib/shrine/plugins/upload_endpoint.rb +++ b/lib/shrine/plugins/upload_endpoint.rb @@ -91,9 +91,18 @@ def call(env) handle_request(request) end - headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + if Rack.release >= "3" + headers["content-length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s : + body.map(&:bytesize).inject(0, :+).to_s + else + headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s + end - [status, headers, body] + if Rack.release >= "3" + [status, headers.transform_keys(&:downcase), body] + else + [status, headers, body] + end end def inspect @@ -210,7 +219,11 @@ def verify_checksum!(file, request) # Used for early returning an error response. def error!(status, message) - throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]] + if Rack.release >= "3" + throw :halt, [status, { "content-type" => CONTENT_TYPE_TEXT }, [message]] + else + throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]] + end end # Returns the uploader around the specified storage. diff --git a/shrine.gemspec b/shrine.gemspec index 3878b93e6..5c2c3a36c 100644 --- a/shrine.gemspec +++ b/shrine.gemspec @@ -42,7 +42,7 @@ direct uploads for fully asynchronous user experience. gem.add_development_dependency "mocha", "~> 1.11" # for endpoint plugins - gem.add_development_dependency "rack", "~> 2.0" + gem.add_development_dependency "rack", ">= 2", "< 4" gem.add_development_dependency "http-form_data", "~> 2.2" gem.add_development_dependency "rack-test_app" diff --git a/test/plugin/derivation_endpoint_test.rb b/test/plugin/derivation_endpoint_test.rb index 1f6994f39..05cb77051 100644 --- a/test/plugin/derivation_endpoint_test.rb +++ b/test/plugin/derivation_endpoint_test.rb @@ -198,7 +198,7 @@ describe "Shrine.derivation_endpoint" do def app(*args, **options) - Rack::TestApp.wrap(Rack::Lint.new(endpoint(*args, **options))) + Rack::TestApp.wrap(Rack::Lint.new(endpoint(*args, **options)), { Rack::SERVER_PROTOCOL => "HTTP/1.1" }) end def endpoint(*args, **options) @@ -210,7 +210,7 @@ def endpoint(*args, **options) response = app.get(derivation_url) assert_equal 200, response.status assert_equal "gray dark content", response.body_binary - assert_equal "17", response.headers["Content-Length"] + assert_equal "17", response.headers[CONTENT_LENGTH_HEADER] end it "handles Range requests" do @@ -218,8 +218,8 @@ def endpoint(*args, **options) response = app.get(derivation_url, headers: { "Range" => "bytes=0-3" }) assert_equal 206, response.status assert_equal "gray", response.body_binary - assert_equal "4", response.headers["Content-Length"] - assert_equal "bytes 0-3/12", response.headers["Content-Range"] + assert_equal "4", response.headers[CONTENT_LENGTH_HEADER] + assert_equal "bytes 0-3/12", response.headers[CONTENT_RANGE_HEADER] end it "applies plugin options" do @@ -227,7 +227,7 @@ def endpoint(*args, **options) derivation_url = @uploaded_file.derivation_url(:gray) response = app.get(derivation_url) assert_equal 200, response.status - assert_match "attachment", response.headers["Content-Disposition"] + assert_match "attachment", response.headers[CONTENT_DISPOSITION_HEADER] end it "applies app options" do @@ -235,7 +235,7 @@ def endpoint(*args, **options) derivation_url = @uploaded_file.derivation_url(:gray) response = app(disposition: "attachment").get(derivation_url) assert_equal 200, response.status - assert_match "attachment", response.headers["Content-Disposition"] + assert_match "attachment", response.headers[CONTENT_DISPOSITION_HEADER] end it "applies 'type' param" do @@ -243,7 +243,7 @@ def endpoint(*args, **options) derivation_url = @uploaded_file.derivation_url(:gray, type: "text/csv") response = app(type: "text/plain").get(derivation_url) assert_equal 200, response.status - assert_equal "text/csv", response.headers["Content-Type"] + assert_equal "text/csv", response.headers[CONTENT_TYPE_HEADER] end it "applies 'disposition' param" do @@ -251,7 +251,7 @@ def endpoint(*args, **options) derivation_url = @uploaded_file.derivation_url(:gray, disposition: "attachment") response = app(disposition: "inline").get(derivation_url) assert_equal 200, response.status - assert_match "attachment", response.headers["Content-Disposition"] + assert_match "attachment", response.headers[CONTENT_DISPOSITION_HEADER] end it "applies 'filename' param" do @@ -259,7 +259,7 @@ def endpoint(*args, **options) derivation_url = @uploaded_file.derivation_url(:gray, filename: "custom") response = app(filename: "default").get(derivation_url) assert_equal 200, response.status - assert_match "filename=\"custom\"", response.headers["Content-Disposition"] + assert_match "filename=\"custom\"", response.headers[CONTENT_DISPOSITION_HEADER] end it "applies 'version' param" do @@ -267,41 +267,41 @@ def endpoint(*args, **options) derivation_url = @uploaded_file.derivation_url(:gray, version: 2) response = app(version: 1).get(derivation_url) assert_equal 200, response.status - assert_match "filename=\"2\"", response.headers["Content-Disposition"] + assert_match "filename=\"2\"", response.headers[CONTENT_DISPOSITION_HEADER] end it "returns Cache-Control header on 2xx response" do derivation_url = @uploaded_file.derivation_url(:gray) response = app.get(derivation_url) assert_equal 200, response.status - assert_equal "public, max-age=31536000", response.headers["Cache-Control"] + assert_equal "public, max-age=31536000", response.headers[CACHE_CONTROL_HEADER] derivation_url = @uploaded_file.derivation_url(:gray) response = app.get(derivation_url, headers: { "Range" => "bytes=0-3" }) assert_equal 206, response.status - assert_equal "public, max-age=31536000", response.headers["Cache-Control"] + assert_equal "public, max-age=31536000", response.headers[CACHE_CONTROL_HEADER] derivation_url = @uploaded_file.derivation_url(:gray) response = app(upload: true, upload_redirect: true).get(derivation_url) assert_equal 302, response.status - refute response.headers.key?("Cache-Control") + refute response.headers.key?(CACHE_CONTROL_HEADER) end it "applies :cache_control" do @shrine.plugin :derivation_endpoint, cache_control: "public, max-age=10" derivation_url = @uploaded_file.derivation_url(:gray) response = app.get(derivation_url) - assert_equal "public, max-age=10", response.headers["Cache-Control"] + assert_equal "public, max-age=10", response.headers[CACHE_CONTROL_HEADER] response = app(cache_control: "public, max-age=20").get(derivation_url) - assert_equal "public, max-age=20", response.headers["Cache-Control"] + assert_equal "public, max-age=20", response.headers[CACHE_CONTROL_HEADER] response = app(cache_control: -> { "public, max-age=20" }).get(derivation_url) - assert_equal "public, max-age=20", response.headers["Cache-Control"] + assert_equal "public, max-age=20", response.headers[CACHE_CONTROL_HEADER] derivation_url = @uploaded_file.derivation_url(:gray, expires_in: 100) response = app.get(derivation_url) - assert_equal "public, max-age=10", response.headers["Cache-Control"] + assert_equal "public, max-age=10", response.headers[CACHE_CONTROL_HEADER] end it "returns 404 on unknown derivation" do @@ -309,7 +309,7 @@ def endpoint(*args, **options) response = app.get(derivation_url) assert_equal 404, response.status assert_match "Unknown derivation", response.body_binary - assert_equal response.body_binary.length.to_s, response.headers["Content-Length"] + assert_equal response.body_binary.length.to_s, response.headers[CONTENT_LENGTH_HEADER] end it "returns 404 when source was not found" do @@ -318,17 +318,17 @@ def endpoint(*args, **options) response = app.get(derivation_url) assert_equal 404, response.status assert_match "Source file not found", response.body_binary - assert_equal response.body_binary.length.to_s, response.headers["Content-Length"] + assert_equal response.body_binary.length.to_s, response.headers[CONTENT_LENGTH_HEADER] end it "successfully handles expiring links that have not yet expired" do derivation_url = @uploaded_file.derivation_url(:gray, expires_in: 100) response = app.get(derivation_url) assert_equal 200, response.status - assert_equal "12", response.headers["Content-Length"] + assert_equal "12", response.headers[CONTENT_LENGTH_HEADER] # caching duration is limited by the expiration date - max_age = Integer(response.headers["Cache-Control"][/max-age=(\d+)/, 1]) + max_age = Integer(response.headers[CACHE_CONTROL_HEADER][/max-age=(\d+)/, 1]) assert_operator max_age, :<=, 100 assert_operator 0, :<, max_age end @@ -339,8 +339,8 @@ def endpoint(*args, **options) response = app.get(derivation_url) assert_equal 403, response.status assert_match "Request has expired", response.body_binary - assert_equal response.body_binary.length.to_s, response.headers["Content-Length"] - refute response.headers.key?("Cache-Control") + assert_equal response.body_binary.length.to_s, response.headers[CONTENT_LENGTH_HEADER] + refute response.headers.key?(CACHE_CONTROL_HEADER) end it "returns 403 on invalid signature" do @@ -349,8 +349,8 @@ def endpoint(*args, **options) response = app.get(derivation_url) assert_equal 403, response.status assert_match "signature does not match", response.body_binary - assert_equal response.body_binary.length.to_s, response.headers["Content-Length"] - refute response.headers.key?("Cache-Control") + assert_equal response.body_binary.length.to_s, response.headers[CONTENT_LENGTH_HEADER] + refute response.headers.key?(CACHE_CONTROL_HEADER) end it "returns 403 on missing signature" do @@ -359,8 +359,8 @@ def endpoint(*args, **options) response = app.get(derivation_url) assert_equal 403, response.status assert_match "Missing \"signature\" param", response.body_binary - assert_equal response.body_binary.length.to_s, response.headers["Content-Length"] - refute response.headers.key?("Cache-Control") + assert_equal response.body_binary.length.to_s, response.headers[CONTENT_LENGTH_HEADER] + refute response.headers.key?(CACHE_CONTROL_HEADER) end it "includes request params when calculating signature" do @@ -368,7 +368,7 @@ def endpoint(*args, **options) response = app.get(derivation_url) assert_equal 403, response.status assert_match "signature does not match", response.body_binary - assert_equal response.body_binary.length.to_s, response.headers["Content-Length"] + assert_equal response.body_binary.length.to_s, response.headers[CONTENT_LENGTH_HEADER] end it "skips signature verifcation when secret_key is nil" do @@ -378,14 +378,14 @@ def endpoint(*args, **options) derivation_url = @uploaded_file.derivation_url(:gray).sub(/signature=\w+$/, "") response = app.get(derivation_url) assert_equal 200, response.status - assert_equal "12", response.headers["Content-Length"] + assert_equal "12", response.headers[CONTENT_LENGTH_HEADER] end it "accepts HEAD requests" do derivation_url = @uploaded_file.derivation_url(:gray) response = app.head(derivation_url) assert_equal 200, response.status - assert_equal "12", response.headers["Content-Length"] + assert_equal "12", response.headers[CONTENT_LENGTH_HEADER] end it "returns 405 on invalid request method" do @@ -393,7 +393,7 @@ def endpoint(*args, **options) response = app.post(derivation_url) assert_equal 405, response.status assert_equal "Method not allowed", response.body_binary - assert_equal response.body_binary.length.to_s, response.headers["Content-Length"] + assert_equal response.body_binary.length.to_s, response.headers[CONTENT_LENGTH_HEADER] end it "defines #inspect and #to_s" do @@ -419,7 +419,7 @@ def endpoint(*args, **options) status, headers, body = @shrine.derivation_response(env) assert_equal 200, status - assert_equal "12", headers["Content-Length"] + assert_equal "12", headers[CONTENT_LENGTH_HEADER] assert_equal "gray content", body.enum_for(:each).to_a.join assert_equal "", env["SCRIPT_NAME"] @@ -461,7 +461,7 @@ def endpoint(*args, **options) status, headers, body = @shrine.derivation_response(env, type: "text/plain") assert_equal 200, status - assert_equal "text/plain", headers["Content-Type"] + assert_equal "text/plain", headers[CONTENT_TYPE_HEADER] end it "fails when request path doesn't start with prefix" do @@ -489,26 +489,26 @@ def endpoint(*args, **options) response = @uploaded_file.derivation_response(:gray, env: {}) assert_equal 200, response[0] - assert_equal "12", response[1]["Content-Length"] + assert_equal "12", response[1][CONTENT_LENGTH_HEADER] assert_equal "gray content", response[2].enum_for(:each).to_a.join end it "returns Content-Disposition" do response = @uploaded_file.derivation_response(:gray, env: {}) - assert_equal ContentDisposition.inline("gray-#{@uploaded_file.id}"), response[1]["Content-Disposition"] + assert_equal ContentDisposition.inline("gray-#{@uploaded_file.id}"), response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, "dark", env: {}) - assert_equal ContentDisposition.inline("gray-dark-#{@uploaded_file.id}"), response[1]["Content-Disposition"] + assert_equal ContentDisposition.inline("gray-dark-#{@uploaded_file.id}"), response[1][CONTENT_DISPOSITION_HEADER] @shrine.derivation(:gray) { |file| Tempfile.new(["derivation", ".txt"]) } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_equal ContentDisposition.inline("gray-#{@uploaded_file.id}.txt"), response[1]["Content-Disposition"] + assert_equal ContentDisposition.inline("gray-#{@uploaded_file.id}.txt"), response[1][CONTENT_DISPOSITION_HEADER] end it "returns Content-Type" do @shrine.derivation(:gray) { |file| Tempfile.new(["derivation", ".jpg"]) } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_equal "image/jpeg", response[1]["Content-Type"] + assert_equal "image/jpeg", response[1][CONTENT_TYPE_HEADER] @shrine.derivation(:gray) { |file| Tempfile.new(["derivation"]) } response = @uploaded_file.derivation_response(:gray, env: {}) @@ -520,33 +520,33 @@ def endpoint(*args, **options) @shrine.plugin :derivation_endpoint, type: "text/plain" response = @uploaded_file.derivation_response(:gray, env: {}) - assert_equal "text/plain", response[1]["Content-Type"] + assert_equal "text/plain", response[1][CONTENT_TYPE_HEADER] @shrine.plugin :derivation_endpoint, type: -> { "text/plain" } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_equal "text/plain", response[1]["Content-Type"] + assert_equal "text/plain", response[1][CONTENT_TYPE_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, type: "text/csv") - assert_equal "text/csv", response[1]["Content-Type"] + assert_equal "text/csv", response[1][CONTENT_TYPE_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, type: -> { "text/csv" }) - assert_equal "text/csv", response[1]["Content-Type"] + assert_equal "text/csv", response[1][CONTENT_TYPE_HEADER] end it "applies :disposition" do @shrine.plugin :derivation_endpoint, disposition: "attachment" response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "attachment; ", response[1]["Content-Disposition"] + assert_match "attachment; ", response[1][CONTENT_DISPOSITION_HEADER] @shrine.plugin :derivation_endpoint, disposition: -> { "attachment" } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "attachment; ", response[1]["Content-Disposition"] + assert_match "attachment; ", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, disposition: "inline") - assert_match "inline; ", response[1]["Content-Disposition"] + assert_match "inline; ", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, disposition: -> { "inline" }) - assert_match "inline; ", response[1]["Content-Disposition"] + assert_match "inline; ", response[1][CONTENT_DISPOSITION_HEADER] end it "applies :filename" do @@ -554,30 +554,30 @@ def endpoint(*args, **options) @shrine.plugin :derivation_endpoint, filename: "one" response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "inline; filename=\"one.txt\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"one.txt\"", response[1][CONTENT_DISPOSITION_HEADER] @shrine.plugin :derivation_endpoint, filename: -> { "one" } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "inline; filename=\"one.txt\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"one.txt\"", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, filename: "two.csv") - assert_match "inline; filename=\"two.csv\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"two.csv\"", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, filename: -> { "two.csv" }) - assert_match "inline; filename=\"two.csv\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"two.csv\"", response[1][CONTENT_DISPOSITION_HEADER] end it "handles Range requests" do response = @uploaded_file.derivation_response(:gray, env: { "HTTP_RANGE" => "bytes=0-3" }) assert_equal 206, response[0] - assert_equal "bytes 0-3/12", response[1]["Content-Range"] - assert_equal "bytes", response[1]["Accept-Ranges"] + assert_equal "bytes 0-3/12", response[1][CONTENT_RANGE_HEADER] + assert_equal "bytes", response[1][ACCEPT_RANGES_HEADER] assert_equal "gray", response[2].enum_for(:each).to_a.join response = @uploaded_file.derivation_response(:gray, env: {}) assert_equal 200, response[0] - assert_equal "bytes", response[1]["Accept-Ranges"] - refute response[1].key?("Content-Range") + assert_equal "bytes", response[1][ACCEPT_RANGES_HEADER] + refute response[1].key?(CONTENT_RANGE_HEADER) end it "closes and deletes derivation result" do @@ -605,7 +605,7 @@ def endpoint(*args, **options) response = @uploaded_file.derivation_response(:gray, env: {}) assert_equal 200, response[0] - assert_equal "12", response[1]["Content-Length"] + assert_equal "12", response[1][CONTENT_LENGTH_HEADER] assert_equal "gray content", response[2].enum_for(:each).to_a.join refute_instance_of Shrine::Plugins::RackResponse::FileBody, response[2] @@ -618,7 +618,7 @@ def endpoint(*args, **options) response = @uploaded_file.derivation_response(:gray, env: {}) assert_equal 200, response[0] - assert_equal "12", response[1]["Content-Length"] + assert_equal "12", response[1][CONTENT_LENGTH_HEADER] assert_equal "gray content", response[2].enum_for(:each).to_a.join end @@ -627,17 +627,17 @@ def endpoint(*args, **options) @shrine.plugin :derivation_endpoint, type: "text/plain" response = @uploaded_file.derivation_response(:gray, env: {}) - assert_equal "text/plain", response[1]["Content-Type"] + assert_equal "text/plain", response[1][CONTENT_TYPE_HEADER] @shrine.plugin :derivation_endpoint, type: -> { "text/plain" } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_equal "text/plain", response[1]["Content-Type"] + assert_equal "text/plain", response[1][CONTENT_TYPE_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, type: "text/csv") - assert_equal "text/csv", response[1]["Content-Type"] + assert_equal "text/csv", response[1][CONTENT_TYPE_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, type: -> { "text/csv" }) - assert_equal "text/csv", response[1]["Content-Type"] + assert_equal "text/csv", response[1][CONTENT_TYPE_HEADER] end it "applies :disposition" do @@ -645,17 +645,17 @@ def endpoint(*args, **options) @shrine.plugin :derivation_endpoint, disposition: "attachment" response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "attachment; ", response[1]["Content-Disposition"] + assert_match "attachment; ", response[1][CONTENT_DISPOSITION_HEADER] @shrine.plugin :derivation_endpoint, disposition: -> { "attachment" } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "attachment; ", response[1]["Content-Disposition"] + assert_match "attachment; ", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, disposition: "inline") - assert_match "inline; ", response[1]["Content-Disposition"] + assert_match "inline; ", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, disposition: -> { "inline" }) - assert_match "inline; ", response[1]["Content-Disposition"] + assert_match "inline; ", response[1][CONTENT_DISPOSITION_HEADER] end it "applies :filename" do @@ -663,33 +663,33 @@ def endpoint(*args, **options) @shrine.plugin :derivation_endpoint, filename: "one" response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "inline; filename=\"one\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"one\"", response[1][CONTENT_DISPOSITION_HEADER] @shrine.plugin :derivation_endpoint, filename: -> { "one" } response = @uploaded_file.derivation_response(:gray, env: {}) - assert_match "inline; filename=\"one\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"one\"", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, filename: "two") - assert_match "inline; filename=\"two\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"two\"", response[1][CONTENT_DISPOSITION_HEADER] response = @uploaded_file.derivation_response(:gray, env: {}, filename: -> { "two" }) - assert_match "inline; filename=\"two\"", response[1]["Content-Disposition"] + assert_match "inline; filename=\"two\"", response[1][CONTENT_DISPOSITION_HEADER] end it "handles Range requests" do @uploaded_file.derivation_response(:gray, env: {}) response = @uploaded_file.derivation_response(:gray, env: { "HTTP_RANGE" => "bytes=0-3" }) assert_equal 206, response[0] - assert_equal "bytes 0-3/12", response[1]["Content-Range"] - assert_equal "bytes", response[1]["Accept-Ranges"] + assert_equal "bytes 0-3/12", response[1][CONTENT_RANGE_HEADER] + assert_equal "bytes", response[1][ACCEPT_RANGES_HEADER] assert_equal "gray", response[2].enum_for(:each).to_a.join end it "returns ETag" do @uploaded_file.derivation_response(:gray, env: {}) response = @uploaded_file.derivation_response(:gray, env: {}) - assert_instance_of String, response[1]["ETag"] - assert_match /^W\/"\w{32}"$/, response[1]["ETag"] + assert_instance_of String, response[1][ETAG_HEADER] + assert_match /^W\/"\w{32}"$/, response[1][ETAG_HEADER] end it "applies :upload_open_options" do @@ -739,7 +739,7 @@ def upload(io, id, **options) response = @uploaded_file.derivation_response(:gray, env: {}) assert_equal 200, response[0] - assert_equal "12", response[1]["Content-Length"] + assert_equal "12", response[1][CONTENT_LENGTH_HEADER] assert_equal "gray content", response[2].enum_for(:each).to_a.join end diff --git a/test/plugin/download_endpoint_test.rb b/test/plugin/download_endpoint_test.rb index ab660ceec..05cecc969 100644 --- a/test/plugin/download_endpoint_test.rb +++ b/test/plugin/download_endpoint_test.rb @@ -4,7 +4,7 @@ describe Shrine::Plugins::DownloadEndpoint do def app - Rack::TestApp.wrap(Rack::Lint.new(endpoint)) + Rack::TestApp.wrap(Rack::Lint.new(endpoint), { Rack::SERVER_PROTOCOL => "HTTP/1.1" }) end def endpoint @@ -23,9 +23,9 @@ def endpoint response = app.get(@uploaded_file.download_url) assert_equal 200, response.status assert_equal @uploaded_file.read, response.body_binary - assert_equal @uploaded_file.size.to_s, response.headers["Content-Length"] - assert_equal @uploaded_file.mime_type, response.headers["Content-Type"] - assert_equal ContentDisposition.inline(@uploaded_file.original_filename), response.headers["Content-Disposition"] + assert_equal @uploaded_file.size.to_s, response.headers[CONTENT_LENGTH_HEADER] + assert_equal @uploaded_file.mime_type, response.headers[CONTENT_TYPE_HEADER] + assert_equal ContentDisposition.inline(@uploaded_file.original_filename), response.headers[CONTENT_DISPOSITION_HEADER] end it "applies :download_options hash" do @@ -45,46 +45,46 @@ def endpoint it "applies :disposition to response" do @shrine.plugin :download_endpoint, disposition: "attachment" response = app.get(@uploaded_file.download_url) - assert_equal ContentDisposition.attachment(@uploaded_file.id), response.headers["Content-Disposition"] + assert_equal ContentDisposition.attachment(@uploaded_file.id), response.headers[CONTENT_DISPOSITION_HEADER] end it "returns Cache-Control" do response = app.get(@uploaded_file.download_url) - assert_equal "max-age=31536000", response.headers["Cache-Control"] + assert_equal "max-age=31536000", response.headers[CACHE_CONTROL_HEADER] end it "accepts :redirect with true" do @shrine.plugin :download_endpoint, redirect: true response = app.get(@uploaded_file.download_url) assert_equal 302, response.status - assert_match %r{^memory://\w+$}, response.headers["Location"] + assert_match %r{^memory://\w+$}, response.headers[LOCATION_HEADER] end it "accepts :redirect with proc" do @shrine.plugin :download_endpoint, redirect: -> (uploaded_file, request) { "/foo" } response = app.get(@uploaded_file.download_url) assert_equal 302, response.status - assert_equal "/foo", response.headers["Location"] + assert_equal "/foo", response.headers[LOCATION_HEADER] end it "returns Accept-Ranges" do response = app.get(@uploaded_file.download_url) - assert_equal "bytes", response.headers["Accept-Ranges"] + assert_equal "bytes", response.headers[ACCEPT_RANGES_HEADER] end it "supports ranged requests" do @uploaded_file = @uploader.upload(fakeio("content")) response = app.get(@uploaded_file.download_url, headers: { "Range" => "bytes=2-4" }) assert_equal 206, response.status - assert_equal "bytes 2-4/7", response.headers["Content-Range"] - assert_equal "3", response.headers["Content-Length"] + assert_equal "bytes 2-4/7", response.headers[CONTENT_RANGE_HEADER] + assert_equal "3", response.headers[CONTENT_LENGTH_HEADER] assert_equal "nte", response.body_binary end it "returns ETag" do response = app.get(@uploaded_file.download_url) - assert_instance_of String, response.headers["ETag"] - assert_match /^W\/"\w{32}"$/, response.headers["ETag"] + assert_instance_of String, response.headers[ETAG_HEADER] + assert_match /^W\/"\w{32}"$/, response.headers[ETAG_HEADER] end it "returns 404 for nonexisting file" do @@ -125,9 +125,9 @@ def endpoint end it "accepts ad-hoc options" do - app = Rack::TestApp.wrap(@shrine.download_endpoint(disposition: "attachment")) + app = Rack::TestApp.wrap(@shrine.download_endpoint(disposition: "attachment"), { Rack::SERVER_PROTOCOL => "HTTP/1.1" }) response = app.get(@uploaded_file.download_url) - assert_match /^attachment; /, response.headers["Content-Disposition"] + assert_match /^attachment; /, response.headers[CONTENT_DISPOSITION_HEADER] end it "returns same URL regardless of metadata order" do @@ -165,7 +165,7 @@ def endpoint status, headers, body = @shrine.download_response(env) assert_equal 200, status - assert_equal @uploaded_file.size.to_s, headers["Content-Length"] + assert_equal @uploaded_file.size.to_s, headers[CONTENT_LENGTH_HEADER] assert_equal @uploaded_file.read, body.enum_for(:each).to_a.join assert_equal "", env["SCRIPT_NAME"] @@ -207,7 +207,7 @@ def endpoint status, headers, body = @shrine.download_response(env, disposition: "attachment") assert_equal 200, status - assert_match /^attachment; /, headers["Content-Disposition"] + assert_match /^attachment; /, headers[CONTENT_DISPOSITION_HEADER] end it "fails when request path doesn't start with prefix" do diff --git a/test/plugin/presign_endpoint_test.rb b/test/plugin/presign_endpoint_test.rb index 34cf53bff..248c3ce1a 100644 --- a/test/plugin/presign_endpoint_test.rb +++ b/test/plugin/presign_endpoint_test.rb @@ -5,7 +5,7 @@ describe Shrine::Plugins::PresignEndpoint do def app - Rack::TestApp.wrap(Rack::Lint.new(endpoint)) + Rack::TestApp.wrap(Rack::Lint.new(endpoint), { Rack::SERVER_PROTOCOL => "HTTP/1.1" }) end def endpoint @@ -23,9 +23,9 @@ def endpoint assert_equal 200, response.status - assert_equal "application/json; charset=utf-8", response.headers["Content-Type"] - assert_equal response.body_binary.bytesize.to_s, response.headers["Content-Length"] - assert_equal "no-store", response.headers["Cache-Control"] + assert_equal "application/json; charset=utf-8", response.headers[CONTENT_TYPE_HEADER] + assert_equal response.body_binary.bytesize.to_s, response.headers[CONTENT_LENGTH_HEADER] + assert_equal "no-store", response.headers[CACHE_CONTROL_HEADER] assert_instance_of String, response.body_json["method"] assert_instance_of String, response.body_json["url"] @@ -86,23 +86,23 @@ def endpoint it "accepts response proc" do @shrine.plugin :presign_endpoint, rack_response: -> (o, r) do - [200, {"Content-Type" => "application/vnd.api+json"}, [{data: o}.to_json]] + [200, {CONTENT_TYPE_HEADER => "application/vnd.api+json"}, [{data: o}.to_json]] end response = app.get "/" assert_equal ["fields", "headers", "method", "url"], JSON.parse(response.body_binary)["data"].keys.sort - assert_equal "application/vnd.api+json", response.headers["Content-Type"] + assert_equal "application/vnd.api+json", response.headers[CONTENT_TYPE_HEADER] end it "allows overriding Cache-Control" do @shrine.plugin :presign_endpoint, rack_response: -> (o, r) do - [200, {"Content-Type" => "application/json", "Cache-Control" => "no-cache"}, [o.to_json]] + [200, {CONTENT_TYPE_HEADER => "application/json", "Cache-Control" => "no-cache"}, [o.to_json]] end response = app.get "/" - assert_equal "no-cache", response.headers["Cache-Control"] + assert_equal "no-cache", response.headers[CACHE_CONTROL_HEADER] end it "allows overriding options when instantiating the endpoint" do - app = Rack::TestApp.wrap(@shrine.presign_endpoint(:cache, presign_options: { content_type: "image/jpeg" })) + app = Rack::TestApp.wrap(@shrine.presign_endpoint(:cache, presign_options: { content_type: "image/jpeg" }), { Rack::SERVER_PROTOCOL => "HTTP/1.1" }) response = app.get "/" assert_equal "image/jpeg", response.body_json["fields"]["Content-Type"] end @@ -111,7 +111,7 @@ def endpoint response = app.options "/" assert_equal 200, response.status - assert_equal Hash["Content-Length" => "0"], response.headers + assert_equal Hash[CONTENT_LENGTH_HEADER => "0"], response.headers assert_equal "", response.body_binary end @@ -123,7 +123,7 @@ def endpoint it "doesn't accept verbs other than GET or OPTIONS" do response = app.put "/" assert_equal 405, response.status - assert_equal "text/plain", response.headers["Content-Type"] + assert_equal "text/plain", response.headers[CONTENT_TYPE_HEADER] assert_equal "Method Not Allowed", response.body_binary end @@ -140,7 +140,7 @@ def endpoint response = @shrine.presign_response(:cache, env) assert_equal 200, response[0] - assert_equal "application/json; charset=utf-8", response[1]["Content-Type"] + assert_equal "application/json; charset=utf-8", response[1][CONTENT_TYPE_HEADER] assert_match /\.txt$/, JSON.parse(response[2].first)["fields"]["key"] end @@ -156,7 +156,7 @@ def endpoint response = @shrine.presign_response(:cache, env, presign_options: { content_type: "foo/bar" }) assert_equal 200, response[0] - assert_equal "application/json; charset=utf-8", response[1]["Content-Type"] + assert_equal "application/json; charset=utf-8", response[1][CONTENT_TYPE_HEADER] assert_equal "foo/bar", JSON.parse(response[2].first)["fields"]["Content-Type"] end end diff --git a/test/plugin/rack_response_test.rb b/test/plugin/rack_response_test.rb index a0cdb4492..f89e672a4 100644 --- a/test/plugin/rack_response_test.rb +++ b/test/plugin/rack_response_test.rb @@ -18,71 +18,71 @@ uploaded_file = @uploader.upload(fakeio("content")) uploaded_file.metadata.delete("size") response = uploaded_file.to_rack_response - assert_equal "7", response[1]["Content-Length"] + assert_equal "7", response[1][CONTENT_LENGTH_HEADER] end it "returns Content-Type header with mime_type metadata" do uploaded_file = @uploader.upload(fakeio(content_type: "text/plain")) response = uploaded_file.to_rack_response - assert_equal "text/plain", response[1]["Content-Type"] + assert_equal "text/plain", response[1][CONTENT_TYPE_HEADER] end it "returns Content-Type header from extension if mime_type metadata is missing" do uploaded_file = @uploader.upload(fakeio(filename: "document.txt")) response = uploaded_file.to_rack_response - assert_equal "text/plain", response[1]["Content-Type"] + assert_equal "text/plain", response[1][CONTENT_TYPE_HEADER] end it "doesn't return Content-Type header if MIME type is unknown" do uploaded_file = @uploader.upload(fakeio(filename: "foo.foo")) response = uploaded_file.to_rack_response - refute response[1].key?("Content-Type") + refute response[1].key?(CONTENT_TYPE_HEADER) end it "doesn't Content-Type header if MIME type is missing" do uploaded_file = @uploader.upload(fakeio) response = uploaded_file.to_rack_response - refute response[1].key?("Content-Type") + refute response[1].key?(CONTENT_TYPE_HEADER) end it "returns Content-Type header from :type" do uploaded_file = @uploader.upload(fakeio(content_type: "text/plain")) response = uploaded_file.to_rack_response(type: "text/plain; charset=utf-8") - assert_equal "text/plain; charset=utf-8", response[1]["Content-Type"] + assert_equal "text/plain; charset=utf-8", response[1][CONTENT_TYPE_HEADER] end it "it allows setting Content-Type to application/octet-stream" do uploaded_file = @uploader.upload(fakeio(content_type: "application/octet-stream")) response = uploaded_file.to_rack_response - assert_equal "application/octet-stream", response[1]["Content-Type"] + assert_equal "application/octet-stream", response[1][CONTENT_TYPE_HEADER] uploaded_file = @uploader.upload(fakeio) response = uploaded_file.to_rack_response(type: "application/octet-stream") - assert_equal "application/octet-stream", response[1]["Content-Type"] + assert_equal "application/octet-stream", response[1][CONTENT_TYPE_HEADER] end it "returns Content-Disposition filename from metadata" do uploaded_file = @uploader.upload(fakeio(filename: "plain.txt")) response = uploaded_file.to_rack_response - assert_equal ContentDisposition.inline("plain.txt"), response[1]["Content-Disposition"] + assert_equal ContentDisposition.inline("plain.txt"), response[1][CONTENT_DISPOSITION_HEADER] end it "returns Content-Disposition filename from :filename" do uploaded_file = @uploader.upload(fakeio(filename: "plain.txt")) response = uploaded_file.to_rack_response(filename: "custom.txt") - assert_equal ContentDisposition.inline("custom.txt"), response[1]["Content-Disposition"] + assert_equal ContentDisposition.inline("custom.txt"), response[1][CONTENT_DISPOSITION_HEADER] end it "returns Content-Disposition filename with id if metadata is missing" do uploaded_file = @uploader.upload(fakeio, location: "foo/bar/baz") response = uploaded_file.to_rack_response - assert_equal ContentDisposition.inline("baz"), response[1]["Content-Disposition"] + assert_equal ContentDisposition.inline("baz"), response[1][CONTENT_DISPOSITION_HEADER] end it "returns Content-Disposition disposition from :disposition" do uploaded_file = @uploader.upload(fakeio) response = uploaded_file.to_rack_response(disposition: "attachment") - assert_equal ContentDisposition.attachment(uploaded_file.id), response[1]["Content-Disposition"] + assert_equal ContentDisposition.attachment(uploaded_file.id), response[1][CONTENT_DISPOSITION_HEADER] end it "returns body which yields contents of the file" do @@ -114,69 +114,69 @@ uploaded_file = @uploader.upload(fakeio("content")) response = uploaded_file.to_rack_response(range: "bytes=0-6") assert_equal 206, response[0] - assert_equal "bytes 0-6/7", response[1]["Content-Range"] - assert_equal "7", response[1]["Content-Length"] + assert_equal "bytes 0-6/7", response[1][CONTENT_RANGE_HEADER] + assert_equal "7", response[1][CONTENT_LENGTH_HEADER] assert_equal "content", response[2].each { |chunk| break chunk } uploaded_file = @uploader.upload(fakeio("content")) response = uploaded_file.to_rack_response(range: "bytes=0-2") assert_equal 206, response[0] - assert_equal "bytes 0-2/7", response[1]["Content-Range"] - assert_equal "3", response[1]["Content-Length"] + assert_equal "bytes 0-2/7", response[1][CONTENT_RANGE_HEADER] + assert_equal "3", response[1][CONTENT_LENGTH_HEADER] assert_equal "con", response[2].each { |chunk| break chunk } uploaded_file = @uploader.upload(fakeio("content")) response = uploaded_file.to_rack_response(range: "bytes=2-4") assert_equal 206, response[0] - assert_equal "bytes 2-4/7", response[1]["Content-Range"] - assert_equal "3", response[1]["Content-Length"] + assert_equal "bytes 2-4/7", response[1][CONTENT_RANGE_HEADER] + assert_equal "3", response[1][CONTENT_LENGTH_HEADER] assert_equal "nte", response[2].each { |chunk| break chunk } uploaded_file = @uploader.upload(fakeio("content")) response = uploaded_file.to_rack_response(range: "bytes=4-6") assert_equal 206, response[0] - assert_equal "bytes 4-6/7", response[1]["Content-Range"] - assert_equal "3", response[1]["Content-Length"] + assert_equal "bytes 4-6/7", response[1][CONTENT_RANGE_HEADER] + assert_equal "3", response[1][CONTENT_LENGTH_HEADER] assert_equal "ent", response[2].each { |chunk| break chunk } end it "returns ranged responses across multiple chunks" do uploaded_file = @uploader.upload(fakeio("a" * 16*1024 + "b" * 16*1024 + "c" * 4*1024)) response = uploaded_file.to_rack_response(range: "bytes=0-36863") - assert_equal "bytes 0-36863/36864", response[1]["Content-Range"] - assert_equal "36864", response[1]["Content-Length"] + assert_equal "bytes 0-36863/36864", response[1][CONTENT_RANGE_HEADER] + assert_equal "36864", response[1][CONTENT_LENGTH_HEADER] yielded_content = "" response[2].each { |chunk| yielded_content << chunk } assert_equal "a" * 16*1024 + "b" * 16*1024 + "c" * 4*1024, yielded_content uploaded_file = @uploader.upload(fakeio("a" * 16*1024 + "b" * 16*1024 + "c" * 4*1024)) response = uploaded_file.to_rack_response(range: "bytes=0-20479") - assert_equal "bytes 0-20479/36864", response[1]["Content-Range"] - assert_equal "20480", response[1]["Content-Length"] + assert_equal "bytes 0-20479/36864", response[1][CONTENT_RANGE_HEADER] + assert_equal "20480", response[1][CONTENT_LENGTH_HEADER] yielded_content = "" response[2].each { |chunk| yielded_content << chunk } assert_equal "a" * 16*1024 + "b" * 4*1024, yielded_content uploaded_file = @uploader.upload(fakeio("a" * 16*1024 + "b" * 16*1024 + "c" * 4*1024)) response = uploaded_file.to_rack_response(range: "bytes=12288-20479") - assert_equal "bytes 12288-20479/36864", response[1]["Content-Range"] - assert_equal "8192", response[1]["Content-Length"] + assert_equal "bytes 12288-20479/36864", response[1][CONTENT_RANGE_HEADER] + assert_equal "8192", response[1][CONTENT_LENGTH_HEADER] yielded_content = "" response[2].each { |chunk| yielded_content << chunk } assert_equal "a" * 4*1024 + "b" * 4*1024, yielded_content uploaded_file = @uploader.upload(fakeio("a" * 16*1024 + "b" * 16*1024 + "c" * 4*1024)) response = uploaded_file.to_rack_response(range: "bytes=12288-33791") - assert_equal "bytes 12288-33791/36864", response[1]["Content-Range"] - assert_equal "21504", response[1]["Content-Length"] + assert_equal "bytes 12288-33791/36864", response[1][CONTENT_RANGE_HEADER] + assert_equal "21504", response[1][CONTENT_LENGTH_HEADER] yielded_content = "" response[2].each { |chunk| yielded_content << chunk } assert_equal "a" * 4*1024 + "b" * 16*1024 + "c" * 1*1024, yielded_content uploaded_file = @uploader.upload(fakeio("a" * 16*1024 + "b" * 16*1024 + "c" * 4*1024)) response = uploaded_file.to_rack_response(range: "bytes=35840-36863") - assert_equal "bytes 35840-36863/36864", response[1]["Content-Range"] - assert_equal "1024", response[1]["Content-Length"] + assert_equal "bytes 35840-36863/36864", response[1][CONTENT_RANGE_HEADER] + assert_equal "1024", response[1][CONTENT_LENGTH_HEADER] yielded_content = "" response[2].each { |chunk| yielded_content << chunk } assert_equal "c" * 1*1024, yielded_content @@ -187,24 +187,24 @@ uploaded_file.metadata.delete("size") response = uploaded_file.to_rack_response(range: "bytes=0-6") assert_equal 206, response[0] - assert_equal "bytes 0-6/7", response[1]["Content-Range"] - assert_equal "7", response[1]["Content-Length"] + assert_equal "bytes 0-6/7", response[1][CONTENT_RANGE_HEADER] + assert_equal "7", response[1][CONTENT_LENGTH_HEADER] assert_equal "content", response[2].each { |chunk| break chunk } end it "returns Accept-Ranges when :range is given" do uploaded_file = @uploader.upload(fakeio) response = uploaded_file.to_rack_response - refute response[1].key?("Accept-Ranges") + refute response[1].key?(ACCEPT_RANGES_HEADER) response = uploaded_file.to_rack_response(range: nil) - assert_equal "bytes", response[1]["Accept-Ranges"] + assert_equal "bytes", response[1][ACCEPT_RANGES_HEADER] end it "returns ETag" do uploaded_file = @uploader.upload(fakeio) response = uploaded_file.to_rack_response - assert_instance_of String, response[1]["ETag"] - assert_match /^W\/"\w{32}"$/, response[1]["ETag"] + assert_instance_of String, response[1][ETAG_HEADER] + assert_match /^W\/"\w{32}"$/, response[1][ETAG_HEADER] end it "makes ETag as unique as possible" do @@ -212,19 +212,19 @@ etags << @uploader.class.new(:cache) .upload(fakeio, location: "foo") - .to_rack_response[1]["ETag"] + .to_rack_response[1][ETAG_HEADER] etags << @uploader.class.new(:cache) .upload(fakeio, location: "bar") - .to_rack_response[1]["ETag"] + .to_rack_response[1][ETAG_HEADER] etags << @uploader.class.new(:store) .upload(fakeio, location: "foo") - .to_rack_response[1]["ETag"] + .to_rack_response[1][ETAG_HEADER] etags << uploader { plugin :rack_response } .upload(fakeio, location: "foo") - .to_rack_response[1]["ETag"] + .to_rack_response[1][ETAG_HEADER] assert_equal etags, etags.uniq end diff --git a/test/plugin/upload_endpoint_test.rb b/test/plugin/upload_endpoint_test.rb index f23698c9c..91750987f 100644 --- a/test/plugin/upload_endpoint_test.rb +++ b/test/plugin/upload_endpoint_test.rb @@ -5,7 +5,7 @@ describe Shrine::Plugins::UploadEndpoint do def app - Rack::TestApp.wrap(Rack::Lint.new(endpoint)) + Rack::TestApp.wrap(Rack::Lint.new(endpoint), { Rack::SERVER_PROTOCOL => "HTTP/1.1" }) end def endpoint @@ -21,7 +21,7 @@ def endpoint response = app.post "/", multipart: { file: image } assert_equal 200, response.status - assert_equal "application/json; charset=utf-8", response.headers["Content-Type"] + assert_equal "application/json; charset=utf-8", response.headers[CONTENT_TYPE_HEADER] assert_match /^\w+\.jpg$/, response.body_json["id"] assert_equal "cache", response.body_json["storage"] @@ -64,28 +64,28 @@ def endpoint @shrine.plugin :upload_endpoint, max_size: 10 response = app.post "/", multipart: { file: image } assert_equal 413, response.status - assert_equal "text/plain", response.headers["Content-Type"] + assert_equal "text/plain", response.headers[CONTENT_TYPE_HEADER] assert_equal "Upload Too Large", response.body_binary end it "validates that param is a file" do response = app.post "/", multipart: { file: "image" } assert_equal 400, response.status - assert_equal "text/plain", response.headers["Content-Type"] + assert_equal "text/plain", response.headers[CONTENT_TYPE_HEADER] assert_equal "Upload Not Valid", response.body_binary end it "validates that param is present" do response = app.post "/", multipart: { image: "image" } assert_equal 400, response.status - assert_equal "text/plain", response.headers["Content-Type"] + assert_equal "text/plain", response.headers[CONTENT_TYPE_HEADER] assert_equal "Upload Not Found", response.body_binary end it "handles filenames with UTF-8 characters" do filename = "über_pdf_with_1337%_leetness.pdf" form = HTTP::FormData.create({ file: HTTP::FormData::Part.new("", filename: filename) }) - response = app.post "/", multipart: { input: form.to_s }, headers: {"Content-Type" => form.content_type} + response = app.post "/", multipart: { input: form.to_s }, headers: {CONTENT_TYPE_HEADER => form.content_type} assert_equal 200, response.status uploaded_file = @shrine.uploaded_file(response.body_json) assert_equal filename, uploaded_file.original_filename @@ -144,27 +144,27 @@ def endpoint it "accepts response proc" do @shrine.plugin :upload_endpoint, rack_response: -> (o, r) do - [200, {"Content-Type" => "application/vnd.api+json"}, [{data: o}.to_json]] + [200, {CONTENT_TYPE_HEADER => "application/vnd.api+json"}, [{data: o}.to_json]] end response = app.post "/", multipart: { file: image } assert_equal ["id", "storage", "metadata"], JSON.parse(response.body_binary)["data"].keys - assert_equal "application/vnd.api+json", response.headers["Content-Type"] + assert_equal "application/vnd.api+json", response.headers[CONTENT_TYPE_HEADER] end it "allows overriding options when instantiating the endpoint" do - app = Rack::TestApp.wrap(@shrine.upload_endpoint(:cache, max_size: 10)) + app = Rack::TestApp.wrap(@shrine.upload_endpoint(:cache, max_size: 10), { Rack::SERVER_PROTOCOL => "HTTP/1.1" }) response = app.post "/", multipart: { file: image } assert_equal 413, response.status end it "doesn't react to parseable Content-Type" do - response = app.post "/", headers: { "Content-Type" => "application/x-www-form-urlencoded" } + response = app.post "/", headers: { CONTENT_TYPE_HEADER => "application/x-www-form-urlencoded" } assert_equal 400, response.status assert_equal "Upload Not Found", response.body_binary end it "doesn't react to blank Content-Type" do - response = app.post "/", headers: { "Content-Type" => "" } + response = app.post "/", headers: { CONTENT_TYPE_HEADER => "" } assert_equal 400, response.status assert_equal "Upload Not Found", response.body_binary end @@ -172,7 +172,7 @@ def endpoint it "accepts only POST requests" do response = app.put "/", multipart: { file: image } assert_equal 405, response.status - assert_equal "text/plain", response.headers["Content-Type"] + assert_equal "text/plain", response.headers[CONTENT_TYPE_HEADER] assert_equal "Method Not Allowed", response.body_binary end @@ -199,7 +199,7 @@ def endpoint response = @shrine.upload_response(:cache, env) assert_equal 200, response[0] - assert_equal "application/json; charset=utf-8", response[1]["Content-Type"] + assert_equal "application/json; charset=utf-8", response[1][CONTENT_TYPE_HEADER] assert_equal "content", @shrine.uploaded_file(response[2].first).read end @@ -220,7 +220,7 @@ def endpoint response = @shrine.upload_response(:cache, env, max_size: 1) assert_equal 413, response[0] - assert_equal "text/plain", response[1]["Content-Type"] + assert_equal "text/plain", response[1][CONTENT_TYPE_HEADER] assert_equal "Upload Too Large", response[2].first end end diff --git a/test/support/ext.rb b/test/support/ext.rb index 307bba938..af1dbe286 100644 --- a/test/support/ext.rb +++ b/test/support/ext.rb @@ -9,3 +9,19 @@ class Rack::TestApp::Wrapper alias_method verb, verb.upcase end end + +module RackTestAppResultPatch + def body_binary + @body_binary ||= super + end + + def body_text + @body_text ||= super + end + + def body_json + @body_json ||= super + end +end + +Rack::TestApp::Result.send(:prepend, RackTestAppResultPatch) diff --git a/test/test_helper.rb b/test/test_helper.rb index 66426eef4..5d3789cf1 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -39,3 +39,12 @@ def self.load(data) eval(data) end end + +ACCEPT_RANGES_HEADER = Rack.release >= "3" ? "accept-ranges" : "Accept-Ranges" +CACHE_CONTROL_HEADER = Rack.release >= "3" ? "cache-control" : "Cache-Control" +CONTENT_DISPOSITION_HEADER = Rack.release >= "3" ? "content-disposition" : "Content-Disposition" +CONTENT_LENGTH_HEADER = Rack.release >= "3" ? "content-length" : "Content-Length" +CONTENT_RANGE_HEADER = Rack.release >= "3" ? "content-range" : "Content-Range" +CONTENT_TYPE_HEADER = Rack.release >= "3" ? "content-type" : "Content-Type" +ETAG_HEADER = Rack.release >= "3" ? "etag" : "ETag" +LOCATION_HEADER = Rack.release >= "3" ? "location" : "Location" From f418af21efc7ee55923f2b86ba5d308b3676fb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Celizna?= Date: Mon, 1 Apr 2024 10:41:53 +0200 Subject: [PATCH 2/7] add appraisals to test on both Rack 2 & 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • drop Ruby 2.3 test --- .github/workflows/ci.yml | 39 +++++---- Appraisals | 7 ++ gemfiles/rack_2.gemfile | 10 +++ gemfiles/rack_2.gemfile.lock | 161 +++++++++++++++++++++++++++++++++++ gemfiles/rack_3.gemfile | 10 +++ gemfiles/rack_3.gemfile.lock | 161 +++++++++++++++++++++++++++++++++++ shrine.gemspec | 1 + 7 files changed, 371 insertions(+), 18 deletions(-) create mode 100644 Appraisals create mode 100644 gemfiles/rack_2.gemfile create mode 100644 gemfiles/rack_2.gemfile.lock create mode 100644 gemfiles/rack_3.gemfile create mode 100644 gemfiles/rack_3.gemfile.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e763de5a..23a80316b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ '**' ] + branches: ["**"] env: RACK_ENV: development @@ -24,7 +24,6 @@ jobs: fail-fast: false matrix: ruby: - - "2.3" - "2.4" - "2.5" - "2.6" @@ -32,24 +31,28 @@ jobs: - "3.0" - "3.1" - "3.2" + - "3.3" - "jruby-9.4" + rack: + - "2" + - "3" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v3 - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - rubygems: ${{ matrix.ruby <= '2.5' && '3.3.26' || 'latest' }} + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + rubygems: ${{ matrix.ruby <= '2.5' && '3.3.26' || 'latest' }} - - name: Set up Minio - run: | - mkdir -p "${GITHUB_WORKSPACE}"/minio/data/minio-bucket - wget -nc -O "${GITHUB_WORKSPACE}"/minio/minio https://dl.min.io/server/minio/release/linux-amd64/minio - chmod +x "${GITHUB_WORKSPACE}"/minio/minio - ${GITHUB_WORKSPACE}/minio/minio server ${GITHUB_WORKSPACE}/minio/data --address localhost:9000 &>${GITHUB_WORKSPACE}/minio/data/server.log & + - name: Set up Minio + run: | + mkdir -p "${GITHUB_WORKSPACE}"/minio/data/minio-bucket + wget -nc -O "${GITHUB_WORKSPACE}"/minio/minio https://dl.min.io/server/minio/release/linux-amd64/minio + chmod +x "${GITHUB_WORKSPACE}"/minio/minio + ${GITHUB_WORKSPACE}/minio/minio server ${GITHUB_WORKSPACE}/minio/data --address localhost:9000 &>${GITHUB_WORKSPACE}/minio/data/server.log & - - name: Run tests - run: bundle exec rake test + - name: Run tests + run: bundle exec appraisal rack-${{ matrix.rack }} rake test diff --git a/Appraisals b/Appraisals new file mode 100644 index 000000000..f5b330cf7 --- /dev/null +++ b/Appraisals @@ -0,0 +1,7 @@ +appraise "rack-2" do + gem "rack", "~> 2" +end + +appraise "rack-3" do + gem "rack", "~> 3" +end diff --git a/gemfiles/rack_2.gemfile b/gemfiles/rack_2.gemfile new file mode 100644 index 000000000..0b47a3a30 --- /dev/null +++ b/gemfiles/rack_2.gemfile @@ -0,0 +1,10 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "pry" +gem "simplecov" +gem "hanna", require: false +gem "rack", "~> 2" + +gemspec path: "../" diff --git a/gemfiles/rack_2.gemfile.lock b/gemfiles/rack_2.gemfile.lock new file mode 100644 index 000000000..c74a73316 --- /dev/null +++ b/gemfiles/rack_2.gemfile.lock @@ -0,0 +1,161 @@ +PATH + remote: .. + specs: + shrine (3.5.0) + content_disposition (~> 1.0) + down (~> 5.1) + +GEM + remote: https://rubygems.org/ + specs: + activemodel (7.1.3.2) + activesupport (= 7.1.3.2) + activerecord (7.1.3.2) + activemodel (= 7.1.3.2) + activesupport (= 7.1.3.2) + timeout (>= 0.4.0) + activesupport (7.1.3.2) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) + addressable (2.8.6) + public_suffix (>= 2.0.2, < 6.0) + appraisal (2.5.0) + bundler + rake + thor (>= 0.14.0) + aws-eventstream (1.3.0) + aws-partitions (1.904.0) + aws-sdk-core (3.191.5) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.8) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.78.0) + aws-sdk-core (~> 3, >= 3.191.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.146.1) + aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) + aws-eventstream (~> 1, >= 1.0.2) + base64 (0.2.0) + bigdecimal (3.1.7) + coderay (1.1.3) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) + content_disposition (1.0.0) + docile (1.4.0) + down (5.4.1) + addressable (~> 2.8) + drb (2.2.1) + dry-configurable (1.1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.1) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-events (1.0.1) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-monitor (1.0.1) + dry-configurable (~> 1.0, < 2) + dry-core (~> 1.0, < 2) + dry-events (~> 1.0, < 2) + fastimage (2.3.0) + ffi (1.16.3) + hanna (1.5.0) + rdoc (>= 4) + http-form_data (2.3.0) + i18n (1.14.4) + concurrent-ruby (~> 1.0) + jmespath (1.6.2) + marcel (1.0.4) + method_source (1.0.0) + mime-types (3.5.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2024.0305) + mimemagic (0.4.3) + nokogiri (~> 1) + rake + mini_magick (4.12.0) + mini_mime (1.1.5) + minitest (5.22.3) + mocha (1.16.1) + mutex_m (0.2.0) + nokogiri (1.16.3-arm64-darwin) + racc (~> 1.4) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + psych (5.1.2) + stringio + public_suffix (5.0.4) + racc (1.7.3) + rack (2.2.9) + rack-test_app (1.1.0) + rack + rake (13.1.0) + rdoc (6.6.3.1) + psych (>= 4.0.0) + rexml (3.2.6) + ruby-filemagic (0.7.3) + ruby-vips (2.2.1) + ffi (~> 1.12) + sequel (5.78.0) + bigdecimal + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) + sqlite3 (1.7.3-arm64-darwin) + stringio (3.1.0) + thor (1.3.1) + timeout (0.4.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + zeitwerk (2.6.13) + +PLATFORMS + arm64-darwin + +DEPENDENCIES + activerecord (~> 7.0) + activesupport (~> 7.0) + appraisal (~> 2.5) + aws-sdk-core (~> 3.23) + aws-sdk-s3 (~> 1.69) + dry-monitor + fastimage + hanna + http-form_data (~> 2.2) + marcel + mime-types + mimemagic (>= 0.3.2) + mini_magick (~> 4.0) + mini_mime (~> 1.0) + minitest (~> 5.8) + mocha (~> 1.11) + pry + rack (~> 2) + rack-test_app + rake (>= 11.1) + rexml + ruby-filemagic (~> 0.7) + ruby-vips (~> 2.0) + sequel + shrine! + simplecov + sqlite3 (~> 1.4) + +BUNDLED WITH + 2.5.4 diff --git a/gemfiles/rack_3.gemfile b/gemfiles/rack_3.gemfile new file mode 100644 index 000000000..c3394c647 --- /dev/null +++ b/gemfiles/rack_3.gemfile @@ -0,0 +1,10 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "pry" +gem "simplecov" +gem "hanna", require: false +gem "rack", "~> 3" + +gemspec path: "../" diff --git a/gemfiles/rack_3.gemfile.lock b/gemfiles/rack_3.gemfile.lock new file mode 100644 index 000000000..8276eed92 --- /dev/null +++ b/gemfiles/rack_3.gemfile.lock @@ -0,0 +1,161 @@ +PATH + remote: .. + specs: + shrine (3.5.0) + content_disposition (~> 1.0) + down (~> 5.1) + +GEM + remote: https://rubygems.org/ + specs: + activemodel (7.1.3.2) + activesupport (= 7.1.3.2) + activerecord (7.1.3.2) + activemodel (= 7.1.3.2) + activesupport (= 7.1.3.2) + timeout (>= 0.4.0) + activesupport (7.1.3.2) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + minitest (>= 5.1) + mutex_m + tzinfo (~> 2.0) + addressable (2.8.6) + public_suffix (>= 2.0.2, < 6.0) + appraisal (2.5.0) + bundler + rake + thor (>= 0.14.0) + aws-eventstream (1.3.0) + aws-partitions (1.904.0) + aws-sdk-core (3.191.5) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.8) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.78.0) + aws-sdk-core (~> 3, >= 3.191.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.146.1) + aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) + aws-eventstream (~> 1, >= 1.0.2) + base64 (0.2.0) + bigdecimal (3.1.7) + coderay (1.1.3) + concurrent-ruby (1.2.3) + connection_pool (2.4.1) + content_disposition (1.0.0) + docile (1.4.0) + down (5.4.1) + addressable (~> 2.8) + drb (2.2.1) + dry-configurable (1.1.0) + dry-core (~> 1.0, < 2) + zeitwerk (~> 2.6) + dry-core (1.0.1) + concurrent-ruby (~> 1.0) + zeitwerk (~> 2.6) + dry-events (1.0.1) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-monitor (1.0.1) + dry-configurable (~> 1.0, < 2) + dry-core (~> 1.0, < 2) + dry-events (~> 1.0, < 2) + fastimage (2.3.0) + ffi (1.16.3) + hanna (1.5.0) + rdoc (>= 4) + http-form_data (2.3.0) + i18n (1.14.4) + concurrent-ruby (~> 1.0) + jmespath (1.6.2) + marcel (1.0.4) + method_source (1.0.0) + mime-types (3.5.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2024.0305) + mimemagic (0.4.3) + nokogiri (~> 1) + rake + mini_magick (4.12.0) + mini_mime (1.1.5) + minitest (5.22.3) + mocha (1.16.1) + mutex_m (0.2.0) + nokogiri (1.16.3-arm64-darwin) + racc (~> 1.4) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + psych (5.1.2) + stringio + public_suffix (5.0.4) + racc (1.7.3) + rack (3.0.10) + rack-test_app (1.1.0) + rack + rake (13.1.0) + rdoc (6.6.3.1) + psych (>= 4.0.0) + rexml (3.2.6) + ruby-filemagic (0.7.3) + ruby-vips (2.2.1) + ffi (~> 1.12) + sequel (5.78.0) + bigdecimal + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) + sqlite3 (1.7.3-arm64-darwin) + stringio (3.1.0) + thor (1.3.1) + timeout (0.4.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + zeitwerk (2.6.13) + +PLATFORMS + arm64-darwin + +DEPENDENCIES + activerecord (~> 7.0) + activesupport (~> 7.0) + appraisal (~> 2.5) + aws-sdk-core (~> 3.23) + aws-sdk-s3 (~> 1.69) + dry-monitor + fastimage + hanna + http-form_data (~> 2.2) + marcel + mime-types + mimemagic (>= 0.3.2) + mini_magick (~> 4.0) + mini_mime (~> 1.0) + minitest (~> 5.8) + mocha (~> 1.11) + pry + rack (~> 3) + rack-test_app + rake (>= 11.1) + rexml + ruby-filemagic (~> 0.7) + ruby-vips (~> 2.0) + sequel + shrine! + simplecov + sqlite3 (~> 1.4) + +BUNDLED WITH + 2.5.4 diff --git a/shrine.gemspec b/shrine.gemspec index 5c2c3a36c..26912822d 100644 --- a/shrine.gemspec +++ b/shrine.gemspec @@ -37,6 +37,7 @@ direct uploads for fully asynchronous user experience. gem.add_dependency "content_disposition", "~> 1.0" # general testing helpers + gem.add_development_dependency "appraisal", "~> 2.5" gem.add_development_dependency "rake", ">= 11.1" gem.add_development_dependency "minitest", "~> 5.8" gem.add_development_dependency "mocha", "~> 1.11" From 02124cc8a2cdd668fdde335653dc36839719a892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Celizna?= Date: Mon, 1 Apr 2024 18:23:20 +0200 Subject: [PATCH 3/7] install appraisals --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23a80316b..b6f9c7652 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,5 +54,8 @@ jobs: chmod +x "${GITHUB_WORKSPACE}"/minio/minio ${GITHUB_WORKSPACE}/minio/minio server ${GITHUB_WORKSPACE}/minio/data --address localhost:9000 &>${GITHUB_WORKSPACE}/minio/data/server.log & + - name: Install dependencies + run: bundle exec appraisal install + - name: Run tests run: bundle exec appraisal rack-${{ matrix.rack }} rake test From 7ac48d2c94f047ef41e238163661bbdcae164180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Celizna?= Date: Mon, 1 Apr 2024 19:03:02 +0200 Subject: [PATCH 4/7] remove lockfiles --- gemfiles/rack_2.gemfile.lock | 161 ----------------------------------- gemfiles/rack_3.gemfile.lock | 161 ----------------------------------- 2 files changed, 322 deletions(-) delete mode 100644 gemfiles/rack_2.gemfile.lock delete mode 100644 gemfiles/rack_3.gemfile.lock diff --git a/gemfiles/rack_2.gemfile.lock b/gemfiles/rack_2.gemfile.lock deleted file mode 100644 index c74a73316..000000000 --- a/gemfiles/rack_2.gemfile.lock +++ /dev/null @@ -1,161 +0,0 @@ -PATH - remote: .. - specs: - shrine (3.5.0) - content_disposition (~> 1.0) - down (~> 5.1) - -GEM - remote: https://rubygems.org/ - specs: - activemodel (7.1.3.2) - activesupport (= 7.1.3.2) - activerecord (7.1.3.2) - activemodel (= 7.1.3.2) - activesupport (= 7.1.3.2) - timeout (>= 0.4.0) - activesupport (7.1.3.2) - base64 - bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) - appraisal (2.5.0) - bundler - rake - thor (>= 0.14.0) - aws-eventstream (1.3.0) - aws-partitions (1.904.0) - aws-sdk-core (3.191.5) - aws-eventstream (~> 1, >= 1.3.0) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) - jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.78.0) - aws-sdk-core (~> 3, >= 3.191.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.146.1) - aws-sdk-core (~> 3, >= 3.191.0) - aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) - aws-eventstream (~> 1, >= 1.0.2) - base64 (0.2.0) - bigdecimal (3.1.7) - coderay (1.1.3) - concurrent-ruby (1.2.3) - connection_pool (2.4.1) - content_disposition (1.0.0) - docile (1.4.0) - down (5.4.1) - addressable (~> 2.8) - drb (2.2.1) - dry-configurable (1.1.0) - dry-core (~> 1.0, < 2) - zeitwerk (~> 2.6) - dry-core (1.0.1) - concurrent-ruby (~> 1.0) - zeitwerk (~> 2.6) - dry-events (1.0.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0, < 2) - dry-monitor (1.0.1) - dry-configurable (~> 1.0, < 2) - dry-core (~> 1.0, < 2) - dry-events (~> 1.0, < 2) - fastimage (2.3.0) - ffi (1.16.3) - hanna (1.5.0) - rdoc (>= 4) - http-form_data (2.3.0) - i18n (1.14.4) - concurrent-ruby (~> 1.0) - jmespath (1.6.2) - marcel (1.0.4) - method_source (1.0.0) - mime-types (3.5.2) - mime-types-data (~> 3.2015) - mime-types-data (3.2024.0305) - mimemagic (0.4.3) - nokogiri (~> 1) - rake - mini_magick (4.12.0) - mini_mime (1.1.5) - minitest (5.22.3) - mocha (1.16.1) - mutex_m (0.2.0) - nokogiri (1.16.3-arm64-darwin) - racc (~> 1.4) - pry (0.14.2) - coderay (~> 1.1) - method_source (~> 1.0) - psych (5.1.2) - stringio - public_suffix (5.0.4) - racc (1.7.3) - rack (2.2.9) - rack-test_app (1.1.0) - rack - rake (13.1.0) - rdoc (6.6.3.1) - psych (>= 4.0.0) - rexml (3.2.6) - ruby-filemagic (0.7.3) - ruby-vips (2.2.1) - ffi (~> 1.12) - sequel (5.78.0) - bigdecimal - simplecov (0.22.0) - docile (~> 1.1) - simplecov-html (~> 0.11) - simplecov_json_formatter (~> 0.1) - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.4) - sqlite3 (1.7.3-arm64-darwin) - stringio (3.1.0) - thor (1.3.1) - timeout (0.4.1) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - zeitwerk (2.6.13) - -PLATFORMS - arm64-darwin - -DEPENDENCIES - activerecord (~> 7.0) - activesupport (~> 7.0) - appraisal (~> 2.5) - aws-sdk-core (~> 3.23) - aws-sdk-s3 (~> 1.69) - dry-monitor - fastimage - hanna - http-form_data (~> 2.2) - marcel - mime-types - mimemagic (>= 0.3.2) - mini_magick (~> 4.0) - mini_mime (~> 1.0) - minitest (~> 5.8) - mocha (~> 1.11) - pry - rack (~> 2) - rack-test_app - rake (>= 11.1) - rexml - ruby-filemagic (~> 0.7) - ruby-vips (~> 2.0) - sequel - shrine! - simplecov - sqlite3 (~> 1.4) - -BUNDLED WITH - 2.5.4 diff --git a/gemfiles/rack_3.gemfile.lock b/gemfiles/rack_3.gemfile.lock deleted file mode 100644 index 8276eed92..000000000 --- a/gemfiles/rack_3.gemfile.lock +++ /dev/null @@ -1,161 +0,0 @@ -PATH - remote: .. - specs: - shrine (3.5.0) - content_disposition (~> 1.0) - down (~> 5.1) - -GEM - remote: https://rubygems.org/ - specs: - activemodel (7.1.3.2) - activesupport (= 7.1.3.2) - activerecord (7.1.3.2) - activemodel (= 7.1.3.2) - activesupport (= 7.1.3.2) - timeout (>= 0.4.0) - activesupport (7.1.3.2) - base64 - bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) - appraisal (2.5.0) - bundler - rake - thor (>= 0.14.0) - aws-eventstream (1.3.0) - aws-partitions (1.904.0) - aws-sdk-core (3.191.5) - aws-eventstream (~> 1, >= 1.3.0) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.8) - jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.78.0) - aws-sdk-core (~> 3, >= 3.191.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.146.1) - aws-sdk-core (~> 3, >= 3.191.0) - aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) - aws-eventstream (~> 1, >= 1.0.2) - base64 (0.2.0) - bigdecimal (3.1.7) - coderay (1.1.3) - concurrent-ruby (1.2.3) - connection_pool (2.4.1) - content_disposition (1.0.0) - docile (1.4.0) - down (5.4.1) - addressable (~> 2.8) - drb (2.2.1) - dry-configurable (1.1.0) - dry-core (~> 1.0, < 2) - zeitwerk (~> 2.6) - dry-core (1.0.1) - concurrent-ruby (~> 1.0) - zeitwerk (~> 2.6) - dry-events (1.0.1) - concurrent-ruby (~> 1.0) - dry-core (~> 1.0, < 2) - dry-monitor (1.0.1) - dry-configurable (~> 1.0, < 2) - dry-core (~> 1.0, < 2) - dry-events (~> 1.0, < 2) - fastimage (2.3.0) - ffi (1.16.3) - hanna (1.5.0) - rdoc (>= 4) - http-form_data (2.3.0) - i18n (1.14.4) - concurrent-ruby (~> 1.0) - jmespath (1.6.2) - marcel (1.0.4) - method_source (1.0.0) - mime-types (3.5.2) - mime-types-data (~> 3.2015) - mime-types-data (3.2024.0305) - mimemagic (0.4.3) - nokogiri (~> 1) - rake - mini_magick (4.12.0) - mini_mime (1.1.5) - minitest (5.22.3) - mocha (1.16.1) - mutex_m (0.2.0) - nokogiri (1.16.3-arm64-darwin) - racc (~> 1.4) - pry (0.14.2) - coderay (~> 1.1) - method_source (~> 1.0) - psych (5.1.2) - stringio - public_suffix (5.0.4) - racc (1.7.3) - rack (3.0.10) - rack-test_app (1.1.0) - rack - rake (13.1.0) - rdoc (6.6.3.1) - psych (>= 4.0.0) - rexml (3.2.6) - ruby-filemagic (0.7.3) - ruby-vips (2.2.1) - ffi (~> 1.12) - sequel (5.78.0) - bigdecimal - simplecov (0.22.0) - docile (~> 1.1) - simplecov-html (~> 0.11) - simplecov_json_formatter (~> 0.1) - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.4) - sqlite3 (1.7.3-arm64-darwin) - stringio (3.1.0) - thor (1.3.1) - timeout (0.4.1) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - zeitwerk (2.6.13) - -PLATFORMS - arm64-darwin - -DEPENDENCIES - activerecord (~> 7.0) - activesupport (~> 7.0) - appraisal (~> 2.5) - aws-sdk-core (~> 3.23) - aws-sdk-s3 (~> 1.69) - dry-monitor - fastimage - hanna - http-form_data (~> 2.2) - marcel - mime-types - mimemagic (>= 0.3.2) - mini_magick (~> 4.0) - mini_mime (~> 1.0) - minitest (~> 5.8) - mocha (~> 1.11) - pry - rack (~> 3) - rack-test_app - rake (>= 11.1) - rexml - ruby-filemagic (~> 0.7) - ruby-vips (~> 2.0) - sequel - shrine! - simplecov - sqlite3 (~> 1.4) - -BUNDLED WITH - 2.5.4 From c31a6ae08f26ac1ce747cb1d3d8798e03d6a0be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Celizna?= Date: Mon, 1 Apr 2024 19:03:56 +0200 Subject: [PATCH 5/7] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 313608364..cc041148f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ website/build coverage/ node_modules .docusaurus +gemfiles/*.lock From d65c9e702bddb687fd6aa2375f7d523f82f09672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Celizna?= Date: Tue, 23 Apr 2024 11:05:37 +0200 Subject: [PATCH 6/7] downcase headers refactor to `headers = headers.transform_keys(&:downcase) if Rack.release >= "3"` --- lib/shrine/plugins/derivation_endpoint.rb | 34 ++++++++++------------- lib/shrine/plugins/download_endpoint.rb | 18 ++++++------ lib/shrine/plugins/presign_endpoint.rb | 18 ++++++------ lib/shrine/plugins/upload_endpoint.rb | 18 ++++++------ 4 files changed, 38 insertions(+), 50 deletions(-) diff --git a/lib/shrine/plugins/derivation_endpoint.rb b/lib/shrine/plugins/derivation_endpoint.rb index 38b9226df..27fef576a 100644 --- a/lib/shrine/plugins/derivation_endpoint.rb +++ b/lib/shrine/plugins/derivation_endpoint.rb @@ -374,11 +374,9 @@ def call(env) headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s end - if Rack.release >= "3" - [status, headers.transform_keys(&:downcase), body] - else - [status, headers, body] - end + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + [status, headers, body] end # Verifies validity of the URL, then extracts parameters from it (such as @@ -422,11 +420,9 @@ def handle_request(request) headers["Cache-Control"] = derivation.option(:cache_control) end - if Rack.release >= "3" - [status, headers.transform_keys(&:downcase), body] - else - [status, headers, body] - end + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + [status, headers, body] end def inspect @@ -459,11 +455,11 @@ def expires_in(request) # Halts the request with the error message. def error!(status, message) - if Rack.release >= "3" - throw :halt, [status, { "content-type" => "text/plain" }, [message]] - else - throw :halt, [status, { "Content-Type" => "text/plain" }, [message]] - end + headers = { "Content-Type" => "text/plain" } + + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + throw :halt, [status, headers, [message]] end def secret_key @@ -526,11 +522,9 @@ def file_response(file, env) file.close - if Rack.release >= "3" - [status, headers.transform_keys(&:downcase), body] - else - [status, headers, body] - end + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + [status, headers, body] end # This is called when `:upload` is enabled. Checks the storage for already diff --git a/lib/shrine/plugins/download_endpoint.rb b/lib/shrine/plugins/download_endpoint.rb index 75866696d..768376209 100644 --- a/lib/shrine/plugins/download_endpoint.rb +++ b/lib/shrine/plugins/download_endpoint.rb @@ -120,11 +120,9 @@ def call(env) headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s end - if Rack.release >= "3" - [status, headers.transform_keys(&:downcase), body] - else - [status, headers, body] - end + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + [status, headers, body] end def inspect @@ -206,11 +204,11 @@ def bad_request!(message) # Halts the request with the error message. def error!(status, message) - if Rack.release >= "3" - throw :halt, [status, { "content-type" => "text/plain" }, [message]] - else - throw :halt, [status, { "Content-Type" => "text/plain" }, [message]] - end + headers = { "Content-Type" => "text/plain" } + + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + throw :halt, [status, headers, [message]] end end end diff --git a/lib/shrine/plugins/presign_endpoint.rb b/lib/shrine/plugins/presign_endpoint.rb index f2f295830..c8330f96a 100644 --- a/lib/shrine/plugins/presign_endpoint.rb +++ b/lib/shrine/plugins/presign_endpoint.rb @@ -98,11 +98,9 @@ def call(env) headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s end - if Rack.release >= "3" - [status, headers.transform_keys(&:downcase), body] - else - [status, headers, body] - end + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + [status, headers, body] end def inspect @@ -181,11 +179,11 @@ def make_response(object, request) # Used for early returning an error response. def error!(status, message) - if Rack.release >= "3" - throw :halt, [status, { "content-type" => CONTENT_TYPE_TEXT }, [message]] - else - throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]] - end + headers = { "Content-Type" => CONTENT_TYPE_TEXT } + + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + throw :halt, [status, headers, [message]] end # Returns the uploader around the specified storage. diff --git a/lib/shrine/plugins/upload_endpoint.rb b/lib/shrine/plugins/upload_endpoint.rb index 488f2ed71..8e271af80 100644 --- a/lib/shrine/plugins/upload_endpoint.rb +++ b/lib/shrine/plugins/upload_endpoint.rb @@ -98,11 +98,9 @@ def call(env) headers["Content-Length"] ||= body.map(&:bytesize).inject(0, :+).to_s end - if Rack.release >= "3" - [status, headers.transform_keys(&:downcase), body] - else - [status, headers, body] - end + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + [status, headers, body] end def inspect @@ -219,11 +217,11 @@ def verify_checksum!(file, request) # Used for early returning an error response. def error!(status, message) - if Rack.release >= "3" - throw :halt, [status, { "content-type" => CONTENT_TYPE_TEXT }, [message]] - else - throw :halt, [status, { "Content-Type" => CONTENT_TYPE_TEXT }, [message]] - end + headers = { "Content-Type" => CONTENT_TYPE_TEXT } + + headers = headers.transform_keys(&:downcase) if Rack.release >= "3" + + throw :halt, [status, headers, [message]] end # Returns the uploader around the specified storage. From 5d109ca48c3d0dd3528ea987a0c5e0976fa65479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Celizna?= Date: Tue, 23 Apr 2024 11:07:29 +0200 Subject: [PATCH 7/7] update `activerecord-jdbcsqlite3-adapter` --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index bae8c28c9..9b00365dd 100644 --- a/Gemfile +++ b/Gemfile @@ -7,4 +7,4 @@ gem "simplecov" gem "hanna", require: false -gem "activerecord-jdbcsqlite3-adapter", "~> 70.0", platform: :jruby if RUBY_ENGINE == "jruby" +gem "activerecord-jdbcsqlite3-adapter", "~> 51.0", platform: :jruby if RUBY_ENGINE == "jruby"