Exemplo n.º 1
0
    def test_pre_auth_wsgi_input(self):
        oldenv = {}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue("wsgi.input" in newenv)
        self.assertEquals(newenv["wsgi.input"].read(), "")

        oldenv = {"wsgi.input": StringIO("original wsgi.input")}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue("wsgi.input" in newenv)
        self.assertEquals(newenv["wsgi.input"].read(), "")
Exemplo n.º 2
0
    def test_pre_auth_wsgi_input(self):
        oldenv = {}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue('wsgi.input' in newenv)
        self.assertEquals(newenv['wsgi.input'].read(), '')

        oldenv = {'wsgi.input': StringIO('original wsgi.input')}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue('wsgi.input' in newenv)
        self.assertEquals(newenv['wsgi.input'].read(), '')
Exemplo n.º 3
0
    def test_pre_auth_wsgi_input(self):
        oldenv = {}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue('wsgi.input' in newenv)
        self.assertEquals(newenv['wsgi.input'].read(), '')

        oldenv = {'wsgi.input': StringIO('original wsgi.input')}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue('wsgi.input' in newenv)
        self.assertEquals(newenv['wsgi.input'].read(), '')
def iter_objects_by_prefix(account, container, prefix, swift_client=None,
                           app=None):
    marker = ''
    while True:
        param = 'format=json&marker=%s' % marker
        if marker == '':
            param = '%s&prefix=%s' % (param, prefix)

        if swift_client:
            path = swift_client.make_path(account, container)
            resp = swift_client.make_request('GET', '%s?%s' % (path, param),
                                             {}, (2, 4))
        elif app:
            path = '/v1/%s/%s' % (account, container)
            env = make_pre_authed_env({}, method='GET', path=path,
                                      query_string=param)
            req = make_pre_authed_request(env)
            resp = req.get_response(app)

        if not resp.status_int == 200:
            break

        data = json.loads(resp.body)
        if not data:
            break
        for item in data:
            yield item
        marker = data[-1]['name'].encode('utf8')
Exemplo n.º 5
0
    def handle_object(self, env, start_response):
        """
        Handles a possible static web request for an object. This object could
        resolve into an index or listing request.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        """
        tmp_env = dict(env)
        tmp_env['HTTP_USER_AGENT'] = \
            '%s StaticWeb' % env.get('HTTP_USER_AGENT')
        resp = self._app_call(tmp_env)
        status_int = self._get_status_int()
        if status_int // 100 in (2, 3):
            start_response(self._response_status, self._response_headers,
                           self._response_exc_info)
            return resp
        if status_int != 404:
            return self._error_response(resp, env, start_response)
        self._get_container_info(env)
        if not self._listings and not self._index:
            return self.app(env, start_response)
        status_int = 404
        if self._index:
            tmp_env = dict(env)
            tmp_env['HTTP_USER_AGENT'] = \
                '%s StaticWeb' % env.get('HTTP_USER_AGENT')
            if tmp_env['PATH_INFO'][-1] != '/':
                tmp_env['PATH_INFO'] += '/'
            tmp_env['PATH_INFO'] += self._index
            resp = self._app_call(tmp_env)
            status_int = self._get_status_int()
            if status_int // 100 in (2, 3):
                if env['PATH_INFO'][-1] != '/':
                    resp = HTTPMovedPermanently(
                        location=env['PATH_INFO'] + '/')
                    self._log_response(env, resp.status_int)
                    return resp(env, start_response)
                start_response(self._response_status, self._response_headers,
                               self._response_exc_info)
                return resp
        if status_int == 404:
            if env['PATH_INFO'][-1] != '/':
                tmp_env = make_pre_authed_env(env, 'GET',
                            '/%s/%s/%s' % (self.version, self.account,
                                           self.container),
                            self.agent)
                tmp_env['QUERY_STRING'] = 'limit=1&format=json&delimiter' \
                    '=/&limit=1&prefix=%s' % quote(self.obj + '/')
                resp = self._app_call(tmp_env)
                body = ''.join(resp)
                if self._get_status_int() // 100 != 2 or not body or \
                        not json.loads(body):
                    resp = HTTPNotFound()(env, self._start_response)
                    return self._error_response(resp, env, start_response)
                resp = HTTPMovedPermanently(location=env['PATH_INFO'] +
                    '/')
                self._log_response(env, resp.status_int)
                return resp(env, start_response)
            return self._listing(env, start_response, self.obj)
Exemplo n.º 6
0
    def _error_response(self, response, env, start_response):
        """
        Sends the error response to the remote client, possibly resolving a
        custom error response body based on x-container-meta-web-error.

        :param response: The error response we should default to sending.
        :param env: The original request WSGI environment.
        :param start_response: The WSGI start_response hook.
        """
        if not self._error:
            start_response(self._response_status, self._response_headers,
                           self._response_exc_info)
            return response
        save_response_status = self._response_status
        save_response_headers = self._response_headers
        save_response_exc_info = self._response_exc_info
        resp = self._app_call(
            make_pre_authed_env(env,
                                'GET',
                                '/%s/%s/%s/%s%s' %
                                (self.version, self.account, self.container,
                                 self._get_status_int(), self._error),
                                self.agent,
                                swift_source='SW'))
        if is_success(self._get_status_int()):
            start_response(save_response_status, self._response_headers,
                           self._response_exc_info)
            return resp
        start_response(save_response_status, save_response_headers,
                       save_response_exc_info)
        return response
Exemplo n.º 7
0
    def _get_key(self, env, account):
        """
        Returns the X-Account-Meta-Temp-URL-Key header value for the
        account, or None if none is set.

        :param env: The WSGI environment for the request.
        :param account: Account str.
        :returns: X-Account-Meta-Temp-URL-Key str value, or None.
        """
        key = None
        memcache = env.get('swift.cache')
        if memcache:
            key = memcache.get('temp-url-key/%s' % account)
        if not key:
            newenv = make_pre_authed_env(env, 'HEAD', '/v1/' + account,
                                         self.agent)
            newenv['CONTENT_LENGTH'] = '0'
            newenv['wsgi.input'] = StringIO('')
            key = [None]

            def _start_response(status, response_headers, exc_info=None):
                for h, v in response_headers:
                    if h.lower() == 'x-account-meta-temp-url-key':
                        key[0] = v

            i = iter(self.app(newenv, _start_response))
            try:
                i.next()
            except StopIteration:
                pass
            key = key[0]
            if key and memcache:
                memcache.set('temp-url-key/%s' % account, key, timeout=60)
        return key
