Checkboxes for prior research
Describe the bug
As per the Content-Disposition specification, a UTF-8 encoded filename can be set for links with the attachment disposition by including filename*=UTF-8''{encodedFilename} in the value for response-content-disposition in the query string.
However, when this addition is made to a URL and then passed to cloudfront-signer's getSignedUrl(), the resulting signed URL fails on load with an Access Denied error.
Regression Issue
SDK version number
@aws-sdk/cloudfront-signer@3.1046.0
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v24.4.1
Reproduction Steps
Generate a signed URL that includes filename*:
const signer = require('@aws-sdk/cloudfront-signer');
const filename = '文件';
const normalizedFilename = normalizeHelperFunction(filename);
const encodedFilename = encodeURIComponent(filename);
const signedUrl = signer.getSignedUrl({
url: `https://example.com/path?response-content-disposition=attachment;filename=${normalizedFilename};filename*=UTF-8''${encodedFilename}`,
});
return signedUrl;
Take that signed URL and attempt to load it in a web browser.
Observed Behavior
The signed URL redirects to an error page with an Access Denied error.
Expected Behavior
The signed URL loads the requested file for download.
Possible Solution
Add special handling of the UTF-8'' part of the filename* option so that apostrophes are allowed to be included unencoded there. (See the Additional Information/Context below.)
Additional Information/Context
There was a similar issue in the past: #7470.
However, where that past issue was caused by encoding issues with the asterisk * in filename*, this current issue appears to be related to the apostrophes in UTF-8''. If the apostrophes are percent encoded, turning that part into UTF-8%27%27, then the resulting signed URL loads successfully.
However, this is not an ideal solution because there is inconsistent behaviour on how UTF-8%27%27 is handled between browsers on file download:
- Chrome: Properly decodes
filename*
- Firefox: Properly decodes the filename, but misinterprets the
UTF-8'' part as a literal string and includes it in the filename as a prefix
- Edge: Properly decodes
filename*
- Safari: Does not parse
filename*, likely due to a failing check on the value, and falls back to filename
Checkboxes for prior research
Describe the bug
As per the Content-Disposition specification, a UTF-8 encoded filename can be set for links with the
attachmentdisposition by includingfilename*=UTF-8''{encodedFilename}in the value forresponse-content-dispositionin the query string.However, when this addition is made to a URL and then passed to cloudfront-signer's
getSignedUrl(), the resulting signed URL fails on load with an Access Denied error.Regression Issue
SDK version number
@aws-sdk/cloudfront-signer@3.1046.0
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v24.4.1
Reproduction Steps
Generate a signed URL that includes
filename*:Take that signed URL and attempt to load it in a web browser.
Observed Behavior
The signed URL redirects to an error page with an Access Denied error.
Expected Behavior
The signed URL loads the requested file for download.
Possible Solution
Add special handling of the
UTF-8''part of thefilename*option so that apostrophes are allowed to be included unencoded there. (See the Additional Information/Context below.)Additional Information/Context
There was a similar issue in the past: #7470.
However, where that past issue was caused by encoding issues with the asterisk
*infilename*, this current issue appears to be related to the apostrophes inUTF-8''. If the apostrophes are percent encoded, turning that part intoUTF-8%27%27, then the resulting signed URL loads successfully.However, this is not an ideal solution because there is inconsistent behaviour on how
UTF-8%27%27is handled between browsers on file download:filename*UTF-8''part as a literal string and includes it in the filename as a prefixfilename*filename*, likely due to a failing check on the value, and falls back to filename