mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 02:11:08 -06:00
DEV: Add both safe and unsafe Discourse.store.download methods (#21498)
* DEV: Add both safe and unsafe Discourse.store.download methods * DEV: Update call sites that can use the safe store download method
This commit is contained in:
parent
4e846b69c4
commit
b837459e1d
@ -55,13 +55,8 @@ class OptimizedImage < ActiveRecord::Base
|
|||||||
|
|
||||||
if original_path.blank?
|
if original_path.blank?
|
||||||
# download is protected with a DistributedMutex
|
# download is protected with a DistributedMutex
|
||||||
external_copy =
|
external_copy = Discourse.store.download_safe(upload)
|
||||||
begin
|
original_path = external_copy&.path
|
||||||
Discourse.store.download(upload)
|
|
||||||
rescue StandardError
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
original_path = external_copy.try(:path)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
lock(upload.id, width, height) do
|
lock(upload.id, width, height) do
|
||||||
|
@ -189,13 +189,8 @@ class ThemeField < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
if Discourse.store.external?
|
if Discourse.store.external?
|
||||||
external_copy =
|
external_copy = Discourse.store.download_safe(upload)
|
||||||
begin
|
path = external_copy&.path
|
||||||
Discourse.store.download(upload)
|
|
||||||
rescue StandardError
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
path = external_copy.try(:path)
|
|
||||||
else
|
else
|
||||||
path = Discourse.store.path_for(upload)
|
path = Discourse.store.path_for(upload)
|
||||||
end
|
end
|
||||||
|
@ -160,13 +160,8 @@ class Upload < ActiveRecord::Base
|
|||||||
# this is relatively cheap once cached
|
# this is relatively cheap once cached
|
||||||
original_path = Discourse.store.path_for(self)
|
original_path = Discourse.store.path_for(self)
|
||||||
if original_path.blank?
|
if original_path.blank?
|
||||||
external_copy =
|
external_copy = Discourse.store.download_safe(self)
|
||||||
begin
|
original_path = external_copy&.path
|
||||||
Discourse.store.download(self)
|
|
||||||
rescue StandardError
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
original_path = external_copy.try(:path)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
image_info =
|
image_info =
|
||||||
@ -361,13 +356,7 @@ class Upload < ActiveRecord::Base
|
|||||||
if local?
|
if local?
|
||||||
Discourse.store.path_for(self)
|
Discourse.store.path_for(self)
|
||||||
else
|
else
|
||||||
begin
|
Discourse.store.download_safe(self)&.path
|
||||||
Discourse.store.download(self)&.path
|
|
||||||
rescue OpenURI::HTTPError => e
|
|
||||||
# Some issue with downloading the image from a remote store.
|
|
||||||
# Assume the upload is broken and save an empty string to prevent re-evaluation
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if local_path.nil?
|
if local_path.nil?
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module FileStore
|
module FileStore
|
||||||
|
class DownloadError < StandardError
|
||||||
|
end
|
||||||
|
|
||||||
class BaseStore
|
class BaseStore
|
||||||
UPLOAD_PATH_REGEX ||= %r{/(original/\d+X/.*)}
|
UPLOAD_PATH_REGEX ||= %r{/(original/\d+X/.*)}
|
||||||
OPTIMIZED_IMAGE_PATH_REGEX ||= %r{/(optimized/\d+X/.*)}
|
OPTIMIZED_IMAGE_PATH_REGEX ||= %r{/(optimized/\d+X/.*)}
|
||||||
@ -88,7 +91,26 @@ module FileStore
|
|||||||
not_implemented
|
not_implemented
|
||||||
end
|
end
|
||||||
|
|
||||||
def download(object, max_file_size_kb: nil)
|
# TODO: Remove when #download becomes the canonical safe version.
|
||||||
|
def download_safe(*, **)
|
||||||
|
download(*, **, print_deprecation: false)
|
||||||
|
rescue StandardError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def download!(*, **)
|
||||||
|
download(*, **, print_deprecation: false)
|
||||||
|
rescue StandardError
|
||||||
|
raise DownloadError
|
||||||
|
end
|
||||||
|
|
||||||
|
def download(object, max_file_size_kb: nil, print_deprecation: true)
|
||||||
|
Discourse.deprecate(<<~MESSAGE, output_in_test: true) if print_deprecation
|
||||||
|
In a future version `FileStore#download` will no longer raise an error when the
|
||||||
|
download fails, and will instead return `nil`. If you need a method that raises
|
||||||
|
an error, use `FileStore#download!`, which raises a `FileStore::DownloadError`.
|
||||||
|
MESSAGE
|
||||||
|
|
||||||
DistributedMutex.synchronize("download_#{object.sha1}", validity: 3.minutes) do
|
DistributedMutex.synchronize("download_#{object.sha1}", validity: 3.minutes) do
|
||||||
extension =
|
extension =
|
||||||
File.extname(
|
File.extname(
|
||||||
|
@ -1200,13 +1200,7 @@ task "uploads:downsize" => :environment do
|
|||||||
if upload.local?
|
if upload.local?
|
||||||
Discourse.store.path_for(upload)
|
Discourse.store.path_for(upload)
|
||||||
else
|
else
|
||||||
(
|
Discourse.store.download_safe(upload, max_file_size_kb: 100.megabytes)&.path
|
||||||
begin
|
|
||||||
Discourse.store.download(upload, max_file_size_kb: 100.megabytes)
|
|
||||||
rescue StandardError
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
)&.path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
unless path
|
unless path
|
||||||
|
@ -189,16 +189,16 @@ RSpec.describe FileStore::BaseStore do
|
|||||||
# Net::HTTP always returns binary ASCII-8BIT encoding. File.read auto-detects the encoding
|
# Net::HTTP always returns binary ASCII-8BIT encoding. File.read auto-detects the encoding
|
||||||
# Make sure we File.read after downloading a file for consistency
|
# Make sure we File.read after downloading a file for consistency
|
||||||
|
|
||||||
first_encoding = store.download(upload_s3).read.encoding
|
first_encoding = store.download(upload_s3, print_deprecation: false).read.encoding
|
||||||
|
|
||||||
second_encoding = store.download(upload_s3).read.encoding
|
second_encoding = store.download(upload_s3, print_deprecation: false).read.encoding
|
||||||
|
|
||||||
expect(first_encoding).to eq(Encoding::UTF_8)
|
expect(first_encoding).to eq(Encoding::UTF_8)
|
||||||
expect(second_encoding).to eq(Encoding::UTF_8)
|
expect(second_encoding).to eq(Encoding::UTF_8)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return the file" do
|
it "should return the file" do
|
||||||
file = store.download(upload_s3)
|
file = store.download(upload_s3, print_deprecation: false)
|
||||||
|
|
||||||
expect(file.class).to eq(File)
|
expect(file.class).to eq(File)
|
||||||
end
|
end
|
||||||
@ -210,7 +210,7 @@ RSpec.describe FileStore::BaseStore do
|
|||||||
body: "Hello world",
|
body: "Hello world",
|
||||||
)
|
)
|
||||||
|
|
||||||
file = store.download(upload_s3)
|
file = store.download(upload_s3, print_deprecation: true)
|
||||||
|
|
||||||
expect(file.class).to eq(File)
|
expect(file.class).to eq(File)
|
||||||
end
|
end
|
||||||
@ -223,9 +223,41 @@ RSpec.describe FileStore::BaseStore do
|
|||||||
signed_url = Discourse.store.signed_url_for_path(upload_s3.url)
|
signed_url = Discourse.store.signed_url_for_path(upload_s3.url)
|
||||||
stub_request(:get, signed_url).to_return(status: 200, body: "Hello world")
|
stub_request(:get, signed_url).to_return(status: 200, body: "Hello world")
|
||||||
|
|
||||||
file = store.download(upload_s3)
|
file = store.download(upload_s3, print_deprecation: false)
|
||||||
|
|
||||||
expect(file.class).to eq(File)
|
expect(file.class).to eq(File)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#download!" do
|
||||||
|
before do
|
||||||
|
setup_s3
|
||||||
|
stub_request(:get, upload_s3.url).to_return(status: 200, body: "Hello world")
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:upload_s3) { Fabricate(:upload_s3) }
|
||||||
|
let(:store) { FileStore::BaseStore.new }
|
||||||
|
|
||||||
|
it "does not raise an error when download fails" do
|
||||||
|
FileHelper.stubs(:download).raises(OpenURI::HTTPError.new("400 error", anything))
|
||||||
|
|
||||||
|
expect { store.download!(upload_s3) }.to raise_error(FileStore::DownloadError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#download_safe" do
|
||||||
|
before do
|
||||||
|
setup_s3
|
||||||
|
stub_request(:get, upload_s3.url).to_return(status: 200, body: "Hello world")
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:upload_s3) { Fabricate(:upload_s3) }
|
||||||
|
let(:store) { FileStore::BaseStore.new }
|
||||||
|
|
||||||
|
it "does not raise an error when download fails" do
|
||||||
|
FileHelper.stubs(:download).raises(OpenURI::HTTPError.new("400 error", anything))
|
||||||
|
|
||||||
|
expect(store.download_safe(upload_s3)).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user