Exemplo n.º 8
0
    def handle_object(self, env, start_response):
        """
        Handles a possible static web request for an object. This object could
        resolve into an index or listing request.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        """
        tmp_env = dict(env)
        tmp_env['HTTP_USER_AGENT'] = \
            '%s StaticWeb' % env.get('HTTP_USER_AGENT')
        resp = self._app_call(tmp_env)
        status_int = self._get_status_int()
        if is_success(status_int) or is_redirection(status_int):
            start_response(self._response_status, self._response_headers,
                           self._response_exc_info)
            return resp
        if status_int != HTTP_NOT_FOUND:
            return self._error_response(resp, env, start_response)
        self._get_container_info(env)
        if not self._listings and not self._index:
            return self.app(env, start_response)
        status_int = HTTP_NOT_FOUND
        if self._index:
            tmp_env = dict(env)
            tmp_env['HTTP_USER_AGENT'] = \
                '%s StaticWeb' % env.get('HTTP_USER_AGENT')
            if tmp_env['PATH_INFO'][-1] != '/':
                tmp_env['PATH_INFO'] += '/'
            tmp_env['PATH_INFO'] += self._index
            resp = self._app_call(tmp_env)
            status_int = self._get_status_int()
            if is_success(status_int) or is_redirection(status_int):
                if env['PATH_INFO'][-1] != '/':
                    resp = HTTPMovedPermanently(
                        location=env['PATH_INFO'] + '/')
                    self._log_response(env, resp.status_int)
                    return resp(env, start_response)
                start_response(self._response_status, self._response_headers,
                               self._response_exc_info)
                return resp
        if status_int == HTTP_NOT_FOUND:
            if env['PATH_INFO'][-1] != '/':
                tmp_env = make_pre_authed_env(env, 'GET',
                            '/%s/%s/%s' % (self.version, self.account,
                                           self.container),
                            self.agent)
                tmp_env['QUERY_STRING'] = 'limit=1&format=json&delimiter' \
                    '=/&limit=1&prefix=%s' % quote(self.obj + '/')
                resp = self._app_call(tmp_env)
                body = ''.join(resp)
                if not is_success(self._get_status_int()) or not body or \
                        not json.loads(body):
                    resp = HTTPNotFound()(env, self._start_response)
                    return self._error_response(resp, env, start_response)
                resp = HTTPMovedPermanently(location=env['PATH_INFO'] +
                    '/')
                self._log_response(env, resp.status_int)
                return resp(env, start_response)
            return self._listing(env, start_response, self.obj)
Exemplo n.º 9
0
    def _error_response(self, response, env, start_response):
        """
        Sends the error response to the remote client, possibly resolving a
        custom error response body based on x-container-meta-web-error.

        :param response: The error response we should default to sending.
        :param env: The original request WSGI environment.
        :param start_response: The WSGI start_response hook.
        """
        if not self._error:
            start_response(self._response_status, self._response_headers,
                           self._response_exc_info)
            return response
        save_response_status = self._response_status
        save_response_headers = self._response_headers
        save_response_exc_info = self._response_exc_info
        resp = self._app_call(make_pre_authed_env(
            env, 'GET', '/%s/%s/%s/%s%s' % (
                self.version, self.account, self.container,
                self._get_status_int(), self._error),
            self.agent, swift_source='SW'))
        if is_success(self._get_status_int()):
            start_response(save_response_status, self._response_headers,
                           self._response_exc_info)
            return resp
        start_response(save_response_status, save_response_headers,
                       save_response_exc_info)
        return response
Exemplo n.º 10
0
    def _perform_subrequest(self, orig_env, attributes, fp, key):
        """
        Performs the subrequest and returns the response.

        :param orig_env: The WSGI environment dict; will only be used
                         to form a new env for the subrequest.
        :param attributes: dict of the attributes of the form so far.
        :param fp: The file-like object containing the request body.
        :param key: The account key to validate the signature with.
        :returns: (status_line, message)
        """
        if not key:
            return '401 Unauthorized', 'invalid signature'
        try:
            max_file_size = int(attributes.get('max_file_size') or 0)
        except ValueError:
            raise FormInvalid('max_file_size not an integer')
        subenv = make_pre_authed_env(orig_env,
                                     'PUT',
                                     agent=None,
                                     swift_source='FP')
        if 'QUERY_STRING' in subenv:
            del subenv['QUERY_STRING']
        subenv['HTTP_TRANSFER_ENCODING'] = 'chunked'
        subenv['wsgi.input'] = _CappedFileLikeObject(fp, max_file_size)
        if subenv['PATH_INFO'][-1] != '/' and \
                subenv['PATH_INFO'].count('/') < 4:
            subenv['PATH_INFO'] += '/'
        subenv['PATH_INFO'] += attributes['filename'] or 'filename'
        if 'content-type' in attributes:
            subenv['CONTENT_TYPE'] = \
                attributes['content-type'] or 'application/octet-stream'
        elif 'CONTENT_TYPE' in subenv:
            del subenv['CONTENT_TYPE']
        try:
            if int(attributes.get('expires') or 0) < time():
                return '401 Unauthorized', 'form expired'
        except ValueError:
            raise FormInvalid('expired not an integer')
        hmac_body = '%s\n%s\n%s\n%s\n%s' % (
            orig_env['PATH_INFO'], attributes.get('redirect')
            or '', attributes.get('max_file_size') or '0',
            attributes.get('max_file_count') or '0', attributes.get('expires')
            or '0')
        sig = hmac.new(key, hmac_body, sha1).hexdigest()
        if not streq_const_time(sig,
                                (attributes.get('signature') or 'invalid')):
            return '401 Unauthorized', 'invalid signature'
        substatus = [None]

        def _start_response(status, headers, exc_info=None):
            substatus[0] = status

        i = iter(self.app(subenv, _start_response))
        try:
            i.next()
        except StopIteration:
            pass
        return substatus[0], ''
Exemplo n.º 11
0
    def _perform_subrequest(self, orig_env, attributes, fp, key):
        """
        Performs the subrequest and returns the response.

        :param orig_env: The WSGI environment dict; will only be used
                         to form a new env for the subrequest.
        :param attributes: dict of the attributes of the form so far.
        :param fp: The file-like object containing the request body.
        :param key: The account key to validate the signature with.
        :returns: (status_line, message)
        """
        if not key:
            return '401 Unauthorized', 'invalid signature'
        try:
            max_file_size = int(attributes.get('max_file_size') or 0)
        except ValueError:
            raise FormInvalid('max_file_size not an integer')
        subenv = make_pre_authed_env(orig_env, 'PUT', agent=None,
                                     swift_source='FP')
        if 'QUERY_STRING' in subenv:
            del subenv['QUERY_STRING']
        subenv['HTTP_TRANSFER_ENCODING'] = 'chunked'
        subenv['wsgi.input'] = _CappedFileLikeObject(fp, max_file_size)
        if subenv['PATH_INFO'][-1] != '/' and \
                subenv['PATH_INFO'].count('/') < 4:
            subenv['PATH_INFO'] += '/'
        subenv['PATH_INFO'] += attributes['filename'] or 'filename'
        if 'content-type' in attributes:
            subenv['CONTENT_TYPE'] = \
                attributes['content-type'] or 'application/octet-stream'
        elif 'CONTENT_TYPE' in subenv:
            del subenv['CONTENT_TYPE']
        try:
            if int(attributes.get('expires') or 0) < time():
                return '401 Unauthorized', 'form expired'
        except ValueError:
            raise FormInvalid('expired not an integer')
        hmac_body = '%s\n%s\n%s\n%s\n%s' % (
            orig_env['PATH_INFO'],
            attributes.get('redirect') or '',
            attributes.get('max_file_size') or '0',
            attributes.get('max_file_count') or '0',
            attributes.get('expires') or '0')
        sig = hmac.new(key, hmac_body, sha1).hexdigest()
        if not streq_const_time(sig, (attributes.get('signature') or
                                      'invalid')):
            return '401 Unauthorized', 'invalid signature'
        substatus = [None]

        def _start_response(status, headers, exc_info=None):
            substatus[0] = status

        i = iter(self.app(subenv, _start_response))
        try:
            i.next()
        except StopIteration:
            pass
        return substatus[0], ''
