Add X-Delete-At/After support to FormPost
This change adds the ability to specify a X-Delete-At or X-Delete-After attribute when using the FormPost middleware. Here is an example of what you need to add to the form: <input type="hidden" name="x_delete_at" value="<unix-timestamp>"/> <input type="hidden" name="x_delete_after" value="<seconds>"/> To be inline with the other form imput names, x-delete-at/after has changed to x_delete_at/after. DocImpact Change-Id: Ib1cc0bcf1dd7d2b689f2f26d100f9bab36880c81 Closes-Bug: #1065522
This commit is contained in:
parent
0a5b003345
commit
90272a0564
@ -31,6 +31,13 @@ The format of the form is::
|
||||
<input type="submit" />
|
||||
</form>
|
||||
|
||||
Optionally, if you want the uploaded files to be temporary you can set
|
||||
x-delete-at or x-delete-after attributes by adding one of these as a
|
||||
form input::
|
||||
|
||||
<input type="hidden" name="x_delete_at" value="<unix-timestamp>" />
|
||||
<input type="hidden" name="x_delete_after" value="<seconds>" />
|
||||
|
||||
The <swift-url> is the URL to the Swift desination, such as::
|
||||
|
||||
https://swift-cluster.example.com/v1/AUTH_account/container/object_prefix
|
||||
@ -87,6 +94,8 @@ The key is the value of the X-Account-Meta-Temp-URL-Key header on the
|
||||
account.
|
||||
|
||||
Be certain to use the full path, from the /v1/ onward.
|
||||
Note the x_delete_at and x_delete_after attributes are not used in signature
|
||||
generation as these are both considered optional attributes.
|
||||
|
||||
The command line tool ``swift-form-signature`` may be used (mostly
|
||||
just when testing) to compute expires and signature.
|
||||
@ -441,6 +450,19 @@ class FormPost(object):
|
||||
subenv['PATH_INFO'].count('/') < 4:
|
||||
subenv['PATH_INFO'] += '/'
|
||||
subenv['PATH_INFO'] += attributes['filename'] or 'filename'
|
||||
if 'x_delete_at' in attributes:
|
||||
try:
|
||||
subenv['HTTP_X_DELETE_AT'] = int(attributes['x_delete_at'])
|
||||
except ValueError:
|
||||
raise FormInvalid('x_delete_at not an integer: '
|
||||
'Unix timestamp required.')
|
||||
if 'x_delete_after' in attributes:
|
||||
try:
|
||||
subenv['HTTP_X_DELETE_AFTER'] = int(
|
||||
attributes['x_delete_after'])
|
||||
except ValueError:
|
||||
raise FormInvalid('x_delete_after not an integer: '
|
||||
'Number of seconds required.')
|
||||
if 'content-type' in attributes:
|
||||
subenv['CONTENT_TYPE'] = \
|
||||
attributes['content-type'] or 'application/octet-stream'
|
||||
|
@ -1692,6 +1692,156 @@ class TestFormPost(unittest.TestCase):
|
||||
self.assertEquals(exc_info, None)
|
||||
self.assertTrue('FormPost: expired not an integer' in body)
|
||||
|
||||
def test_x_delete_at(self):
|
||||
delete_at = int(time() + 100)
|
||||
x_delete_body_part = [
|
||||
'------WebKitFormBoundaryNcxTqxSlX7t4TDkR',
|
||||
'Content-Disposition: form-data; name="x_delete_at"',
|
||||
'',
|
||||
str(delete_at),
|
||||
]
|
||||
key = 'abc'
|
||||
sig, env, body = self._make_sig_env_body(
|
||||
'/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key)
|
||||
env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body))
|
||||
env['swift.account/AUTH_test'] = self._fake_cache_env(
|
||||
'AUTH_test', [key])
|
||||
self.app = FakeApp(iter([('201 Created', {}, ''),
|
||||
('201 Created', {}, '')]))
|
||||
self.auth = tempauth.filter_factory({})(self.app)
|
||||
self.formpost = formpost.filter_factory({})(self.auth)
|
||||
status = [None]
|
||||
headers = [None]
|
||||
exc_info = [None]
|
||||
|
||||
def start_response(s, h, e=None):
|
||||
status[0] = s
|
||||
headers[0] = h
|
||||
exc_info[0] = e
|
||||
|
||||
body = ''.join(self.formpost(env, start_response))
|
||||
status = status[0]
|
||||
headers = headers[0]
|
||||
exc_info = exc_info[0]
|
||||
self.assertEquals(status, '201 Created')
|
||||
self.assertTrue('201 Created' in body)
|
||||
self.assertEquals(len(self.app.requests), 2)
|
||||
self.assertTrue("X-Delete-At" in self.app.requests[0].headers)
|
||||
self.assertTrue("X-Delete-At" in self.app.requests[1].headers)
|
||||
self.assertEquals(delete_at,
|
||||
self.app.requests[0].headers["X-Delete-At"])
|
||||
self.assertEquals(delete_at,
|
||||
self.app.requests[1].headers["X-Delete-At"])
|
||||
|
||||
def test_x_delete_at_not_int(self):
|
||||
delete_at = "2014-07-16"
|
||||
x_delete_body_part = [
|
||||
'------WebKitFormBoundaryNcxTqxSlX7t4TDkR',
|
||||
'Content-Disposition: form-data; name="x_delete_at"',
|
||||
'',
|
||||
str(delete_at),
|
||||
]
|
||||
key = 'abc'
|
||||
sig, env, body = self._make_sig_env_body(
|
||||
'/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key)
|
||||
env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body))
|
||||
env['swift.account/AUTH_test'] = self._fake_cache_env(
|
||||
'AUTH_test', [key])
|
||||
self.app = FakeApp(iter([('201 Created', {}, ''),
|
||||
('201 Created', {}, '')]))
|
||||
self.auth = tempauth.filter_factory({})(self.app)
|
||||
self.formpost = formpost.filter_factory({})(self.auth)
|
||||
status = [None]
|
||||
headers = [None]
|
||||
exc_info = [None]
|
||||
|
||||
def start_response(s, h, e=None):
|
||||
status[0] = s
|
||||
headers[0] = h
|
||||
exc_info[0] = e
|
||||
|
||||
body = ''.join(self.formpost(env, start_response))
|
||||
status = status[0]
|
||||
headers = headers[0]
|
||||
exc_info = exc_info[0]
|
||||
self.assertEquals(status, '400 Bad Request')
|
||||
self.assertTrue('FormPost: x_delete_at not an integer' in body)
|
||||
|
||||
def test_x_delete_after(self):
|
||||
delete_after = 100
|
||||
x_delete_body_part = [
|
||||
'------WebKitFormBoundaryNcxTqxSlX7t4TDkR',
|
||||
'Content-Disposition: form-data; name="x_delete_after"',
|
||||
'',
|
||||
str(delete_after),
|
||||
]
|
||||
key = 'abc'
|
||||
sig, env, body = self._make_sig_env_body(
|
||||
'/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key)
|
||||
env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body))
|
||||
env['swift.account/AUTH_test'] = self._fake_cache_env(
|
||||
'AUTH_test', [key])
|
||||
self.app = FakeApp(iter([('201 Created', {}, ''),
|
||||
('201 Created', {}, '')]))
|
||||
self.auth = tempauth.filter_factory({})(self.app)
|
||||
self.formpost = formpost.filter_factory({})(self.auth)
|
||||
status = [None]
|
||||
headers = [None]
|
||||
exc_info = [None]
|
||||
|
||||
def start_response(s, h, e=None):
|
||||
status[0] = s
|
||||
headers[0] = h
|
||||
exc_info[0] = e
|
||||
|
||||
body = ''.join(self.formpost(env, start_response))
|
||||
status = status[0]
|
||||
headers = headers[0]
|
||||
exc_info = exc_info[0]
|
||||
self.assertEquals(status, '201 Created')
|
||||
self.assertTrue('201 Created' in body)
|
||||
self.assertEquals(len(self.app.requests), 2)
|
||||
self.assertTrue("X-Delete-After" in self.app.requests[0].headers)
|
||||
self.assertTrue("X-Delete-After" in self.app.requests[1].headers)
|
||||
self.assertEqual(delete_after,
|
||||
self.app.requests[0].headers["X-Delete-After"])
|
||||
self.assertEqual(delete_after,
|
||||
self.app.requests[1].headers["X-Delete-After"])
|
||||
|
||||
def test_x_delete_after_not_int(self):
|
||||
delete_after = "2 days"
|
||||
x_delete_body_part = [
|
||||
'------WebKitFormBoundaryNcxTqxSlX7t4TDkR',
|
||||
'Content-Disposition: form-data; name="x_delete_after"',
|
||||
'',
|
||||
str(delete_after),
|
||||
]
|
||||
key = 'abc'
|
||||
sig, env, body = self._make_sig_env_body(
|
||||
'/v1/AUTH_test/container', '', 1024, 10, int(time() + 86400), key)
|
||||
env['wsgi.input'] = StringIO('\r\n'.join(x_delete_body_part + body))
|
||||
env['swift.account/AUTH_test'] = self._fake_cache_env(
|
||||
'AUTH_test', [key])
|
||||
self.app = FakeApp(iter([('201 Created', {}, ''),
|
||||
('201 Created', {}, '')]))
|
||||
self.auth = tempauth.filter_factory({})(self.app)
|
||||
self.formpost = formpost.filter_factory({})(self.auth)
|
||||
status = [None]
|
||||
headers = [None]
|
||||
exc_info = [None]
|
||||
|
||||
def start_response(s, h, e=None):
|
||||
status[0] = s
|
||||
headers[0] = h
|
||||
exc_info[0] = e
|
||||
|
||||
body = ''.join(self.formpost(env, start_response))
|
||||
status = status[0]
|
||||
headers = headers[0]
|
||||
exc_info = exc_info[0]
|
||||
self.assertEquals(status, '400 Bad Request')
|
||||
self.assertTrue('FormPost: x_delete_after not an integer' in body)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user