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)
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
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)
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)
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)
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)
def __call__(self, env, start_response): loc = env['PATH_INFO'] + '/' return HTTPMovedPermanently(location=loc)(env, start_response)