Esempio n. 1
0
    def handle_request(self, env, start_response):
        trans_id_suffix = self.trans_id_suffix
        trans_id_extra = env.get('HTTP_X_TRANS_ID_EXTRA')
        if trans_id_extra:
            trans_id_suffix += '-' + trans_id_extra[:32]

        trans_id = generate_trans_id(trans_id_suffix)
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:
            # catch any errors in the pipeline
            resp = self._app_call(env)
        except:  # noqa
            self.logger.exception(_('Error: An error occurred'))
            resp = HTTPServerError(request=Request(env),
                                   body='An error occurred',
                                   content_type='text/plain')
            resp.headers['X-Trans-Id'] = trans_id
            resp.headers['X-Openstack-Request-Id'] = trans_id
            return resp(env, start_response)

        # make sure the response has the trans_id
        if self._response_headers is None:
            self._response_headers = []
        self._response_headers.append(('X-Trans-Id', trans_id))
        self._response_headers.append(('X-Openstack-Request-Id', trans_id))
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        return resp
Esempio n. 2
0
    def handle_request(self, env, start_response):
        trans_id_suffix = self.trans_id_suffix
        trans_id_extra = env.get('HTTP_X_TRANS_ID_EXTRA')
        if trans_id_extra:
            trans_id_suffix += '-' + trans_id_extra[:32]

        trans_id = generate_trans_id(trans_id_suffix)
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:
            # catch any errors in the pipeline
            resp = self._app_call(env)
        except:  # noqa
            self.logger.exception(_('Error: An error occurred'))
            resp = HTTPServerError(request=Request(env),
                                   body='An error occurred',
                                   content_type='text/plain')
            resp.headers['X-Trans-Id'] = trans_id
            resp.headers['X-Openstack-Request-Id'] = trans_id
            return resp(env, start_response)

        # make sure the response has the trans_id
        if self._response_headers is None:
            self._response_headers = []
        self._response_headers.append(('X-Trans-Id', trans_id))
        self._response_headers.append(('X-Openstack-Request-Id', trans_id))
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        return resp
Esempio n. 3
0
 def handle_request(self, env, start_response):
     trans_id = generate_trans_id(self.trans_id_suffix)
     env['swift.trans_id'] = trans_id
     self.logger.txn_id = trans_id
     try:
         # catch any errors in the pipeline
         resp = self._app_call(env)
     except (Exception, Timeout), err:
         self.logger.exception(_('Error: %s'), err)
         resp = HTTPServerError(request=Request(env),
                                body='An error occurred',
                                content_type='text/plain')
         resp.headers['X-Trans-Id'] = trans_id
         return resp(env, start_response)
Esempio n. 4
0
 def handle_request(self, env, start_response):
     trans_id = generate_trans_id(self.trans_id_suffix)
     env['swift.trans_id'] = trans_id
     self.logger.txn_id = trans_id
     try:
         # catch any errors in the pipeline
         resp = self._app_call(env)
     except (Exception, Timeout), err:
         self.logger.exception(_('Error: %s'), err)
         resp = HTTPServerError(request=Request(env),
                                body='An error occurred',
                                content_type='text/plain')
         resp.headers['X-Trans-Id'] = trans_id
         return resp(env, start_response)
