Exemplo n.º 1
0
    def __call__(self, environ, start_response):
        request = Request(environ)

        if not request.headers.get(REQUEST_ID_HEADER, None):
            req_id = str(uuid.uuid4())
            request.headers[REQUEST_ID_HEADER] = req_id

        def custom_start_response(status, headers, exc_info=None):
            headers = ResponseHeaders(headers)

            req_id_header = request.headers.get(REQUEST_ID_HEADER, None)
            if req_id_header:
                headers[REQUEST_ID_HEADER] = req_id_header

            return start_response(status, headers._items, exc_info)

        return self.app(environ, custom_start_response)
Exemplo n.º 2
0
    def __call__(self, environ, start_response):
        request = Request(environ)

        def custom_start_response(status, headers, exc_info=None):
            headers = ResponseHeaders(headers)

            origin = request.headers.get('Origin')
            origins = set(cfg.CONF.api.allow_origin)

            # Build a list of the default allowed origins
            public_api_url = cfg.CONF.auth.api_url

            # Default gulp development server WebUI URL
            origins.add('http://127.0.0.1:3000')

            # By default WebUI simple http server listens on 8080
            origins.add('http://localhost:8080')
            origins.add('http://127.0.0.1:8080')

            if public_api_url:
                # Public API URL
                origins.add(public_api_url)

            if origin:
                if '*' in origins:
                    origin_allowed = '*'
                else:
                    # See http://www.w3.org/TR/cors/#access-control-allow-origin-response-header
                    origin_allowed = origin if origin in origins else 'null'
            else:
                origin_allowed = list(origins)[0]

            methods_allowed = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
            request_headers_allowed = [
                'Content-Type', 'Authorization', HEADER_ATTRIBUTE_NAME,
                HEADER_API_KEY_ATTRIBUTE_NAME, REQUEST_ID_HEADER
            ]
            response_headers_allowed = [
                'Content-Type', 'X-Limit', 'X-Total-Count', REQUEST_ID_HEADER
            ]

            headers['Access-Control-Allow-Origin'] = origin_allowed
            headers['Access-Control-Allow-Methods'] = ','.join(methods_allowed)
            headers['Access-Control-Allow-Headers'] = ','.join(
                request_headers_allowed)
            headers['Access-Control-Expose-Headers'] = ','.join(
                response_headers_allowed)

            return start_response(status, headers._items, exc_info)

        try:
            return self.app(environ, custom_start_response)
        except NotFoundException:
            if request.method != 'options':
                raise

            return Response()(environ, custom_start_response)
Exemplo n.º 3
0
    def __call__(self, environ, start_response):
        # The middleware sets a number of headers that helps prevent a range of attacks in browser
        # environment. It also handles OPTIONS requests used by browser as pre-flight check before
        # the potentially insecure request is made. An absence of this headers on the response will
        # prevent the error from ever reaching the JS layer of client-side code making it impossible
        # to process the response or provide a human-friendly error message. Order is not important
        # as long at this condition is met and headers not get overridden by another middleware
        # higher up the call stack.
        request = Request(environ)

        def custom_start_response(status, headers, exc_info=None):
            headers = ResponseHeaders(headers)

            origin = request.headers.get('Origin')
            origins = set(cfg.CONF.api.allow_origin)

            # Build a list of the default allowed origins
            public_api_url = cfg.CONF.auth.api_url

            # Default gulp development server WebUI URL
            origins.add('http://127.0.0.1:3000')

            # By default WebUI simple http server listens on 8080
            origins.add('http://localhost:8080')
            origins.add('http://127.0.0.1:8080')

            if public_api_url:
                # Public API URL
                origins.add(public_api_url)

            if origin:
                if '*' in origins:
                    origin_allowed = '*'
                else:
                    # See http://www.w3.org/TR/cors/#access-control-allow-origin-response-header
                    origin_allowed = origin if origin in origins else 'null'
            else:
                origin_allowed = list(origins)[0]

            methods_allowed = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
            request_headers_allowed = ['Content-Type', 'Authorization', HEADER_ATTRIBUTE_NAME,
                                       HEADER_API_KEY_ATTRIBUTE_NAME, REQUEST_ID_HEADER]
            response_headers_allowed = ['Content-Type', 'X-Limit', 'X-Total-Count',
                                        REQUEST_ID_HEADER]

            headers['Access-Control-Allow-Origin'] = origin_allowed
            headers['Access-Control-Allow-Methods'] = ','.join(methods_allowed)
            headers['Access-Control-Allow-Headers'] = ','.join(request_headers_allowed)
            headers['Access-Control-Expose-Headers'] = ','.join(response_headers_allowed)

            return start_response(status, headers._items, exc_info)

        if request.method == 'OPTIONS':
            return Response()(environ, custom_start_response)
        else:
            return self.app(environ, custom_start_response)
