Merge "Make Content-Disposition support inline; filename=... format."

This commit is contained in:
Jenkins 2016-10-15 21:07:10 +00:00 committed by Gerrit Code Review
commit a79d8508df
2 changed files with 31 additions and 7 deletions

View File

@ -112,6 +112,16 @@ If you do not want the object to be downloaded, you can cause
temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709& temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709&
temp_url_expires=1323479485&inline temp_url_expires=1323479485&inline
In some cases, the client might not able to present the content of the object,
but you still want the content able to save to local with the specific
filename. So you can cause ``Content-Disposition: inline; filename=...`` to be
set on the response by adding the ``inline&filename=...`` parameter to the
query string, like so::
https://swift-cluster.example.com/v1/AUTH_account/container/object?
temp_url_sig=da39a3ee5e6b4b0d3255bfef95601890afd80709&
temp_url_expires=1323479485&inline&filename=My+Test+File.pdf
--------------------- ---------------------
Cluster Configuration Cluster Configuration
--------------------- ---------------------
@ -220,9 +230,15 @@ def get_tempurl_keys_from_metadata(meta):
if key.lower() in ('temp-url-key', 'temp-url-key-2')] if key.lower() in ('temp-url-key', 'temp-url-key-2')]
def disposition_format(filename): def disposition_format(disposition_type, filename):
return '''attachment; filename="%s"; filename*=UTF-8''%s''' % ( # Content-Disposition in HTTP is defined in
quote(filename, safe=' /'), quote(filename)) # https://tools.ietf.org/html/rfc6266 and references
# https://tools.ietf.org/html/rfc5987#section-3.2
# to explain the filename*= encoding format. The summary
# is that it's the charset, then an optional (and empty) language
# then the filename. Looks funny, but it's right.
return '''%s; filename="%s"; filename*=UTF-8''%s''' % (
disposition_type, quote(filename, safe=' /'), quote(filename))
def authorize_same_account(account_to_match): def authorize_same_account(account_to_match):
@ -413,14 +429,20 @@ class TempURL(object):
else: else:
existing_disposition = v existing_disposition = v
if inline_disposition: if inline_disposition:
disposition_value = 'inline' if filename:
disposition_value = disposition_format('inline',
filename)
else:
disposition_value = 'inline'
elif filename: elif filename:
disposition_value = disposition_format(filename) disposition_value = disposition_format('attachment',
filename)
elif existing_disposition: elif existing_disposition:
disposition_value = existing_disposition disposition_value = existing_disposition
else: else:
name = basename(env['PATH_INFO'].rstrip('/')) name = basename(env['PATH_INFO'].rstrip('/'))
disposition_value = disposition_format(name) disposition_value = disposition_format('attachment',
name)
# this is probably just paranoia, I couldn't actually get a # this is probably just paranoia, I couldn't actually get a
# newline into existing_disposition # newline into existing_disposition
value = disposition_value.replace('\n', '%0A') value = disposition_value.replace('\n', '%0A')

View File

@ -267,7 +267,9 @@ class TestTempURL(unittest.TestCase):
self.tempurl.app = FakeApp(iter([('200 Ok', (), '123')])) self.tempurl.app = FakeApp(iter([('200 Ok', (), '123')]))
resp = req.get_response(self.tempurl) resp = req.get_response(self.tempurl)
self.assertEqual(resp.status_int, 200) self.assertEqual(resp.status_int, 200)
self.assertEqual(resp.headers['content-disposition'], 'inline') self.assertEqual(resp.headers['content-disposition'],
'inline; filename="bob %22killer%22.txt"; ' +
"filename*=UTF-8''bob%20%22killer%22.txt")
self.assertIn('expires', resp.headers) self.assertIn('expires', resp.headers)
self.assertEqual('Thu, 01 Jan 1970 00:00:01 GMT', self.assertEqual('Thu, 01 Jan 1970 00:00:01 GMT',
resp.headers['expires']) resp.headers['expires'])