Esempio n. 5
0
    def handle_request(self, env, start_response):
        trans_id = generate_trans_id(self.trans_id_suffix)
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:
            # catch any errors in the pipeline
            resp = self._app_call(env)
        except (Exception, Timeout) as err:
            self.logger.exception(_('Error: %s'), err)
            resp = HTTPServerError(request=Request(env),
                                   body='An error occurred',
                                   content_type='text/plain')
            resp.headers['X-Trans-Id'] = trans_id
            return resp(env, start_response)

        # make sure the response has the trans_id
        if self._response_headers is None:
            self._response_headers = []
        self._response_headers.append(('X-Trans-Id', trans_id))
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        return resp
Esempio n. 6
0
    def handle_request(self, env, start_response):
        trans_id = generate_trans_id(self.trans_id_suffix)
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:
            # catch any errors in the pipeline
            resp = self._app_call(env)
        except (Exception, Timeout) as err:
            self.logger.exception(_('Error: %s'), err)
            resp = HTTPServerError(request=Request(env),
                                   body='An error occurred',
                                   content_type='text/plain')
            resp.headers['X-Trans-Id'] = trans_id
            return resp(env, start_response)

        # make sure the response has the trans_id
        if self._response_headers is None:
            self._response_headers = []
        self._response_headers.append(('X-Trans-Id', trans_id))
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        return resp
Esempio n. 7
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        try:
            self.logger.set_statsd_prefix('proxy-server')
            if req.content_length and req.content_length < 0:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req,
                                      body='Invalid Content-Length')

            try:
                if not check_utf8(req.path_info):
                    self.logger.increment('errors')
                    return HTTPPreconditionFailed(
                        request=req, body='Invalid UTF8 or contains NULL')
            except UnicodeError:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(
                    request=req, body='Invalid UTF8 or contains NULL')

            try:
                controller, path_parts = self.get_controller(req.path)
                p = req.path_info
                if isinstance(p, unicode):
                    p = p.encode('utf-8')
            except ValueError:
                self.logger.increment('errors')
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Bad URL')
            if self.deny_host_headers and \
                    req.host.split(':')[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body='Invalid host header')

            self.logger.set_statsd_prefix('proxy-server.' +
                                          controller.server_type.lower())
            controller = controller(self, **path_parts)
            if 'swift.trans_id' not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id = generate_trans_id(self.trans_id_suffix)
                req.environ['swift.trans_id'] = trans_id
                self.logger.txn_id = trans_id
            req.headers['x-trans-id'] = req.environ['swift.trans_id']
            controller.trans_id = req.environ['swift.trans_id']
            self.logger.client_ip = get_remote_client(req)
            try:
                handler = getattr(controller, req.method)
                getattr(handler, 'publicly_accessible')
            except AttributeError:
                allowed_methods = getattr(controller, 'allowed_methods', set())
                return HTTPMethodNotAllowed(
                    request=req, headers={'Allow': ', '.join(allowed_methods)})
            if 'swift.authorize' in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ['swift.authorize'](req)
                if not resp:
                    # No resp means authorized, no delayed recheck required.
                    del req.environ['swift.authorize']
                else:
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, 'delay_denial', None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ['swift.orig_req_method'] = req.method
            return handler(req)
        except HTTPException as error_response:
            return error_response
        except (Exception, Timeout):
            self.logger.exception(_('ERROR Unhandled exception in request'))
            return HTTPServerError(request=req)
