Beispiel #1
0
 def __init__(self, version, address):
     super(RyuClientBase, self).__init__()
     self.version = version
     res = urllib_parse.SplitResult('', address, '', '', '')
     self.host = res.hostname
     self.port = res.port
     self.url_prefix = '/' + self.version + '/'
    def on_message(self, message):
        try:
            contents = json.loads(message)
        except ValueError:
            self.log.debug('Bad JSON: %r', message)
            self.log.error('Couldn\'t parse JSON', exc_info=True)
            self._write_error(status=400, msg='JSON input is required.')
            return

        if not set(contents.keys()).issuperset(self._REQUIRED_KEYS):
            msg = (
                'Invalid request. The body must contain the following keys: '
                '{required}. Got: {got}').format(required=self._REQUIRED_KEYS,
                                                 got=contents.keys())
            self._write_error(status=400, msg=msg)
            return

        method = str(contents['method']).upper()
        query = ''
        if method in self._REQUIRE_XSRF_FORWARDING_METHODS:
            xsrf = self.get_cookie('_xsrf')
            if xsrf:
                query += '_xsrf={}'.format(xsrf)

        body = contents.get('body')
        if method in self._REQUIRE_NO_BODY_METHODS and body is not None:
            msg = (
                'Invalid request: Body may not be specified for method "{}".'
            ).format(method)
            self._write_error(status=400, msg=msg)
            return

        path = urlparse.urlunsplit(
            urlparse.SplitResult(scheme=self.request.protocol,
                                 netloc=self.request.host,
                                 path=contents['path'],
                                 query=query,
                                 fragment=''))

        emitter = _StreamingResponseEmitter(contents['message_id'],
                                            self.write_message)
        proxy_request = httpclient.HTTPRequest(
            url=path,
            method=method,
            headers=self.request.headers,
            body=contents.get('body'),
            ca_certs=self.ca_certs,
            header_callback=emitter.header_callback,
            streaming_callback=emitter.streaming_callback)
        _modify_proxy_request_test_only(proxy_request)

        http_client = self._get_http_client()
        # Since this channel represents a proxy, don't raise errors directly and
        # instead send them back in the response.
        # The response contents will normally be captured by
        # _StreamingResponseEmitter. However, if a programming error occurs with how
        # the proxy is set up, these callbacks will not be used.
        response = yield http_client.fetch(proxy_request, raise_error=False)
        if response.error and not isinstance(response.error,
                                             httpclient.HTTPError):
            with stack_context.ExceptionStackContext(self._log_fetch_error):
                # Rethrow the exception to capture the stack trace and write
                # an error message.
                response.rethrow()
            self._write_error(
                status=500,
                msg=('Uncaught server-side exception. Check logs for '
                     'additional details.'))
            return

        emitter.done()
    def on_message(self, message):
        try:
            contents = json.loads(message)
        except ValueError:
            self.log.debug('Bad JSON: %r', message)
            self.log.error("Couldn't parse JSON", exc_info=True)
            self._write_error(status=400, msg='JSON input is required.')
            raise gen.Return()

        if not set(contents.keys()).issuperset(self._REQUIRED_KEYS):
            msg = (
                'Invalid request. The body must contain the following keys: '
                '{required}. Got: {got}').format(required=self._REQUIRED_KEYS,
                                                 got=contents.keys())
            self._write_error(status=400,
                              msg=msg,
                              message_id=contents.get('message_id'))
            raise gen.Return()

        message_id = contents['message_id']
        try:
            yield self._attach_auth_cookies()
        except Exception:  # pylint:disable=broad-except
            self.log.error("Couldn't attach auth cookies")
            self._on_unhandled_exception(message_id)
            raise gen.Return()

        method = str(contents['method']).upper()
        query = ''
        if method in self._REQUIRE_XSRF_FORWARDING_METHODS:
            xsrf = self._get_xsrf_cookie()
            if xsrf:
                query += '_xsrf={}'.format(xsrf)

        path = urlparse.urlunsplit(  # pylint:disable=too-many-function-args
            urlparse.SplitResult(scheme=self.request.protocol,
                                 netloc=self.request.host,
                                 path=contents['path'],
                                 query=query,
                                 fragment=''))

        body = None
        if contents.get('body_base64'):
            body = base64.b64decode(
                contents.get('body_base64')).decode('utf-8')
        else:
            body = contents.get('body')

        emitter = _StreamingResponseEmitter(message_id, self.write_message)
        proxy_request = httpclient.HTTPRequest(
            url=path,
            method=method,
            headers=self.request.headers,
            body=body,
            ca_certs=self.ca_certs,
            header_callback=emitter.header_callback,
            streaming_callback=emitter.streaming_callback,
            allow_nonstandard_methods=True)
        _modify_proxy_request_test_only(proxy_request)

        http_client = self._get_http_client()
        # Since this channel represents a proxy, don't raise errors directly and
        # instead send them back in the response.
        # The response contents will normally be captured by
        # _StreamingResponseEmitter. However, if a programming error occurs with how
        # the proxy is set up, these callbacks will not be used.
        response = yield http_client.fetch(proxy_request, raise_error=False)
        if response.error and not isinstance(response.error,
                                             httpclient.HTTPError):
            try:
                response.rethrow()
            except Exception:  # pylint:disable=broad-except
                # Rethrow the exception to capture the stack trace and write
                # an error message.
                self.log.exception('Uncaught error when proxying request')

            self._on_unhandled_exception(message_id)
            raise gen.Return()

        emitter.done()