Exemplo n.º 12
0
    def test_pre_auth_wsgi_input(self):
        oldenv = {}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue('wsgi.input' in newenv)
        self.assertEquals(newenv['wsgi.input'].read(), '')

        oldenv = {'wsgi.input': StringIO('original wsgi.input')}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue('wsgi.input' in newenv)
        self.assertEquals(newenv['wsgi.input'].read(), '')

        oldenv = {'swift.source': 'UT'}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertEquals(newenv['swift.source'], 'UT')

        oldenv = {'swift.source': 'UT'}
        newenv = wsgi.make_pre_authed_env(oldenv, swift_source='SA')
        self.assertEquals(newenv['swift.source'], 'SA')
Exemplo n.º 13
0
    def test_pre_auth_wsgi_input(self):
        oldenv = {}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue("wsgi.input" in newenv)
        self.assertEquals(newenv["wsgi.input"].read(), "")

        oldenv = {"wsgi.input": StringIO("original wsgi.input")}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertTrue("wsgi.input" in newenv)
        self.assertEquals(newenv["wsgi.input"].read(), "")

        oldenv = {"swift.source": "UT"}
        newenv = wsgi.make_pre_authed_env(oldenv)
        self.assertEquals(newenv["swift.source"], "UT")

        oldenv = {"swift.source": "UT"}
        newenv = wsgi.make_pre_authed_env(oldenv, swift_source="SA")
        self.assertEquals(newenv["swift.source"], "SA")
Exemplo n.º 14
0
def _prepare_pre_auth_info_request(env, path):
    """
    Prepares a pre authed request to obtain info using a HEAD.

    :param env: the environment used by the current request
    :param path: The unquoted request path
    :returns: the pre authed request
    """
    # Set the env for the pre_authed call without a query string
    newenv = make_pre_authed_env(env, "HEAD", path, agent="Swift", query_string="", swift_source="GET_INFO")
    # Note that Request.blank expects quoted path
    return Request.blank(quote(path), environ=newenv)
Exemplo n.º 15
0
def _prepare_pre_auth_info_request(env, path):
    """
    Prepares a pre authed request to obtain info using a HEAD.

    :param env: the environment used by the current request
    :param path: The unquoted request path
    :returns: the pre authed request
    """
    # Set the env for the pre_authed call without a query string
    newenv = make_pre_authed_env(env, 'HEAD', path, agent='Swift',
                                 query_string='', swift_source='GET_INFO')
    # Note that Request.blank expects quoted path
    return Request.blank(quote(path), environ=newenv)
Exemplo n.º 16
0
    def handle_object(self, env, start_response):
        """
        Handles a possible static web request for an object. This object could
        resolve into an index or listing request.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        """
        tmp_env = dict(env)
        tmp_env["HTTP_USER_AGENT"] = "%s StaticWeb" % env.get("HTTP_USER_AGENT")
        resp = self._app_call(tmp_env)
        status_int = self._get_status_int()
        if is_success(status_int) or is_redirection(status_int):
            start_response(self._response_status, self._response_headers, self._response_exc_info)
            return resp
        if status_int != HTTP_NOT_FOUND:
            return self._error_response(resp, env, start_response)
        self._get_container_info(env)
        if not self._listings and not self._index:
            return self.app(env, start_response)
        status_int = HTTP_NOT_FOUND
        if self._index:
            tmp_env = dict(env)
            tmp_env["HTTP_USER_AGENT"] = "%s StaticWeb" % env.get("HTTP_USER_AGENT")
            if tmp_env["PATH_INFO"][-1] != "/":
                tmp_env["PATH_INFO"] += "/"
            tmp_env["PATH_INFO"] += self._index
            resp = self._app_call(tmp_env)
            status_int = self._get_status_int()
            if is_success(status_int) or is_redirection(status_int):
                if env["PATH_INFO"][-1] != "/":
                    resp = HTTPMovedPermanently(location=env["PATH_INFO"] + "/")
                    self._log_response(env, resp.status_int)
                    return resp(env, start_response)
                start_response(self._response_status, self._response_headers, self._response_exc_info)
                return resp
        if status_int == HTTP_NOT_FOUND:
            if env["PATH_INFO"][-1] != "/":
                tmp_env = make_pre_authed_env(
                    env, "GET", "/%s/%s/%s" % (self.version, self.account, self.container), self.agent
                )
                tmp_env["QUERY_STRING"] = "limit=1&format=json&delimiter" "=/&limit=1&prefix=%s" % quote(self.obj + "/")
                resp = self._app_call(tmp_env)
                body = "".join(resp)
                if not is_success(self._get_status_int()) or not body or not json.loads(body):
                    resp = HTTPNotFound()(env, self._start_response)
                    return self._error_response(resp, env, start_response)
                resp = HTTPMovedPermanently(location=env["PATH_INFO"] + "/")
                self._log_response(env, resp.status_int)
                return resp(env, start_response)
            return self._listing(env, start_response, self.obj)
Exemplo n.º 17
0
def _prepare_pre_auth_info_request(env, path, swift_source):
    """
    Prepares a pre authed request to obtain info using a HEAD.

    :param env: the environment used by the current request
    :param path: The unquoted request path
    :param swift_source: value for swift.source in WSGI environment
    :returns: the pre authed request
    """
    # Set the env for the pre_authed call without a query string
    newenv = make_pre_authed_env(env, 'HEAD', path, agent='Swift',
                                 query_string='', swift_source=swift_source)
    # Note that Request.blank expects quoted path
    return Request.blank(quote(path), environ=newenv)
Exemplo n.º 18
0
def _prepare_pre_auth_info_request(env, path, swift_source):
    """
    Prepares a pre authed request to obtain info using a HEAD.

    :param env: the environment used by the current request
    :param path: The unquoted request path
    :param swift_source: value for swift.source in WSGI environment
    :returns: the pre authed request
    """
    # Set the env for the pre_authed call without a query string
    newenv = make_pre_authed_env(env, 'HEAD', path, agent='Swift',
                                 query_string='', swift_source=swift_source)
    # This is a sub request for container metadata- drop the Origin header from
    # the request so the it is not treated as a CORS request.
    newenv.pop('HTTP_ORIGIN', None)
    # Note that Request.blank expects quoted path
    return Request.blank(quote(path), environ=newenv)