Esempio n. 8
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        try:
            self.logger.set_statsd_prefix('proxy-server')
            if req.content_length and req.content_length < 0:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req,
                                      body='Invalid Content-Length')

            try:
                if not check_utf8(req.path_info):
                    self.logger.increment('errors')
                    return HTTPPreconditionFailed(
                        request=req, body='Invalid UTF8 or contains NULL')
            except UnicodeError:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(
                    request=req, body='Invalid UTF8 or contains NULL')

            try:
                controller, path_parts = self.get_controller(req)
                p = req.path_info
                if isinstance(p, six.text_type):
                    p = p.encode('utf-8')
            except APIVersionError:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req)
            except ValueError:
                self.logger.increment('errors')
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Bad URL')
            if self.deny_host_headers and \
                    req.host.split(':')[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body='Invalid host header')

            self.logger.set_statsd_prefix('proxy-server.' +
                                          controller.server_type.lower())
            controller = controller(self, **path_parts)
            if 'swift.trans_id' not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id_suffix = self.trans_id_suffix
                trans_id_extra = req.headers.get('x-trans-id-extra')
                if trans_id_extra:
                    trans_id_suffix += '-' + trans_id_extra[:32]
                trans_id = generate_trans_id(trans_id_suffix)
                req.environ['swift.trans_id'] = trans_id
                self.logger.txn_id = trans_id
            req.headers['x-trans-id'] = req.environ['swift.trans_id']
            controller.trans_id = req.environ['swift.trans_id']
            self.logger.client_ip = get_remote_client(req)
            try:
                handler = getattr(controller, req.method)
                getattr(handler, 'publicly_accessible')
            except AttributeError:
                allowed_methods = getattr(controller, 'allowed_methods', set())
                return HTTPMethodNotAllowed(
                    request=req, headers={'Allow': ', '.join(allowed_methods)})
            old_authorize = None
            if 'swift.authorize' in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ['swift.authorize'](req)
                if not resp and not req.headers.get('X-Copy-From-Account') \
                        and not req.headers.get('Destination-Account'):
                    # No resp means authorized, no delayed recheck required.
                    old_authorize = req.environ['swift.authorize']
                else:
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, 'delay_denial', None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ['swift.orig_req_method'] = req.method
            try:
                if old_authorize:
                    req.environ.pop('swift.authorize', None)
                return handler(req)
            finally:
                if old_authorize:
                    req.environ['swift.authorize'] = old_authorize
        except HTTPException as error_response:
            return error_response
        except (Exception, Timeout):
            self.logger.exception(_('ERROR Unhandled exception in request'))
            return HTTPServerError(request=req)
Esempio n. 9
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        try:
            #设置日志的前缀为proxy-server
            self.logger.set_statsd_prefix('proxy-server')
            #如果请求长度为负数,报错
            if req.content_length and req.content_length < 0:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req,
                                      body='Invalid Content-Length')

            try:
                #如果路径信息不是有效的utf-8编码,报错
                if not check_utf8(req.path_info):
                    self.logger.increment('errors')
                    return HTTPPreconditionFailed(
                        request=req, body='Invalid UTF8 or contains NULL')
            except UnicodeError:
                #解码utf-8失败,报错
                self.logger.increment('errors')
                return HTTPPreconditionFailed(
                    request=req, body='Invalid UTF8 or contains NULL')

            try:
                #1、根据请求的路径信息,获取对应的控制器对象,并返回路径字典
                controller, path_parts = self.get_controller(req)
                p = req.path_info
                if isinstance(p, six.text_type):
                    p = p.encode('utf-8')
            except APIVersionError:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req)
            except ValueError:
                self.logger.increment('errors')
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Bad URL')
            if self.deny_host_headers and \
                    req.host.split(':')[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body='Invalid host header')

            self.logger.set_statsd_prefix('proxy-server.' +
                                          controller.server_type.lower())
            #2、生成控制器对象
            controller = controller(self, **path_parts)
            #如果没有在请求的env中设置swift.trans_id,那么现在设置
            if 'swift.trans_id' not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id_suffix = self.trans_id_suffix
                trans_id_extra = req.headers.get('x-trans-id-extra')
                if trans_id_extra:
                    trans_id_suffix += '-' + trans_id_extra[:32]
                trans_id = generate_trans_id(trans_id_suffix)
                req.environ['swift.trans_id'] = trans_id
                self.logger.txn_id = trans_id
            req.headers['x-trans-id'] = req.environ['swift.trans_id']
            controller.trans_id = req.environ['swift.trans_id']
            self.logger.client_ip = get_remote_client(req)
            try:
                #3、根据请求方法,获取对应的函数指针handler
                handler = getattr(controller, req.method)
                getattr(handler, 'publicly_accessible')
            except AttributeError:
                allowed_methods = getattr(controller, 'allowed_methods', set())
                return HTTPMethodNotAllowed(
                    request=req, headers={'Allow': ', '.join(allowed_methods)})
            old_authorize = None
            #4、如果请求的env中有鉴权方法,调用该鉴权方法,进行鉴权
            if 'swift.authorize' in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ['swift.authorize'](req)
                if not resp and not req.headers.get('X-Copy-From-Account') \
                        and not req.headers.get('Destination-Account'):
                    # No resp means authorized, no delayed recheck required.
                    old_authorize = req.environ['swift.authorize']
                else:
                    # 返回resp代表鉴权失败,但是我们可能延迟后重新检查,如果没有设置延迟检查,则返回失败
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, 'delay_denial', None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ['swift.orig_req_method'] = req.method
            try:
                #将鉴权方法从请求的env中取出,以免后续再次调用
                if old_authorize:
                    req.environ.pop('swift.authorize', None)
                #5、调用处理请求的方法,处理请求
                return handler(req)
            finally:
                if old_authorize:
                    req.environ['swift.authorize'] = old_authorize
        except HTTPException as error_response:
            return error_response
        except (Exception, Timeout):
            self.logger.exception(_('ERROR Unhandled exception in request'))
            return HTTPServerError(request=req)
