107
107
from hashlib import sha1
108
from StringIO import StringIO
109
108
from time import time
110
109
from urllib import quote
111
from swift.common.middleware.tempurl import get_tempurl_keys_from_metadata
112
112
from swift.common.utils import streq_const_time
113
113
from swift.common.wsgi import make_pre_authed_env
114
from swift.proxy.controllers.base import get_account_info
116
117
#: The size of data to read from the form at any given time.
359
360
attributes['content-type'] = \
360
361
hdrs['Content-Type'] or 'application/octet-stream'
361
362
status, message = self._perform_subrequest(env, attributes, fp,
363
364
if status[:1] != '2':
397
398
headers = [('Location', redirect), ('Content-Length', str(len(body)))]
398
399
return '303 See Other', headers, body
400
def _perform_subrequest(self, orig_env, attributes, fp, key):
401
def _perform_subrequest(self, orig_env, attributes, fp, keys):
402
403
Performs the subrequest and returns the response.
405
406
to form a new env for the subrequest.
406
407
:param attributes: dict of the attributes of the form so far.
407
408
:param fp: The file-like object containing the request body.
408
:param key: The account key to validate the signature with.
409
:param keys: The account keys to validate the signature with.
409
410
:returns: (status_line, message)
412
413
return '401 Unauthorized', 'invalid signature'
414
415
max_file_size = int(attributes.get('max_file_size') or 0)
440
441
attributes.get('max_file_size') or '0',
441
442
attributes.get('max_file_count') or '0',
442
443
attributes.get('expires') or '0')
443
sig = hmac.new(key, hmac_body, sha1).hexdigest()
444
if not streq_const_time(sig, (attributes.get('signature') or
445
has_valid_sig = False
447
sig = hmac.new(key, hmac_body, sha1).hexdigest()
448
if streq_const_time(sig, (attributes.get('signature') or
451
if not has_valid_sig:
446
452
return '401 Unauthorized', 'invalid signature'
447
454
substatus = [None]
449
456
def _start_response(status, headers, exc_info=None):
457
464
return substatus[0], ''
459
def _get_key(self, env):
466
def _get_keys(self, env):
461
Returns the X-Account-Meta-Temp-URL-Key header value for the
462
account, or None if none is set.
468
Fetch the tempurl keys for the account. Also validate that the request
469
path indicates a valid container; if not, no keys will be returned.
464
471
:param env: The WSGI environment for the request.
465
:returns: X-Account-Meta-Temp-URL-Key str value, or None.
472
:returns: list of tempurl keys
467
474
parts = env['PATH_INFO'].split('/', 4)
468
475
if len(parts) < 4 or parts[0] or parts[1] != 'v1' or not parts[2] or \
473
memcache = env.get('swift.cache')
475
key = memcache.get('temp-url-key/%s' % account)
477
newenv = make_pre_authed_env(env, 'HEAD', '/v1/' + account,
478
agent=None, swift_source='FP')
479
if 'QUERY_STRING' in newenv:
480
del newenv['QUERY_STRING']
481
newenv['CONTENT_LENGTH'] = '0'
482
newenv['wsgi.input'] = StringIO('')
485
def _start_response(status, response_headers, exc_info=None):
486
for h, v in response_headers:
487
if h.lower() == 'x-account-meta-temp-url-key':
490
i = iter(self.app(newenv, _start_response))
493
except StopIteration:
497
memcache.set('temp-url-key/%s' % account, key, time=60)
479
account_info = get_account_info(env, self.app, swift_source='FP')
480
return get_tempurl_keys_from_metadata(account_info['meta'])
501
483
def filter_factory(global_conf, **local_conf):
502
""" Returns the WSGI filter for use with paste.deploy. """
484
"""Returns the WSGI filter for use with paste.deploy."""
503
485
conf = global_conf.copy()
504
486
conf.update(local_conf)
505
487
return lambda app: FormPost(app, conf)