mirror of
https://github.com/discourse/discourse.git
synced 2025-02-06 19:38:24 +00:00
157f10db4c
Discourse shouldn't dynamically calculate the path of uploads and optimized images after a file has been stored on disk or S3. Otherwise it might calculate the wrong path if the SHA1 or extension stored in the database doesn't match the actual file path.
192 lines
7.8 KiB
Ruby
192 lines
7.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
RSpec.describe FileStore::BaseStore do
|
|
fab!(:upload) { Fabricate(:upload, id: 9999, sha1: Digest::SHA1.hexdigest('9999')) }
|
|
|
|
describe '#get_path_for_upload' do
|
|
def expect_correct_path(expected_path)
|
|
expect(described_class.new.get_path_for_upload(upload)).to eq(expected_path)
|
|
end
|
|
|
|
context "empty URL" do
|
|
before do
|
|
upload.update!(url: "")
|
|
end
|
|
|
|
it 'should return the right path' do
|
|
expect_correct_path('original/2X/4/4170ac2a2782a1516fe9e13d7322ae482c1bd594.png')
|
|
end
|
|
|
|
describe 'when Upload#extension has not been set' do
|
|
it 'should return the right path' do
|
|
upload.update!(extension: nil)
|
|
expect_correct_path('original/2X/4/4170ac2a2782a1516fe9e13d7322ae482c1bd594.png')
|
|
end
|
|
end
|
|
|
|
describe 'when id is negative' do
|
|
it 'should return the right depth' do
|
|
upload.update!(id: -999)
|
|
expect_correct_path('original/1X/4170ac2a2782a1516fe9e13d7322ae482c1bd594.png')
|
|
end
|
|
end
|
|
end
|
|
|
|
context "existing URL" do
|
|
context "regular site" do
|
|
it "returns the correct path for files stored on local storage" do
|
|
upload.update!(url: "/uploads/default/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
upload.update!(url: "/uploads/default/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
end
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
upload.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
upload.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
end
|
|
end
|
|
|
|
context "multisite" do
|
|
it "returns the correct path for files stored on local storage" do
|
|
upload.update!(url: "/uploads/foo/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
upload.update!(url: "/uploads/foo/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
end
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
upload.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/foo/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
upload.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/foo/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
end
|
|
|
|
it "returns the correct path when the site name is 'original'" do
|
|
upload.update!(url: "/uploads/original/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
upload.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/original/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#get_path_for_optimized_image' do
|
|
let!(:upload) { Fabricate.build(:upload, id: 100) }
|
|
let!(:optimized_path) { "optimized/1X/#{upload.sha1}_1_100x200.png" }
|
|
|
|
context "empty URL" do
|
|
it 'should return the right path' do
|
|
optimized = Fabricate.build(:optimized_image, upload: upload, version: 1)
|
|
expect(FileStore::BaseStore.new.get_path_for_optimized_image(optimized)).to eq(optimized_path)
|
|
end
|
|
|
|
it 'should return the right path for `nil` version' do
|
|
optimized = Fabricate.build(:optimized_image, upload: upload, version: nil)
|
|
expect(FileStore::BaseStore.new.get_path_for_optimized_image(optimized)).to eq(optimized_path)
|
|
end
|
|
end
|
|
|
|
context "existing URL" do
|
|
let!(:optimized) { Fabricate.build(:optimized_image, upload: upload, version: 1) }
|
|
let!(:optimized_path) { "optimized/1X/#{upload.sha1}_1_100x200.jpg" }
|
|
|
|
def expect_correct_optimized_path
|
|
expect(described_class.new.get_path_for_optimized_image(optimized)).to eq(optimized_path)
|
|
end
|
|
|
|
context "regular site" do
|
|
it "returns the correct path for files stored on local storage" do
|
|
optimized.update!(url: "/uploads/default/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
expect_correct_optimized_path
|
|
end
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
optimized.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
expect_correct_optimized_path
|
|
end
|
|
end
|
|
|
|
context "multisite" do
|
|
it "returns the correct path for files stored on local storage" do
|
|
optimized.update!(url: "/uploads/foo/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
expect_correct_optimized_path
|
|
end
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
optimized.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/foo/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
expect_correct_optimized_path
|
|
end
|
|
|
|
it "returns the correct path when the site name is 'optimized'" do
|
|
optimized.update!(url: "/uploads/optimized/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
expect_correct_optimized_path
|
|
|
|
optimized.update!(url: "//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/optimized/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
expect_correct_optimized_path
|
|
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 "should return consistent encodings for fresh and cached downloads" do
|
|
# 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
|
|
|
|
first_encoding = store.download(upload_s3).read.encoding
|
|
|
|
second_encoding = store.download(upload_s3).read.encoding
|
|
|
|
expect(first_encoding).to eq(Encoding::UTF_8)
|
|
expect(second_encoding).to eq(Encoding::UTF_8)
|
|
end
|
|
|
|
it "should return the file" do
|
|
file = store.download(upload_s3)
|
|
|
|
expect(file.class).to eq(File)
|
|
end
|
|
|
|
it "should return the file when s3 cdn enabled" do
|
|
SiteSetting.s3_cdn_url = "https://cdn.s3.#{SiteSetting.s3_region}.amazonaws.com"
|
|
stub_request(:get, Discourse.store.cdn_url(upload_s3.url)).to_return(status: 200, body: "Hello world")
|
|
|
|
file = store.download(upload_s3)
|
|
|
|
expect(file.class).to eq(File)
|
|
end
|
|
|
|
it "should return the file when secure media are enabled" do
|
|
SiteSetting.login_required = true
|
|
SiteSetting.secure_media = true
|
|
|
|
stub_request(:head, "https://s3-upload-bucket.s3.#{SiteSetting.s3_region}.amazonaws.com/")
|
|
signed_url = Discourse.store.signed_url_for_path(upload_s3.url)
|
|
stub_request(:get, signed_url).to_return(status: 200, body: "Hello world")
|
|
|
|
file = store.download(upload_s3)
|
|
|
|
expect(file.class).to eq(File)
|
|
end
|
|
end
|
|
end
|