~ubuntu-branches/ubuntu/trusty/swift/trusty-updates

« back to all changes in this revision

Viewing changes to swift/common/middleware/formpost.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, James Page, Chuck Short
  • Date: 2013-08-13 10:37:13 UTC
  • mfrom: (1.2.21)
  • Revision ID: package-import@ubuntu.com-20130813103713-1ctbx4zifyljs2aq
Tags: 1.9.1-0ubuntu1
[ James Page ]
* d/control: Update VCS fields for new branch locations.

[ Chuck Short ]
* New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
105
105
import re
106
106
import rfc822
107
107
from hashlib import sha1
108
 
from StringIO import StringIO
109
108
from time import time
110
109
from urllib import quote
111
110
 
 
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
114
115
 
115
116
 
116
117
#: The size of data to read from the form at any given time.
337
338
        :param boundary: The MIME type boundary to look for.
338
339
        :returns: status_line, headers_list, body
339
340
        """
340
 
        key = self._get_key(env)
 
341
        keys = self._get_keys(env)
341
342
        status = message = ''
342
343
        attributes = {}
343
344
        file_count = 0
359
360
                    attributes['content-type'] = \
360
361
                        hdrs['Content-Type'] or 'application/octet-stream'
361
362
                status, message = self._perform_subrequest(env, attributes, fp,
362
 
                                                           key)
 
363
                                                           keys)
363
364
                if status[:1] != '2':
364
365
                    break
365
366
            else:
397
398
        headers = [('Location', redirect), ('Content-Length', str(len(body)))]
398
399
        return '303 See Other', headers, body
399
400
 
400
 
    def _perform_subrequest(self, orig_env, attributes, fp, key):
 
401
    def _perform_subrequest(self, orig_env, attributes, fp, keys):
401
402
        """
402
403
        Performs the subrequest and returns the response.
403
404
 
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)
410
411
        """
411
 
        if not key:
 
412
        if not keys:
412
413
            return '401 Unauthorized', 'invalid signature'
413
414
        try:
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
 
444
 
 
445
        has_valid_sig = False
 
446
        for key in keys:
 
447
            sig = hmac.new(key, hmac_body, sha1).hexdigest()
 
448
            if streq_const_time(sig, (attributes.get('signature') or
445
449
                                      'invalid')):
 
450
                has_valid_sig = True
 
451
        if not has_valid_sig:
446
452
            return '401 Unauthorized', 'invalid signature'
 
453
 
447
454
        substatus = [None]
448
455
 
449
456
        def _start_response(status, headers, exc_info=None):
456
463
            pass
457
464
        return substatus[0], ''
458
465
 
459
 
    def _get_key(self, env):
 
466
    def _get_keys(self, env):
460
467
        """
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.
463
470
 
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
466
473
        """
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 \
469
476
                not parts[3]:
470
 
            return None
471
 
        account = parts[2]
472
 
        key = None
473
 
        memcache = env.get('swift.cache')
474
 
        if memcache:
475
 
            key = memcache.get('temp-url-key/%s' % account)
476
 
        if not key:
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('')
483
 
            key = [None]
484
 
 
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':
488
 
                        key[0] = v
489
 
 
490
 
            i = iter(self.app(newenv, _start_response))
491
 
            try:
492
 
                i.next()
493
 
            except StopIteration:
494
 
                pass
495
 
            key = key[0]
496
 
            if key and memcache:
497
 
                memcache.set('temp-url-key/%s' % account, key, time=60)
498
 
        return key
 
477
            return []
 
478
 
 
479
        account_info = get_account_info(env, self.app, swift_source='FP')
 
480
        return get_tempurl_keys_from_metadata(account_info['meta'])
499
481
 
500
482
 
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)