Esempio n. 10
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        try:
            self.logger.set_statsd_prefix('proxy-server')
            # content_length存在且小于0,返回错误。
            if req.content_length and req.content_length < 0:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req,
                                      body='Invalid Content-Length')

            try:
                if not check_utf8(req.path_info):
                    self.logger.increment('errors')
                    return HTTPPreconditionFailed(
                        request=req, body='Invalid UTF8 or contains NULL')
            except UnicodeError:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(
                    request=req, body='Invalid UTF8 or contains NULL')

            try:
                # 根据 path获取相应的 controller, 如:
                # 1. AccountController.  2. ContainerController
                # 3. ECObjectController  4. ReplicatedObjectController
                # 5. InfoController
                # path_parts is a dict : (version=version,
                #                  account_name=account,
                #                  container_name=container,
                #                  object_name=obj)
                controller, path_parts = self.get_controller(req)
            except APIVersionError:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req)
            except ValueError:
                self.logger.increment('errors')
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Bad URL')
            if self.deny_host_headers and \
                    req.host.split(':')[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body='Invalid host header')

            self.logger.set_statsd_prefix('proxy-server.' +
                                          controller.server_type.lower())
            # 实例化 controller
            controller = controller(self, **path_parts)
            if 'swift.trans_id' not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id_suffix = self.trans_id_suffix
                trans_id_extra = req.headers.get('x-trans-id-extra')
                if trans_id_extra:
                    trans_id_suffix += '-' + trans_id_extra[:32]
                trans_id = generate_trans_id(trans_id_suffix)
                req.environ['swift.trans_id'] = trans_id
                self.logger.txn_id = trans_id
            req.headers['x-trans-id'] = req.environ['swift.trans_id']
            controller.trans_id = req.environ['swift.trans_id']
            self.logger.client_ip = get_remote_client(req)

            if req.method not in controller.allowed_methods:
                return HTTPMethodNotAllowed(
                    request=req,
                    headers={'Allow': ', '.join(controller.allowed_methods)})
            # getattr(object, name) 返回一个对象的属性值
            # 根据 req.method 的值返回controller的 HEAD() GET() PUT() 等函数
            handler = getattr(controller, req.method)

            old_authorize = None
            # swift.authrize 是 swift_auth 提供的句柄
            if 'swift.authorize' in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ['swift.authorize'](req)
                if not resp:
                    # No resp means authorized, no delayed recheck required.
                    old_authorize = req.environ['swift.authorize']
                else:
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, 'delay_denial', None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ.setdefault('swift.orig_req_method', req.method)
            try:
                if old_authorize:
                    req.environ.pop('swift.authorize', None)
                return handler(req)  # call HEAD(),GET(),PUT(),etc...
            finally:
                if old_authorize:
                    req.environ['swift.authorize'] = old_authorize
        except HTTPException as error_response:
            return error_response
        except (Exception, Timeout):
            self.logger.exception(_('ERROR Unhandled exception in request'))
            return HTTPServerError(request=req)