Exemplo n.º 4
0
    def __call__(self, environ, start_response):
        # The middleware adds unique `X-Request-ID` header on the requests that don't have it and
        # modifies the responses to have the same exact header as their request. The middleware
        # helps us better track relation between request and response in places where it might not
        # be immediately obvious (like logs for example). In general, you want to place this header
        # as soon as possible to ensure it's present by the time it's needed. Certainly before
        # LoggingMiddleware which relies on this header.
        request = Request(environ)

        if not request.headers.get(REQUEST_ID_HEADER, None):
            req_id = str(uuid.uuid4())
            request.headers[REQUEST_ID_HEADER] = req_id

        def custom_start_response(status, headers, exc_info=None):
            headers = ResponseHeaders(headers)

            req_id_header = request.headers.get(REQUEST_ID_HEADER, None)
            if req_id_header:
                headers[REQUEST_ID_HEADER] = req_id_header

            return start_response(status, headers._items, exc_info)

        return self.app(environ, custom_start_response)
Exemplo n.º 5
0
    def __call__(self, environ, start_response):
        start_time = clock()
        status_code = []
        content_length = []

        request = Request(environ)

        query_params = request.GET.dict_of_lists()

        # Mask secret / sensitive query params
        secret_query_params = SECRET_QUERY_PARAMS + cfg.CONF.log.mask_secrets_blacklist
        for param_name in secret_query_params:
            if param_name in query_params:
                query_params[param_name] = MASKED_ATTRIBUTE_VALUE

        # Log the incoming request
        values = {
            'method': request.method,
            'path': request.path,
            'remote_addr': request.remote_addr,
            'query': query_params,
            'request_id': request.headers.get(REQUEST_ID_HEADER, None)
        }

        LOG.info('%(request_id)s - %(method)s %(path)s with query=%(query)s' %
                 values,
                 extra=values)

        def custom_start_response(status, headers, exc_info=None):
            status_code.append(int(status.split(' ')[0]))

            for name, value in headers:
                if name.lower() == 'content-length':
                    content_length.append(int(value))
                    break

            return start_response(status, headers, exc_info)

        retval = self.app(environ, custom_start_response)

        try:
            endpoint, path_vars = self.router.match(request)
        except NotFoundException:
            endpoint = {}

        log_result = endpoint.get('x-log-result', True)

        if isinstance(retval, (types.GeneratorType, itertools.chain)):
            # Note: We don't log the result when return value is a generator, because this would
            # result in calling str() on the generator and as such, exhausting it
            content_length = [float('inf')]
            log_result = False

        # Log the response
        values = {
            'method':
            request.method,
            'path':
            request.path,
            'remote_addr':
            request.remote_addr,
            'status':
            status_code[0],
            'runtime':
            float("{0:.3f}".format((clock() - start_time) * 10**3)),
            'content_length':
            content_length[0] if content_length else len(b''.join(retval)),
            'request_id':
            request.headers.get(REQUEST_ID_HEADER, None)
        }

        log_msg = '%(request_id)s - %(status)s %(content_length)s %(runtime)sms' % (
            values)
        LOG.info(log_msg, extra=values)

        if log_result:
            values['result'] = retval[0]
            log_msg = (
                '%(request_id)s - %(status)s %(content_length)s %(runtime)sms\n%(result)s'
                % (values))
            LOG.debug(log_msg, extra=values)

        return retval
Exemplo n.º 6
0
    def __call__(self, environ, start_response):
        start_time = clock()
        status_code = []
        content_length = []

        request = Request(environ)

        # Log the incoming request
        values = {
            'method': request.method,
            'path': request.path,
            'remote_addr': request.remote_addr,
            'query': request.GET.dict_of_lists(),
            'request_id': request.headers.get(REQUEST_ID_HEADER, None)
        }

        LOG.info('%(request_id)s - %(method)s %(path)s with query=%(query)s' %
                 values, extra=values)

        def custom_start_response(status, headers, exc_info=None):
            status_code.append(int(status.split(' ')[0]))

            for name, value in headers:
                if name.lower() == 'content-length':
                    content_length.append(int(value))
                    break

            return start_response(status, headers, exc_info)

        retval = self.app(environ, custom_start_response)

        try:
            endpoint, path_vars = self.router.match(request)
        except NotFoundException:
            endpoint = {}

        log_result = endpoint.get('x-log-result', True)

        if isinstance(retval, types.GeneratorType):
            content_length = [float('inf')]
            log_result = False

        # Log the incoming request
        values = {
            'method': request.method,
            'path': request.path,
            'remote_addr': request.remote_addr,
            'status': status_code[0],
            'runtime': float("{0:.3f}".format((clock() - start_time) * 10**3)),
            'content_length': content_length[0] if content_length else len(b''.join(retval)),
            'request_id': request.headers.get(REQUEST_ID_HEADER, None)
        }

        if log_result:
            values['result'] = retval[0]
            log_msg = '%(request_id)s - %(status)s %(content_length)s %(runtime)sms\n%(result)s'\
                      % values
        else:
            log_msg = '%(request_id)s - %(status)s %(content_length)s %(runtime)sms' % values

        LOG.info(log_msg, extra=values)

        return retval