Skip to content

Commit 841be75

Browse files
committed
Fix uploading files with invalid byte sequences in their file names
1 parent 17a0f5f commit 841be75

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

app/controllers/decidim/apifiles/blobs_controller.rb

+17-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def create
3131

3232
blob = ActiveStorage::Blob.create_and_upload!(
3333
io: uploaded_file,
34-
filename: uploaded_file.original_filename,
34+
filename: sanitized_filename,
3535
content_type: uploaded_file.content_type
3636
)
3737

@@ -46,6 +46,22 @@ def uploaded_file
4646
@uploaded_file ||= params.require(:file)
4747
end
4848

49+
# In case the file name contains invalid byte sequences, they could not be
50+
# stored in the database due to the following exception:
51+
# ActiveRecord::StatementInvalid:
52+
# PG::CharacterNotInRepertoire: ERROR: invalid byte sequence for encoding "UTF8": 0xea 0x78 0xe4
53+
# CONTEXT: unnamed portal parameter $2
54+
#
55+
# This replaces all invalid byte sequences before persisting the file to
56+
# the database.
57+
def sanitized_filename
58+
@sanitized_filename || begin
59+
name = uploaded_file.original_filename
60+
name = name.scrub unless name.valid_encoding?
61+
name
62+
end
63+
end
64+
4965
def uploaded_file_extension
5066
@uploaded_file_extension ||= File.extname(uploaded_file.original_filename).strip.downcase[1..-1]
5167
end

spec/controllers/decidim/apifiles/blobs_controller_spec.rb

+18
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,24 @@
8686
expect(response.parsed_body).to eq({ "error" => "unallowed_content_type" })
8787
end
8888
end
89+
90+
context "with file name in Windows-1252 encoding" do
91+
let(:file) do
92+
Decidim::Dev.test_file("Exampledocument.pdf", "application/pdf").tap do |f|
93+
# In case we stored a file with such name in the "fixtures" folder,
94+
# this would not work because `rack-test` fails to generate the
95+
# `Rack::Test::UploadedFile` due to the weird name. We need to force
96+
# the name on the instance in order to replicate the bug with
97+
# storing file names with this encoding. There is no other way to
98+
# change the "original_filename" of the instance.
99+
f.instance_variable_set(:@original_filename, "êxämplö®'.pdf".encode("WINDOWS-1252"))
100+
end
101+
end
102+
103+
it "allows uploading a file" do
104+
expect(response).to have_http_status(:ok)
105+
end
106+
end
89107
end
90108
end
91109
end

0 commit comments

Comments
 (0)