Esempio n. 11
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        try:
            self.logger.set_statsd_prefix("proxy-server")
            if req.content_length and req.content_length < 0:
                self.logger.increment("errors")
                return HTTPBadRequest(request=req, body="Invalid Content-Length")

            try:
                if not check_utf8(req.path_info):
                    self.logger.increment("errors")
                    return HTTPPreconditionFailed(request=req, body="Invalid UTF8 or contains NULL")
            except UnicodeError:
                self.logger.increment("errors")
                return HTTPPreconditionFailed(request=req, body="Invalid UTF8 or contains NULL")

            try:
                controller, path_parts = self.get_controller(req)
                p = req.path_info
                if isinstance(p, six.text_type):
                    p = p.encode("utf-8")
            except APIVersionError:
                self.logger.increment("errors")
                return HTTPBadRequest(request=req)
            except ValueError:
                self.logger.increment("errors")
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment("errors")
                return HTTPPreconditionFailed(request=req, body="Bad URL")
            if self.deny_host_headers and req.host.split(":")[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body="Invalid host header")

            self.logger.set_statsd_prefix("proxy-server." + controller.server_type.lower())
            controller = controller(self, **path_parts)
            if "swift.trans_id" not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id_suffix = self.trans_id_suffix
                trans_id_extra = req.headers.get("x-trans-id-extra")
                if trans_id_extra:
                    trans_id_suffix += "-" + trans_id_extra[:32]
                trans_id = generate_trans_id(trans_id_suffix)
                req.environ["swift.trans_id"] = trans_id
                self.logger.txn_id = trans_id
            req.headers["x-trans-id"] = req.environ["swift.trans_id"]
            controller.trans_id = req.environ["swift.trans_id"]
            self.logger.client_ip = get_remote_client(req)
            try:
                handler = getattr(controller, req.method)
                getattr(handler, "publicly_accessible")
            except AttributeError:
                allowed_methods = getattr(controller, "allowed_methods", set())
                return HTTPMethodNotAllowed(request=req, headers={"Allow": ", ".join(allowed_methods)})
            old_authorize = None
            if "swift.authorize" in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ["swift.authorize"](req)
                if (
                    not resp
                    and not req.headers.get("X-Copy-From-Account")
                    and not req.headers.get("Destination-Account")
                ):
                    # No resp means authorized, no delayed recheck required.
                    old_authorize = req.environ["swift.authorize"]
                else:
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, "delay_denial", None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ["swift.orig_req_method"] = req.method
            try:
                if old_authorize:
                    req.environ.pop("swift.authorize", None)
                return handler(req)
            finally:
                if old_authorize:
                    req.environ["swift.authorize"] = old_authorize
        except HTTPException as error_response:
            return error_response
        except (Exception, Timeout):
            self.logger.exception(_("ERROR Unhandled exception in request"))
            return HTTPServerError(request=req)