Exemplo n.º 19
0
    def _get_key(self, env):
        """
        Returns the X-Account-Meta-Temp-URL-Key header value for the
        account, or None if none is set.

        :param env: The WSGI environment for the request.
        :returns: X-Account-Meta-Temp-URL-Key str value, or None.
        """
        parts = env['PATH_INFO'].split('/', 4)
        if len(parts) < 4 or parts[0] or parts[1] != 'v1' or not parts[2] or \
                not parts[3]:
            return None
        account = parts[2]
        key = None
        memcache = env.get('swift.cache')
        if memcache:
            key = memcache.get('temp-url-key/%s' % account)
        if not key:
            newenv = make_pre_authed_env(env,
                                         'HEAD',
                                         '/v1/' + account,
                                         agent=None,
                                         swift_source='FP')
            if 'QUERY_STRING' in newenv:
                del newenv['QUERY_STRING']
            newenv['CONTENT_LENGTH'] = '0'
            newenv['wsgi.input'] = StringIO('')
            key = [None]

            def _start_response(status, response_headers, exc_info=None):
                for h, v in response_headers:
                    if h.lower() == 'x-account-meta-temp-url-key':
                        key[0] = v

            i = iter(self.app(newenv, _start_response))
            try:
                i.next()
            except StopIteration:
                pass
            key = key[0]
            if key and memcache:
                memcache.set('temp-url-key/%s' % account, key, time=60)
        return key
Exemplo n.º 20
0
    def _get_keys(self, env, account):
        """
        Returns the X-Account-Meta-Temp-URL-Key[-2] header values for the
        account, or an empty list if none is set.

        Returns 0, 1, or 2 elements depending on how many keys are set
        in the account's metadata.

        :param env: The WSGI environment for the request.
        :param account: Account str.
        :returns: [X-Account-Meta-Temp-URL-Key str value if set,
                   X-Account-Meta-Temp-URL-Key-2 str value if set]
        """
        keys = None
        memcache = env.get('swift.cache')
        memcache_hash_key = 'temp-url-keys/%s' % account
        if memcache:
            keys = memcache.get(memcache_hash_key)
        if keys is None:
            newenv = make_pre_authed_env(env, 'HEAD', '/v1/' + account,
                                         self.agent, swift_source='TU')
            newenv['CONTENT_LENGTH'] = '0'
            newenv['wsgi.input'] = StringIO('')
            keys = []

            def _start_response(status, response_headers, exc_info=None):
                for h, v in response_headers:
                    if h.lower() == 'x-account-meta-temp-url-key':
                        keys.append(v)
                    elif h.lower() == 'x-account-meta-temp-url-key-2':
                        keys.append(v)

            i = iter(self.app(newenv, _start_response))
            try:
                i.next()
            except StopIteration:
                pass
            if memcache:
                timeout = 60 if keys else 6
                memcache.set(memcache_hash_key, keys, time=timeout)
        return keys
Exemplo n.º 21
0
    def _get_key(self, env):
        """
        Returns the X-Account-Meta-Temp-URL-Key header value for the
        account, or None if none is set.

        :param env: The WSGI environment for the request.
        :returns: X-Account-Meta-Temp-URL-Key str value, or None.
        """
        parts = env['PATH_INFO'].split('/', 4)
        if len(parts) < 4 or parts[0] or parts[1] != 'v1' or not parts[2] or \
                not parts[3]:
            return None
        account = parts[2]
        key = None
        memcache = env.get('swift.cache')
        if memcache:
            key = memcache.get('temp-url-key/%s' % account)
        if not key:
            newenv = make_pre_authed_env(env, 'HEAD', '/v1/' + account,
                                         agent=None, swift_source='FP')
            if 'QUERY_STRING' in newenv:
                del newenv['QUERY_STRING']
            newenv['CONTENT_LENGTH'] = '0'
            newenv['wsgi.input'] = StringIO('')
            key = [None]

            def _start_response(status, response_headers, exc_info=None):
                for h, v in response_headers:
                    if h.lower() == 'x-account-meta-temp-url-key':
                        key[0] = v

            i = iter(self.app(newenv, _start_response))
            try:
                i.next()
            except StopIteration:
                pass
            key = key[0]
            if key and memcache:
                memcache.set('temp-url-key/%s' % account, key, time=60)
        return key
Exemplo n.º 22
0
    def handle_object(self, env, start_response):
        """
        Handles a possible static web request for an object. This object could
        resolve into an index or listing request.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        """
        tmp_env = dict(env)
        tmp_env["HTTP_USER_AGENT"] = "%s StaticWeb" % env.get("HTTP_USER_AGENT")
        tmp_env["swift.source"] = "SW"
        resp = self._app_call(tmp_env)
        status_int = self._get_status_int()
        self._get_container_info(env)
        if is_success(status_int) or is_redirection(status_int):
            # Treat directory marker objects as not found
            if not self._dir_type:
                self._dir_type = "application/directory"
            content_length = self._response_header_value("content-length")
            content_length = int(content_length) if content_length else 0
            if self._response_header_value("content-type") == self._dir_type and content_length <= 1:
                status_int = HTTP_NOT_FOUND
            else:
                start_response(self._response_status, self._response_headers, self._response_exc_info)
                return resp
        if status_int != HTTP_NOT_FOUND:
            # Retaining the previous code's behavior of not using custom error
            # pages for non-404 errors.
            self._error = None
            return self._error_response(resp, env, start_response)
        if not self._listings and not self._index:
            return self.app(env, start_response)
        status_int = HTTP_NOT_FOUND
        if self._index:
            tmp_env = dict(env)
            tmp_env["HTTP_USER_AGENT"] = "%s StaticWeb" % env.get("HTTP_USER_AGENT")
            tmp_env["swift.source"] = "SW"
            if tmp_env["PATH_INFO"][-1] != "/":
                tmp_env["PATH_INFO"] += "/"
            tmp_env["PATH_INFO"] += self._index
            resp = self._app_call(tmp_env)
            status_int = self._get_status_int()
            if is_success(status_int) or is_redirection(status_int):
                if env["PATH_INFO"][-1] != "/":
                    resp = HTTPMovedPermanently(location=env["PATH_INFO"] + "/")
                    return resp(env, start_response)
                start_response(self._response_status, self._response_headers, self._response_exc_info)
                return resp
        if status_int == HTTP_NOT_FOUND:
            if env["PATH_INFO"][-1] != "/":
                tmp_env = make_pre_authed_env(
                    env,
                    "GET",
                    "/%s/%s/%s" % (self.version, self.account, self.container),
                    self.agent,
                    swift_source="SW",
                )
                tmp_env["QUERY_STRING"] = "limit=1&format=json&delimiter" "=/&limit=1&prefix=%s" % quote(self.obj + "/")
                resp = self._app_call(tmp_env)
                body = "".join(resp)
                if not is_success(self._get_status_int()) or not body or not json.loads(body):
                    resp = HTTPNotFound()(env, self._start_response)
                    return self._error_response(resp, env, start_response)
                resp = HTTPMovedPermanently(location=env["PATH_INFO"] + "/")
                return resp(env, start_response)
            return self._listing(env, start_response, self.obj)
