mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 22:43:33 +08:00
FIX: Make sure S3 object headers are preserved on copy (#14302)
When copying an existing upload stub temporary object on S3 to its final destination we were not copying across its additional headers such as content-disposition and cache-control, which led to issues like attachments not downloading with their original filename when clicking the download links in posts. This is because the metadata_directive = REPLACE option was not being passed to object.copy_from(), so only the source object's headers were being used. Added an option for apply_metadata_to_destination to apply this option conditionally, because we may not always want to replace this metadata, but we definitely do when copying a temporary upload.
This commit is contained in:
@ -86,6 +86,10 @@ class S3Helper
|
||||
end
|
||||
|
||||
def copy(source, destination, options: {})
|
||||
if options[:apply_metadata_to_destination]
|
||||
options = options.except(:apply_metadata_to_destination).merge(metadata_directive: "REPLACE")
|
||||
end
|
||||
|
||||
destination = get_path_for_s3_upload(destination)
|
||||
if !Rails.configuration.multisite
|
||||
options[:copy_source] = File.join(@s3_bucket_name, source)
|
||||
@ -102,7 +106,21 @@ class S3Helper
|
||||
end
|
||||
end
|
||||
|
||||
response = s3_bucket.object(destination).copy_from(options)
|
||||
destination_object = s3_bucket.object(destination)
|
||||
|
||||
# TODO: copy_source is a legacy option here and may become unsupported
|
||||
# in later versions, we should change to use Aws::S3::Client#copy_object
|
||||
# at some point.
|
||||
#
|
||||
# See https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/lib/aws-sdk-s3/customizations/object.rb#L67-L74
|
||||
#
|
||||
# ----
|
||||
#
|
||||
# Also note, any options for metadata (e.g. content_disposition, content_type)
|
||||
# will not be applied unless the metadata_directive = "REPLACE" option is passed
|
||||
# in. If this is not passed in, the source object's metadata will be used.
|
||||
response = destination_object.copy_from(options)
|
||||
|
||||
[destination, response.copy_object_result.etag.gsub('"', '')]
|
||||
end
|
||||
|
||||
|
Reference in New Issue
Block a user