Esempio n. 12
0
    def handle_request(self, env, start_response):
        trans_id_suffix = self.trans_id_suffix
        trans_id_extra = env.get('HTTP_X_TRANS_ID_EXTRA')
        if trans_id_extra:
            trans_id_suffix += '-' + trans_id_extra[:32]

        trans_id = generate_trans_id(trans_id_suffix)
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:
            # catch any errors in the pipeline
            resp = self._app_call(env)
        except:  # noqa
            self.logger.exception(_('Error: An error occurred'))
            resp = HTTPServerError(request=Request(env),
                                   body=b'An error occurred',
                                   content_type='text/plain')
            resp.headers['X-Trans-Id'] = trans_id
            resp.headers['X-Openstack-Request-Id'] = trans_id
            return resp(env, start_response)

        # If the app specified a Content-Length, enforce that it sends that
        # many bytes.
        #
        # If an app gives too few bytes, then the client will wait for the
        # remainder before sending another HTTP request on the same socket;
        # since no more bytes are coming, this will result in either an
        # infinite wait or a timeout. In this case, we want to raise an
        # exception to signal to the WSGI server that it should close the
        # TCP connection.
        #
        # If an app gives too many bytes, then we can deadlock with the
        # client; if the client reads its N bytes and then sends a large-ish
        # request (enough to fill TCP buffers), it'll block until we read
        # some of the request. However, we won't read the request since
        # we'll be trying to shove the rest of our oversized response out
        # the socket. In that case, we truncate the response body at N bytes
        # and raise an exception to stop any more bytes from being
        # generated and also to kill the TCP connection.
        if env['REQUEST_METHOD'] == 'HEAD':
            resp = enforce_byte_count(resp, 0)

        elif self._response_headers:
            content_lengths = [
                val for header, val in self._response_headers
                if header.lower() == "content-length"
            ]
            if len(content_lengths) == 1:
                try:
                    content_length = int(content_lengths[0])
                except ValueError:
                    pass
                else:
                    resp = enforce_byte_count(resp, content_length)

        # make sure the response has the trans_id
        if self._response_headers is None:
            self._response_headers = []
        self._response_headers.append(('X-Trans-Id', trans_id))
        self._response_headers.append(('X-Openstack-Request-Id', trans_id))
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        return resp
Esempio n. 13
0
    def handle_request(self, env, start_response):
        trans_id_suffix = self.trans_id_suffix
        trans_id_extra = env.get('HTTP_X_TRANS_ID_EXTRA')
        if trans_id_extra:
            trans_id_suffix += '-' + trans_id_extra[:32]

        trans_id = generate_trans_id(trans_id_suffix)
        env['swift.trans_id'] = trans_id
        self.logger.txn_id = trans_id
        try:
            # catch any errors in the pipeline
            resp = self._app_call(env)
        except:  # noqa
            self.logger.exception(_('Error: An error occurred'))
            resp = HTTPServerError(request=Request(env),
                                   body=b'An error occurred',
                                   content_type='text/plain')
            resp.headers['X-Trans-Id'] = trans_id
            resp.headers['X-Openstack-Request-Id'] = trans_id
            return resp(env, start_response)

        # If the app specified a Content-Length, enforce that it sends that
        # many bytes.
        #
        # If an app gives too few bytes, then the client will wait for the
        # remainder before sending another HTTP request on the same socket;
        # since no more bytes are coming, this will result in either an
        # infinite wait or a timeout. In this case, we want to raise an
        # exception to signal to the WSGI server that it should close the
        # TCP connection.
        #
        # If an app gives too many bytes, then we can deadlock with the
        # client; if the client reads its N bytes and then sends a large-ish
        # request (enough to fill TCP buffers), it'll block until we read
        # some of the request. However, we won't read the request since
        # we'll be trying to shove the rest of our oversized response out
        # the socket. In that case, we truncate the response body at N bytes
        # and raise an exception to stop any more bytes from being
        # generated and also to kill the TCP connection.
        if env['REQUEST_METHOD'] == 'HEAD':
            resp = enforce_byte_count(resp, 0)

        elif self._response_headers:
            content_lengths = [val for header, val in self._response_headers
                               if header.lower() == "content-length"]
            if len(content_lengths) == 1:
                try:
                    content_length = int(content_lengths[0])
                except ValueError:
                    pass
                else:
                    resp = enforce_byte_count(resp, content_length)

        # make sure the response has the trans_id
        if self._response_headers is None:
            self._response_headers = []
        self._response_headers.append(('X-Trans-Id', trans_id))
        self._response_headers.append(('X-Openstack-Request-Id', trans_id))
        start_response(self._response_status, self._response_headers,
                       self._response_exc_info)
        return resp