Exemplo n.º 23
0
    def _listing(self, env, start_response, prefix=None):
        """
        Sends an HTML object listing to the remote client.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        :param prefix: Any prefix desired for the container listing.
        """
        if not config_true_value(self._listings):
            resp = HTTPNotFound()(env, self._start_response)
            return self._error_response(resp, env, start_response)
        tmp_env = make_pre_authed_env(
            env, 'GET', '/%s/%s/%s' % (
                self.version, self.account, self.container),
            self.agent, swift_source='SW')
        tmp_env['QUERY_STRING'] = 'delimiter=/&format=json'
        if prefix:
            tmp_env['QUERY_STRING'] += '&prefix=%s' % quote(prefix)
        else:
            prefix = ''
        resp = self._app_call(tmp_env)
        if not is_success(self._get_status_int()):
            return self._error_response(resp, env, start_response)
        listing = None
        body = ''.join(resp)
        if body:
            listing = json.loads(body)
        if not listing:
            resp = HTTPNotFound()(env, self._start_response)
            return self._error_response(resp, env, start_response)
        headers = {'Content-Type': 'text/html; charset=UTF-8'}
        body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \
               'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \
               '<html>\n' \
               ' <head>\n' \
               '  <title>Listing of %s</title>\n' % \
               cgi.escape(env['PATH_INFO'])
        if self._listings_css:
            body += '  <link rel="stylesheet" type="text/css" ' \
                    'href="%s" />\n' % (self._build_css_path(prefix))
        else:
            body += '  <style type="text/css">\n' \
                    '   h1 {font-size: 1em; font-weight: bold;}\n' \
                    '   th {text-align: left; padding: 0px 1em 0px 1em;}\n' \
                    '   td {padding: 0px 1em 0px 1em;}\n' \
                    '   a {text-decoration: none;}\n' \
                    '  </style>\n'
        body += ' </head>\n' \
                ' <body>\n' \
                '  <h1 id="title">Listing of %s</h1>\n' \
                '  <table id="listing">\n' \
                '   <tr id="heading">\n' \
                '    <th class="colname">Name</th>\n' \
                '    <th class="colsize">Size</th>\n' \
                '    <th class="coldate">Date</th>\n' \
                '   </tr>\n' % \
                cgi.escape(env['PATH_INFO'])
        if prefix:
            body += '   <tr id="parent" class="item">\n' \
                    '    <td class="colname"><a href="../">../</a></td>\n' \
                    '    <td class="colsize">&nbsp;</td>\n' \
                    '    <td class="coldate">&nbsp;</td>\n' \
                    '   </tr>\n'
        for item in listing:
            if 'subdir' in item:
                if isinstance(item['subdir'], unicode):
                    subdir = item['subdir'].encode('utf-8')
                else:
                    subdir = item['subdir']
                if prefix:
                    subdir = subdir[len(prefix):]
                body += '   <tr class="item subdir">\n' \
                        '    <td class="colname"><a href="%s">%s</a></td>\n' \
                        '    <td class="colsize">&nbsp;</td>\n' \
                        '    <td class="coldate">&nbsp;</td>\n' \
                        '   </tr>\n' % \
                        (quote(subdir), cgi.escape(subdir))
        for item in listing:
            if 'name' in item:
                if isinstance(item['name'], unicode):
                    name = item['name'].encode('utf-8')
                else:
                    name = item['name']
                if prefix:
                    name = name[len(prefix):]
                body += '   <tr class="item %s">\n' \
                        '    <td class="colname"><a href="%s">%s</a></td>\n' \
                        '    <td class="colsize">%s</td>\n' \
                        '    <td class="coldate">%s</td>\n' \
                        '   </tr>\n' % \
                        (' '.join('type-' + cgi.escape(t.lower(), quote=True)
                                  for t in item['content_type'].split('/')),
                         quote(name), cgi.escape(name),
                         human_readable(item['bytes']),
                         cgi.escape(item['last_modified']).split('.')[0].
                            replace('T', ' '))
        body += '  </table>\n' \
                ' </body>\n' \
                '</html>\n'
        resp = Response(headers=headers, body=body)
        return resp(env, start_response)
