Ejemplo n.º 1
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)
Ejemplo n.º 2
0
    def handle_container(self, env, start_response):
        """
        Handles a possible static web request for a container.

        :param env: The original WSGI environment dict.
        :param start_response: The original WSGI start_response hook.
        """
        self._get_container_info(env)
        if not self._listings and not self._index:
            if config_true_value(env.get('HTTP_X_WEB_MODE', 'f')):
                return HTTPNotFound()(env, start_response)
            return self.app(env, start_response)
        if not env['PATH_INFO'].endswith('/'):
            resp = HTTPMovedPermanently(location=(env['PATH_INFO'] + '/'))
            return resp(env, start_response)
        if not self._index:
            return self._listing(env, start_response)
        tmp_env = dict(env)
        tmp_env['HTTP_USER_AGENT'] = \
            '%s StaticWeb' % env.get('HTTP_USER_AGENT')
        tmp_env['swift.source'] = 'SW'
        tmp_env['PATH_INFO'] += self._index
        resp = self._app_call(tmp_env)
        status_int = self._get_status_int()
        if status_int == HTTP_NOT_FOUND:
            return self._listing(env, start_response)
        elif not is_success(self._get_status_int()) and \
                not is_redirection(self._get_status_int()):
            return self._error_response(resp, env, start_response)
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        return resp
Ejemplo n.º 3
0
    def _redirect_to_shard(self, req, broker, obj_name):
        """
        If the request indicates that it can accept a redirection, look for a
        shard range that contains ``obj_name`` and if one exists return a
        HTTPMovedPermanently response.

        :param req: an instance of :class:`~swift.common.swob.Request`
        :param broker: a container broker
        :param obj_name: an object name
        :return: an instance of :class:`swift.common.swob.HTTPMovedPermanently`
            if a shard range exists for the given ``obj_name``, otherwise None.
        """
        if not config_true_value(
                req.headers.get('x-backend-accept-redirect', False)):
            return None

        shard_ranges = broker.get_shard_ranges(includes=obj_name,
                                               states=SHARD_UPDATE_STATES)
        if not shard_ranges:
            return None

        # note: obj_name may be included in both a created sub-shard and its
        # sharding parent. get_shard_ranges will return the created sub-shard
        # in preference to the parent, which is the desired result.
        containing_range = shard_ranges[0]
        location = "/%s/%s" % (containing_range.name, obj_name)
        headers = {
            'Location': location,
            'X-Backend-Redirect-Timestamp': containing_range.timestamp.internal
        }

        # we do not want the host added to the location
        req.environ['swift.leave_relative_location'] = True
        return HTTPMovedPermanently(headers=headers, request=req)
Ejemplo n.º 4
0
 def _redirect_with_slash(self, env_, start_response):
     env = {}
     env.update(env_)
     if self.url_scheme:
         env['wsgi.url_scheme'] = self.url_scheme
     if self.url_host:
         env['HTTP_HOST'] = self.url_host
     resp = HTTPMovedPermanently(location=(env['PATH_INFO'] + '/'))
     return resp(env, start_response)
Ejemplo n.º 5
0
    def _redirect_to_shard(self, req, broker, obj_name):
        """
        If the request indicates that it can accept a redirection, look for a
        shard range that contains ``obj_name`` and if one exists return a
        HTTPMovedPermanently response.

        :param req: an instance of :class:`~swift.common.swob.Request`
        :param broker: a container broker
        :param obj_name: an object name
        :return: an instance of :class:`swift.common.swob.HTTPMovedPermanently`
            if a shard range exists for the given ``obj_name``, otherwise None.
        """
        if not config_true_value(
                req.headers.get('x-backend-accept-redirect', False)):
            # We want to avoid fetching shard ranges for the (more
            # time-sensitive) object-server update, so allow some misplaced
            # objects to land between when we've started sharding and when the
            # proxy learns about it. Note that this path is also used by old,
            # pre-sharding updaters during a rolling upgrade.
            return None

        shard_ranges = broker.get_shard_ranges(includes=obj_name,
                                               states=SHARD_UPDATE_STATES)
        if not shard_ranges:
            return None

        # note: obj_name may be included in both a created sub-shard and its
        # sharding parent. get_shard_ranges will return the created sub-shard
        # in preference to the parent, which is the desired result.
        containing_range = shard_ranges[0]
        location = "/%s/%s" % (containing_range.name, obj_name)
        if location != quote(location) and not config_true_value(
                req.headers.get('x-backend-accept-quoted-location', False)):
            # Sender expects the destination to be unquoted, but it isn't safe
            # to send unquoted. Eat the update for now and let the sharder
            # move it later. Should only come up during rolling upgrades.
            return None

        headers = {
            'Location': quote(location),
            'X-Backend-Location-Is-Quoted': 'true',
            'X-Backend-Redirect-Timestamp': containing_range.timestamp.internal
        }

        # we do not want the host added to the location
        req.environ['swift.leave_relative_location'] = True
        return HTTPMovedPermanently(headers=headers, request=req)
Ejemplo n.º 6
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 not tmp_env['PATH_INFO'].endswith('/'):
                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 not env['PATH_INFO'].endswith('/'):
                    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 not env['PATH_INFO'].endswith('/'):
                tmp_env = make_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)
Ejemplo n.º 7
0
 def __call__(self, env, start_response):
     loc = env['PATH_INFO'] + '/'
     return HTTPMovedPermanently(location=loc)(env, start_response)