Esempio n. 14
0
    def handle_request(self, req):
        """
        Entry point for proxy server.
        Should return a WSGI-style callable (such as swob.Response).

        :param req: swob.Request object
        """
        try:
            self.logger.set_statsd_prefix('proxy-server')
            if req.content_length and req.content_length < 0:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req,
                                      body='Invalid Content-Length')

            try:
                if not check_utf8(req.path_info):
                    self.logger.increment('errors')
                    return HTTPPreconditionFailed(
                        request=req, body='Invalid UTF8 or contains NULL')
            except UnicodeError:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(
                    request=req, body='Invalid UTF8 or contains NULL')

            try:
                # 这里确定controller的类型,根据req的内容分别返回:
                # account controller,container controller 或者 object controller。
                controller, path_parts = self.get_controller(req)
                p = req.path_info
                if isinstance(p, unicode):
                    p = p.encode('utf-8')
            except APIVersionError:
                self.logger.increment('errors')
                return HTTPBadRequest(request=req)
            except ValueError:
                self.logger.increment('errors')
                return HTTPNotFound(request=req)
            if not controller:
                self.logger.increment('errors')
                return HTTPPreconditionFailed(request=req, body='Bad URL')
            if self.deny_host_headers and \
                    req.host.split(':')[0] in self.deny_host_headers:
                return HTTPForbidden(request=req, body='Invalid host header')

            self.logger.set_statsd_prefix('proxy-server.' +
                                          controller.server_type.lower())
            controller = controller(self, **path_parts)
            if 'swift.trans_id' not in req.environ:
                # if this wasn't set by an earlier middleware, set it now
                trans_id_suffix = self.trans_id_suffix
                trans_id_extra = req.headers.get('x-trans-id-extra')
                if trans_id_extra:
                    trans_id_suffix += '-' + trans_id_extra[:32]
                trans_id = generate_trans_id(trans_id_suffix)
                req.environ['swift.trans_id'] = trans_id
                self.logger.txn_id = trans_id
            req.headers['x-trans-id'] = req.environ['swift.trans_id']
            controller.trans_id = req.environ['swift.trans_id']
            self.logger.client_ip = get_remote_client(req)
            try:
                # 这里的handler是相应controller类中对应于req中方法的方法。
                # 这些方法包括:GET,HEAD,POST,PUT,DELETE,COPY
                handler = getattr(controller, req.method)
                getattr(handler, 'publicly_accessible')
            except AttributeError:
                allowed_methods = getattr(controller, 'allowed_methods', set())
                return HTTPMethodNotAllowed(
                    request=req, headers={'Allow': ', '.join(allowed_methods)})
            if 'swift.authorize' in req.environ:
                # We call authorize before the handler, always. If authorized,
                # we remove the swift.authorize hook so isn't ever called
                # again. If not authorized, we return the denial unless the
                # controller's method indicates it'd like to gather more
                # information and try again later.
                resp = req.environ['swift.authorize'](req)
                if not resp and not req.headers.get('X-Copy-From-Account') \
                        and not req.headers.get('Destination-Account'):
                    # No resp means authorized, no delayed recheck required.
                    del req.environ['swift.authorize']
                else:
                    # Response indicates denial, but we might delay the denial
                    # and recheck later. If not delayed, return the error now.
                    if not getattr(handler, 'delay_denial', None):
                        return resp
            # Save off original request method (GET, POST, etc.) in case it
            # gets mutated during handling.  This way logging can display the
            # method the client actually sent.
            req.environ['swift.orig_req_method'] = req.method
            # 这里返回的是相应于req的controller中具体的处理这个类型的req的方法。
            # 经过层层调用之后,handler(req)其实是一个Response类的实例。
            # 调用过程为(以get object为例):
            # swift.proxy.controllers.ObjectControllerRouter 中找到对应的controller
            # 在 BaseObjectController 中找到 GET 方法,GET 方法使用 GETorHEAD 方法
            # GETorHEAD 方法跳到 ReplicatedObjectController 中的 _get_or_head_response 方法
            # _get_or_head_response 使用 swift.proxy.controller.Controller(base.py)中的 GETorHEAD_base 方法
            # GETorHEAD_base 中调用 GetOrHeadHandler 类中的 get_working_response 方法
            # get_working_response 方法构建一个 Response 类的实例,并返回。
            # 这个 Response 类的实例就是这里被返回的值。
            return handler(req)
        except HTTPException as error_response:
            return error_response
        except (Exception, Timeout):
            self.logger.exception(_('ERROR Unhandled exception in request'))
            return HTTPServerError(request=req)