Exemplo n.º 24
0
    def _perform_subrequest(self, orig_env, attributes, fp, keys):
        """
        Performs the subrequest and returns the response.

        :param orig_env: The WSGI environment dict; will only be used
                         to form a new env for the subrequest.
        :param attributes: dict of the attributes of the form so far.
        :param fp: The file-like object containing the request body.
        :param keys: The account keys to validate the signature with.
        :returns: (status_line, headers_list)
        """
        if not keys:
            raise FormUnauthorized('invalid signature')
        try:
            max_file_size = int(attributes.get('max_file_size') or 0)
        except ValueError:
            raise FormInvalid('max_file_size not an integer')
        subenv = make_pre_authed_env(orig_env, 'PUT', agent=None,
                                     swift_source='FP')
        if 'QUERY_STRING' in subenv:
            del subenv['QUERY_STRING']
        subenv['HTTP_TRANSFER_ENCODING'] = 'chunked'
        subenv['wsgi.input'] = _CappedFileLikeObject(fp, max_file_size)
        if not subenv['PATH_INFO'].endswith('/') and \
                subenv['PATH_INFO'].count('/') < 4:
            subenv['PATH_INFO'] += '/'
        subenv['PATH_INFO'] += str_to_wsgi(
            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'
        if 'content-encoding' in attributes:
            subenv['HTTP_CONTENT_ENCODING'] = attributes['content-encoding']
        try:
            if int(attributes.get('expires') or 0) < time():
                raise FormUnauthorized('form expired')
        except ValueError:
            raise FormInvalid('expired not an integer')
        hmac_body = '%s\n%s\n%s\n%s\n%s' % (
            wsgi_to_str(orig_env['PATH_INFO']),
            attributes.get('redirect') or '',
            attributes.get('max_file_size') or '0',
            attributes.get('max_file_count') or '0',
            attributes.get('expires') or '0')
        if six.PY3:
            hmac_body = hmac_body.encode('utf-8')

        has_valid_sig = False
        for key in keys:
            # Encode key like in swift.common.utls.get_hmac.
            if not isinstance(key, six.binary_type):
                key = key.encode('utf8')
            sig = hmac.new(key, hmac_body, sha1).hexdigest()
            if streq_const_time(sig, (attributes.get('signature') or
                                      'invalid')):
                has_valid_sig = True
        if not has_valid_sig:
            raise FormUnauthorized('invalid signature')

        substatus = [None]
        subheaders = [None]

        wsgi_input = subenv['wsgi.input']

        def _start_response(status, headers, exc_info=None):
            if wsgi_input.file_size_exceeded:
                raise EOFError("max_file_size exceeded")

            substatus[0] = status
            subheaders[0] = headers

        # reiterate to ensure the response started,
        # but drop any data on the floor
        close_if_possible(reiterate(self.app(subenv, _start_response)))
        return substatus[0], subheaders[0]
Exemplo n.º 25
0
    def _listing(self, env, start_response, prefix=None):
        """
        Sends an HTML object listing to the remote client.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        :param prefix: Any prefix desired for the container listing.
        """
        if not config_true_value(self._listings):
            resp = HTTPNotFound()(env, self._start_response)
            return self._error_response(resp, env, start_response)
        tmp_env = make_pre_authed_env(
            env,
            'GET',
            '/%s/%s/%s' % (self.version, self.account, self.container),
            self.agent,
            swift_source='SW')
        tmp_env['QUERY_STRING'] = 'delimiter=/&format=json'
        if prefix:
            tmp_env['QUERY_STRING'] += '&prefix=%s' % quote(prefix)
        else:
            prefix = ''
        resp = self._app_call(tmp_env)
        if not is_success(self._get_status_int()):
            return self._error_response(resp, env, start_response)
        listing = None
        body = ''.join(resp)
        if body:
            listing = json.loads(body)
        if not listing:
            resp = HTTPNotFound()(env, self._start_response)
            return self._error_response(resp, env, start_response)
        headers = {'Content-Type': 'text/html; charset=UTF-8'}
        body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \
               'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \
               '<html>\n' \
               ' <head>\n' \
               '  <title>Listing of %s</title>\n' % \
               cgi.escape(env['PATH_INFO'])
        if self._listings_css:
            body += '  <link rel="stylesheet" type="text/css" ' \
                    'href="%s" />\n' % (self._build_css_path(prefix))
        else:
            body += '  <style type="text/css">\n' \
                    '   h1 {font-size: 1em; font-weight: bold;}\n' \
                    '   th {text-align: left; padding: 0px 1em 0px 1em;}\n' \
                    '   td {padding: 0px 1em 0px 1em;}\n' \
                    '   a {text-decoration: none;}\n' \
                    '  </style>\n'
        body += ' </head>\n' \
                ' <body>\n' \
                '  <h1 id="title">Listing of %s</h1>\n' \
                '  <table id="listing">\n' \
                '   <tr id="heading">\n' \
                '    <th class="colname">Name</th>\n' \
                '    <th class="colsize">Size</th>\n' \
                '    <th class="coldate">Date</th>\n' \
                '   </tr>\n' % \
                cgi.escape(env['PATH_INFO'])
        if prefix:
            body += '   <tr id="parent" class="item">\n' \
                    '    <td class="colname"><a href="../">../</a></td>\n' \
                    '    <td class="colsize">&nbsp;</td>\n' \
                    '    <td class="coldate">&nbsp;</td>\n' \
                    '   </tr>\n'
        for item in listing:
            if 'subdir' in item:
                subdir = item['subdir']
                if prefix:
                    subdir = subdir[len(prefix):]
                body += '   <tr class="item subdir">\n' \
                        '    <td class="colname"><a href="%s">%s</a></td>\n' \
                        '    <td class="colsize">&nbsp;</td>\n' \
                        '    <td class="coldate">&nbsp;</td>\n' \
                        '   </tr>\n' % \
                        (quote(subdir), cgi.escape(subdir))
        for item in listing:
            if 'name' in item:
                name = item['name']
                if prefix:
                    name = name[len(prefix):]
                body += '   <tr class="item %s">\n' \
                        '    <td class="colname"><a href="%s">%s</a></td>\n' \
                        '    <td class="colsize">%s</td>\n' \
                        '    <td class="coldate">%s</td>\n' \
                        '   </tr>\n' % \
                        (' '.join('type-' + cgi.escape(t.lower(), quote=True)
                                  for t in item['content_type'].split('/')),
                         quote(name), cgi.escape(name),
                         human_readable(item['bytes']),
                         cgi.escape(item['last_modified']).split('.')[0].
                            replace('T', ' '))
        body += '  </table>\n' \
                ' </body>\n' \
                '</html>\n'
        resp = Response(headers=headers, body=body)
        return resp(env, start_response)
Exemplo n.º 26
0
    def handle_object(self, env, start_response):
        """
        Handles a possible static web request for an object. This object could
        resolve into an index or listing request.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        """
        tmp_env = dict(env)
        tmp_env['HTTP_USER_AGENT'] = \
            '%s StaticWeb' % env.get('HTTP_USER_AGENT')
        tmp_env['swift.source'] = 'SW'
        resp = self._app_call(tmp_env)
        status_int = self._get_status_int()
        self._get_container_info(env)
        if is_success(status_int) or is_redirection(status_int):
            # Treat directory marker objects as not found
            if not self._dir_type:
                self._dir_type = 'application/directory'
            content_length = self._response_header_value('content-length')
            content_length = int(content_length) if content_length else 0
            if self._response_header_value('content-type') == self._dir_type \
                    and content_length <= 1:
                status_int = HTTP_NOT_FOUND
            else:
                start_response(self._response_status, self._response_headers,
                               self._response_exc_info)
                return resp
        if status_int != HTTP_NOT_FOUND:
            # Retaining the previous code's behavior of not using custom error
            # pages for non-404 errors.
            self._error = None
            return self._error_response(resp, env, start_response)
        if not self._listings and not self._index:
            start_response(self._response_status, self._response_headers,
                           self._response_exc_info)
            return resp
        status_int = HTTP_NOT_FOUND
        if self._index:
            tmp_env = dict(env)
            tmp_env['HTTP_USER_AGENT'] = \
                '%s StaticWeb' % env.get('HTTP_USER_AGENT')
            tmp_env['swift.source'] = 'SW'
            if tmp_env['PATH_INFO'][-1] != '/':
                tmp_env['PATH_INFO'] += '/'
            tmp_env['PATH_INFO'] += self._index
            resp = self._app_call(tmp_env)
            status_int = self._get_status_int()
            if is_success(status_int) or is_redirection(status_int):
                if env['PATH_INFO'][-1] != '/':
                    resp = HTTPMovedPermanently(location=env['PATH_INFO'] +
                                                '/')
                    return resp(env, start_response)
                start_response(self._response_status, self._response_headers,
                               self._response_exc_info)
                return resp
        if status_int == HTTP_NOT_FOUND:
            if env['PATH_INFO'][-1] != '/':
                tmp_env = make_pre_authed_env(
                    env,
                    'GET',
                    '/%s/%s/%s' % (self.version, self.account, self.container),
                    self.agent,
                    swift_source='SW')
                tmp_env['QUERY_STRING'] = 'limit=1&format=json&delimiter' \
                    '=/&limit=1&prefix=%s' % quote(self.obj + '/')
                resp = self._app_call(tmp_env)
                body = ''.join(resp)
                if not is_success(self._get_status_int()) or not body or \
                        not json.loads(body):
                    resp = HTTPNotFound()(env, self._start_response)
                    return self._error_response(resp, env, start_response)
                resp = HTTPMovedPermanently(location=env['PATH_INFO'] + '/')
                return resp(env, start_response)
            return self._listing(env, start_response, self.obj)
Exemplo n.º 27
0
    def _perform_subrequest(self, orig_env, attributes, fp, keys):
        """
        Performs the subrequest and returns the response.

        :param orig_env: The WSGI environment dict; will only be used
                         to form a new env for the subrequest.
        :param attributes: dict of the attributes of the form so far.
        :param fp: The file-like object containing the request body.
        :param keys: The account keys to validate the signature with.
        :returns: (status_line, headers_list)
        """
        if not keys:
            raise FormUnauthorized('invalid signature')
        try:
            max_file_size = int(attributes.get('max_file_size') or 0)
        except ValueError:
            raise FormInvalid('max_file_size not an integer')
        subenv = make_pre_authed_env(orig_env, 'PUT', agent=None,
                                     swift_source='FP')
        if 'QUERY_STRING' in subenv:
            del subenv['QUERY_STRING']
        subenv['HTTP_TRANSFER_ENCODING'] = 'chunked'
        subenv['wsgi.input'] = _CappedFileLikeObject(fp, max_file_size)
        if not subenv['PATH_INFO'].endswith('/') and \
                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'
        if 'content-encoding' in attributes:
            subenv['HTTP_CONTENT_ENCODING'] = attributes['content-encoding']
        try:
            if int(attributes.get('expires') or 0) < time():
                raise FormUnauthorized('form expired')
        except ValueError:
            raise FormInvalid('expired not an integer')
        hmac_body = '%s\n%s\n%s\n%s\n%s' % (
            orig_env['PATH_INFO'],
            attributes.get('redirect') or '',
            attributes.get('max_file_size') or '0',
            attributes.get('max_file_count') or '0',
            attributes.get('expires') or '0')
        if six.PY3:
            hmac_body = hmac_body.encode('utf-8')

        has_valid_sig = False
        for key in keys:
            sig = hmac.new(key, hmac_body, sha1).hexdigest()
            if streq_const_time(sig, (attributes.get('signature') or
                                      'invalid')):
                has_valid_sig = True
        if not has_valid_sig:
            raise FormUnauthorized('invalid signature')

        substatus = [None]
        subheaders = [None]

        wsgi_input = subenv['wsgi.input']

        def _start_response(status, headers, exc_info=None):
            if wsgi_input.file_size_exceeded:
                raise EOFError("max_file_size exceeded")

            substatus[0] = status
            subheaders[0] = headers

        # reiterate to ensure the response started,
        # but drop any data on the floor
        close_if_possible(reiterate(self.app(subenv, _start_response)))
        return substatus[0], subheaders[0]
Exemplo n.º 28
0
    def handle_object(self, env, start_response):
        """
        Handles a possible static web request for an object. This object could
        resolve into an index or listing request.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        """
        tmp_env = dict(env)
        tmp_env['HTTP_USER_AGENT'] = \
            '%s StaticWeb' % env.get('HTTP_USER_AGENT')
        tmp_env['swift.source'] = 'SW'
        resp = self._app_call(tmp_env)
        status_int = self._get_status_int()
        self._get_container_info(env)
        if is_success(status_int) or is_redirection(status_int):
            # Treat directory marker objects as not found
            if not self._dir_type:
                self._dir_type = 'application/directory'
            content_length = self._response_header_value('content-length')
            content_length = int(content_length) if content_length else 0
            if self._response_header_value('content-type') == self._dir_type \
                    and content_length <= 1:
                status_int = HTTP_NOT_FOUND
            else:
                start_response(self._response_status, self._response_headers,
                               self._response_exc_info)
                return resp
        if status_int != HTTP_NOT_FOUND:
            # Retaining the previous code's behavior of not using custom error
            # pages for non-404 errors.
            self._error = None
            return self._error_response(resp, env, start_response)
        if not self._listings and not self._index:
            return self.app(env, start_response)
        status_int = HTTP_NOT_FOUND
        if self._index:
            tmp_env = dict(env)
            tmp_env['HTTP_USER_AGENT'] = \
                '%s StaticWeb' % env.get('HTTP_USER_AGENT')
            tmp_env['swift.source'] = 'SW'
            if tmp_env['PATH_INFO'][-1] != '/':
                tmp_env['PATH_INFO'] += '/'
            tmp_env['PATH_INFO'] += self._index
            resp = self._app_call(tmp_env)
            status_int = self._get_status_int()
            if is_success(status_int) or is_redirection(status_int):
                if env['PATH_INFO'][-1] != '/':
                    resp = HTTPMovedPermanently(
                        location=env['PATH_INFO'] + '/')
                    return resp(env, start_response)
                start_response(self._response_status, self._response_headers,
                               self._response_exc_info)
                return resp
        if status_int == HTTP_NOT_FOUND:
            if env['PATH_INFO'][-1] != '/':
                tmp_env = make_pre_authed_env(
                    env, 'GET', '/%s/%s/%s' % (
                        self.version, self.account, self.container),
                    self.agent, swift_source='SW')
                tmp_env['QUERY_STRING'] = 'limit=1&format=json&delimiter' \
                    '=/&limit=1&prefix=%s' % quote(self.obj + '/')
                resp = self._app_call(tmp_env)
                body = ''.join(resp)
                if not is_success(self._get_status_int()) or not body or \
                        not json.loads(body):
                    resp = HTTPNotFound()(env, self._start_response)
                    return self._error_response(resp, env, start_response)
                resp = HTTPMovedPermanently(location=env['PATH_INFO'] + '/')
                return resp(env, start_response)
            return self._listing(env, start_response, self.obj)
Exemplo n.º 29
0
 def test_pre_auth_copies_script_name_unless_path_overridden(self):
     e = wsgi.make_pre_authed_env({"SCRIPT_NAME": "/script_name"}, path="/override")
     self.assertEquals(e["SCRIPT_NAME"], "")
     self.assertEquals(e["PATH_INFO"], "/override")
    def _perform_subrequest(self, orig_env, attributes, fp, keys):
        """
        Performs the subrequest and returns the response.

        :param orig_env: The WSGI environment dict; will only be used
                         to form a new env for the subrequest.
        :param attributes: dict of the attributes of the form so far.
        :param fp: The file-like object containing the request body.
        :param keys: The account keys to validate the signature with.
        :returns: (status_line, headers_list, message)
        """
        if not keys:
            raise FormUnauthorized("invalid signature")
        try:
            max_file_size = int(attributes.get("max_file_size") or 0)
        except ValueError:
            raise FormInvalid("max_file_size not an integer")
        subenv = make_pre_authed_env(orig_env, "PUT", agent=None, swift_source="FP")
        if "QUERY_STRING" in subenv:
            del subenv["QUERY_STRING"]
        subenv["HTTP_TRANSFER_ENCODING"] = "chunked"
        subenv["wsgi.input"] = _CappedFileLikeObject(fp, max_file_size)
        if subenv["PATH_INFO"][-1] != "/" and 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"
        elif "CONTENT_TYPE" in subenv:
            del subenv["CONTENT_TYPE"]
        try:
            if int(attributes.get("expires") or 0) < time():
                raise FormUnauthorized("form expired")
        except ValueError:
            raise FormInvalid("expired not an integer")
        hmac_body = "%s\n%s\n%s\n%s\n%s" % (
            orig_env["PATH_INFO"],
            attributes.get("redirect") or "",
            attributes.get("max_file_size") or "0",
            attributes.get("max_file_count") or "0",
            attributes.get("expires") or "0",
        )

        has_valid_sig = False
        for key in keys:
            sig = hmac.new(key, hmac_body, sha1).hexdigest()
            if streq_const_time(sig, (attributes.get("signature") or "invalid")):
                has_valid_sig = True
        if not has_valid_sig:
            raise FormUnauthorized("invalid signature")

        substatus = [None]
        subheaders = [None]

        wsgi_input = subenv["wsgi.input"]

        def _start_response(status, headers, exc_info=None):
            if wsgi_input.file_size_exceeded:
                raise EOFError("max_file_size exceeded")

            substatus[0] = status
            subheaders[0] = headers

        i = iter(self.app(subenv, _start_response))
        try:
            i.next()
        except StopIteration:
            pass
        return substatus[0], subheaders[0], ""
Exemplo n.º 31
0
 def test_pre_auth_copies_script_name(self):
     e = wsgi.make_pre_authed_env({'SCRIPT_NAME': '/script_name'})
     self.assertEquals(e['SCRIPT_NAME'], '/script_name')
Exemplo n.º 32
0
    def _listing(self, env, start_response, prefix=None):
        """
        Sends an HTML object listing to the remote client.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        :param prefix: Any prefix desired for the container listing.
        """
        if not config_true_value(self._listings):
            resp = HTTPNotFound()(env, self._start_response)
            return self._error_response(resp, env, start_response)
        tmp_env = make_pre_authed_env(
            env, "GET", "/%s/%s/%s" % (self.version, self.account, self.container), self.agent, swift_source="SW"
        )
        tmp_env["QUERY_STRING"] = "delimiter=/&format=json"
        if prefix:
            tmp_env["QUERY_STRING"] += "&prefix=%s" % quote(prefix)
        else:
            prefix = ""
        resp = self._app_call(tmp_env)
        if not is_success(self._get_status_int()):
            return self._error_response(resp, env, start_response)
        listing = None
        body = "".join(resp)
        if body:
            listing = json.loads(body)
        if not listing:
            resp = HTTPNotFound()(env, self._start_response)
            return self._error_response(resp, env, start_response)
        headers = {"Content-Type": "text/html; charset=UTF-8"}
        body = (
            '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 '
            'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n'
            "<html>\n"
            " <head>\n"
            "  <title>Listing of %s</title>\n" % cgi.escape(env["PATH_INFO"])
        )
        if self._listings_css:
            body += '  <link rel="stylesheet" type="text/css" ' 'href="%s" />\n' % (self._build_css_path(prefix))
        else:
            body += (
                '  <style type="text/css">\n'
                "   h1 {font-size: 1em; font-weight: bold;}\n"
                "   th {text-align: left; padding: 0px 1em 0px 1em;}\n"
                "   td {padding: 0px 1em 0px 1em;}\n"
                "   a {text-decoration: none;}\n"
                "  </style>\n"
            )
        body += (
            " </head>\n"
            " <body>\n"
            '  <h1 id="title">Listing of %s</h1>\n'
            '  <table id="listing">\n'
            '   <tr id="heading">\n'
            '    <th class="colname">Name</th>\n'
            '    <th class="colsize">Size</th>\n'
            '    <th class="coldate">Date</th>\n'
            "   </tr>\n" % cgi.escape(env["PATH_INFO"])
        )
        if prefix:
            body += (
                '   <tr id="parent" class="item">\n'
                '    <td class="colname"><a href="../">../</a></td>\n'
                '    <td class="colsize">&nbsp;</td>\n'
                '    <td class="coldate">&nbsp;</td>\n'
                "   </tr>\n"
            )
        for item in listing:
            if "subdir" in item:
                if isinstance(item["subdir"], unicode):
                    subdir = item["subdir"].encode("utf-8")
                else:
                    subdir = item["subdir"]
                if prefix:
                    subdir = subdir[len(prefix) :]
                body += (
                    '   <tr class="item subdir">\n'
                    '    <td class="colname"><a href="%s">%s</a></td>\n'
                    '    <td class="colsize">&nbsp;</td>\n'
                    '    <td class="coldate">&nbsp;</td>\n'
                    "   </tr>\n" % (quote(subdir), cgi.escape(subdir))
                )
        for item in listing:
            if "name" in item:
                if isinstance(item["name"], unicode):
                    name = item["name"].encode("utf-8")
                else:
                    name = item["name"]
                if prefix:
                    name = name[len(prefix) :]
                body += (
                    '   <tr class="item %s">\n'
                    '    <td class="colname"><a href="%s">%s</a></td>\n'
                    '    <td class="colsize">%s</td>\n'
                    '    <td class="coldate">%s</td>\n'
                    "   </tr>\n"
                    % (
                        " ".join("type-" + cgi.escape(t.lower(), quote=True) for t in item["content_type"].split("/")),
                        quote(name),
                        cgi.escape(name),
                        human_readable(item["bytes"]),
                        cgi.escape(item["last_modified"]).split(".")[0].replace("T", " "),
                    )
                )
        body += "  </table>\n" " </body>\n" "</html>\n"
        resp = Response(headers=headers, body=body)
        return resp(env, start_response)
Exemplo n.º 33
0
 def test_pre_auth_creates_script_name(self):
     e = wsgi.make_pre_authed_env({})
     self.assertTrue('SCRIPT_NAME' in e)
Exemplo n.º 34
0
 def test_pre_auth_copies_script_name(self):
     e = wsgi.make_pre_authed_env({"SCRIPT_NAME": "/script_name"})
     self.assertEquals(e["SCRIPT_NAME"], "/script_name")
Exemplo n.º 35
0
 def test_pre_auth_copies_script_name_unless_path_overridden(self):
     e = wsgi.make_pre_authed_env({'SCRIPT_NAME': '/script_name'},
                                  path='/override')
     self.assertEquals(e['SCRIPT_NAME'], '')
     self.assertEquals(e['PATH_INFO'], '/override')
Exemplo n.º 36
0
    def _perform_subrequest(self, orig_env, attributes, fp, keys):
        """
        Performs the subrequest and returns the response.

        :param orig_env: The WSGI environment dict; will only be used
                         to form a new env for the subrequest.
        :param attributes: dict of the attributes of the form so far.
        :param fp: The file-like object containing the request body.
        :param keys: The account keys to validate the signature with.
        :returns: (status_line, headers_list, message)
        """
        if not keys:
            raise FormUnauthorized('invalid signature')
        try:
            max_file_size = int(attributes.get('max_file_size') or 0)
        except ValueError:
            raise FormInvalid('max_file_size not an integer')
        subenv = make_pre_authed_env(orig_env,
                                     'PUT',
                                     agent=None,
                                     swift_source='FP')
        if 'QUERY_STRING' in subenv:
            del subenv['QUERY_STRING']
        subenv['HTTP_TRANSFER_ENCODING'] = 'chunked'
        subenv['wsgi.input'] = _CappedFileLikeObject(fp, max_file_size)
        if subenv['PATH_INFO'][-1] != '/' and \
                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'
        elif 'CONTENT_TYPE' in subenv:
            del subenv['CONTENT_TYPE']
        try:
            if int(attributes.get('expires') or 0) < time():
                raise FormUnauthorized('form expired')
        except ValueError:
            raise FormInvalid('expired not an integer')
        hmac_body = '%s\n%s\n%s\n%s\n%s' % (
            orig_env['PATH_INFO'], attributes.get('redirect')
            or '', attributes.get('max_file_size') or '0',
            attributes.get('max_file_count') or '0', attributes.get('expires')
            or '0')

        has_valid_sig = False
        for key in keys:
            sig = hmac.new(key, hmac_body, sha1).hexdigest()
            if streq_const_time(sig,
                                (attributes.get('signature') or 'invalid')):
                has_valid_sig = True
        if not has_valid_sig:
            raise FormUnauthorized('invalid signature')

        substatus = [None]
        subheaders = [None]

        wsgi_input = subenv['wsgi.input']

        def _start_response(status, headers, exc_info=None):
            if wsgi_input.file_size_exceeded:
                raise EOFError("max_file_size exceeded")

            substatus[0] = status
            subheaders[0] = headers

        i = iter(self.app(subenv, _start_response))
        try:
            next(i)
        except StopIteration:
            pass
        return substatus[0], subheaders[0], ''