예제 #1
0
 def __call__(self, chain: HandlerChain, context: RequestContext,
              response: Response):
     try:
         router_response = self.router.dispatch(context.request)
         response.update_from(router_response)
         chain.stop()
     except NotFound:
         if self.respond_not_found:
             chain.respond(404)
예제 #2
0
    def on_post(self, request: Request):
        data = request.get_json(True, True)
        if not data:
            return Response("invalid request", 400)

        # backdoor API to support restarting the instance
        if data.get("action") in ["kill", "restart"]:
            terminate_all_processes_in_docker()
            SHUTDOWN_INFRA.set()

        return Response("ok", 200)
예제 #3
0
 def __call__(self, chain: HandlerChain, context: RequestContext,
              response: Response):
     try:
         # serve
         response.update_from(self.resources.dispatch(context.request))
         chain.stop()
     except NotFound:
         path = context.request.path
         if path.startswith(constants.INTERNAL_RESOURCE_PATH + "/"):
             # only return 404 if we're accessing an internal resource, otherwise fall back to the other handlers
             LOG.warning("Unable to find resource handler for path: %s",
                         path)
             chain.respond(404)
예제 #4
0
    def __call__(
        self,
        chain: HandlerChain,
        exception: Exception,
        context: RequestContext,
        response: Response,
    ):
        if not context.service:
            return

        error = self.create_exception_response(exception, context)
        if error:
            response.update_from(error)
예제 #5
0
    def __call__(self, environ: "WSGIEnvironment",
                 start_response: "StartResponse") -> Iterable[bytes]:
        # create request from environment
        LOG.debug(
            "[%s] %s %s%s",
            threading.current_thread().name,
            environ["REQUEST_METHOD"],
            environ.get("HTTP_HOST"),
            environ["RAW_URI"],
        )
        request = Request(environ)
        if "asgi.headers" in environ:
            # restores raw headers from ASGI scope, which allows dashes in header keys
            # see https://github.com/pallets/werkzeug/issues/940
            request.headers = Headers(environ["asgi.headers"].raw_items())
        else:
            # by default, werkzeug requests from environ are immutable
            request.headers = Headers(request.headers)

        # prepare response
        response = Response()

        self.gateway.process(request, response)

        return response(environ, start_response)
예제 #6
0
    def on_get(self, request):
        from localstack.utils.aws.aws_stack import get_valid_regions

        deploy_html_file = os.path.join(constants.MODULE_MAIN_PATH, "services",
                                        "cloudformation", "deploy.html")
        deploy_html = load_file(deploy_html_file)
        req_params = request.values
        params = {
            "stackName": "stack1",
            "templateBody": "{}",
            "errorMessage": "''",
            "regions": json.dumps(sorted(list(get_valid_regions()))),
        }

        download_url = req_params.get("templateURL")
        if download_url:
            try:
                LOG.debug(
                    "Attempting to download CloudFormation template URL: %s",
                    download_url)
                template_body = requests.get(download_url).text
                template_body = parse_json_or_yaml(template_body)
                params["templateBody"] = json.dumps(template_body)
            except Exception as e:
                msg = f"Unable to download CloudFormation template URL: {e}"
                LOG.info(msg)
                params["errorMessage"] = json.dumps(msg.replace("\n", " - "))

        # using simple string replacement here, for simplicity (could be replaced with, e.g., jinja)
        for key, value in params.items():
            deploy_html = deploy_html.replace(f"<{key}>", value)

        return Response(deploy_html, mimetype="text/html")
예제 #7
0
    def test_composite_handler_stops_handler_chain(self):
        def inner1(_chain: HandlerChain, request: RequestContext,
                   response: Response):
            _chain.stop()

        inner2 = mock.MagicMock()
        outer1 = mock.MagicMock()
        outer2 = mock.MagicMock()
        response1 = mock.MagicMock()

        chain = HandlerChain()

        composite = CompositeHandler()
        composite.handlers.append(inner1)
        composite.handlers.append(inner2)

        chain.request_handlers.append(outer1)
        chain.request_handlers.append(composite)
        chain.request_handlers.append(outer2)
        chain.response_handlers.append(response1)

        chain.handle(RequestContext(), Response())
        outer1.assert_called_once()
        outer2.assert_not_called()
        inner2.assert_not_called()
        response1.assert_called_once()
예제 #8
0
    def test_composite_handler_exception_calls_outer_exception_handlers(self):
        def inner1(_chain: HandlerChain, request: RequestContext,
                   response: Response):
            raise ValueError()

        inner2 = mock.MagicMock()
        outer1 = mock.MagicMock()
        outer2 = mock.MagicMock()
        exception_handler = mock.MagicMock()
        response1 = mock.MagicMock()

        chain = HandlerChain()

        composite = CompositeHandler()
        composite.handlers.append(inner1)
        composite.handlers.append(inner2)

        chain.request_handlers.append(outer1)
        chain.request_handlers.append(composite)
        chain.request_handlers.append(outer2)
        chain.exception_handlers.append(exception_handler)
        chain.response_handlers.append(response1)

        chain.handle(RequestContext(), Response())
        outer1.assert_called_once()
        outer2.assert_not_called()
        inner2.assert_not_called()
        exception_handler.assert_called_once()
        response1.assert_called_once()
예제 #9
0
 def invoke_rest_api(self, request: Request,
                     **url_params: Dict[str, Any]) -> Response:
     if not url_params["api_id"] in API_REGIONS:
         return Response(status=404)
     invocation_context = to_invocation_context(request, url_params)
     result = invoke_rest_api_from_request(invocation_context)
     if result is not None:
         return convert_response(result)
     raise NotFound()
예제 #10
0
    def __call__(self, chain: HandlerChain, context: RequestContext,
                 response: Response):
        if not context.service:
            return

        service_name = context.service.service_name
        operation_name = context.operation.name

        key = ServiceOperation(service_name, operation_name)

        handler = self.handlers.get(key)
        if not handler:
            error = self.create_not_implemented_response(context)
            response.update_from(error)
            chain.stop()
            return

        handler(chain, context, response)
예제 #11
0
    def __call__(
        self,
        chain: HandlerChain,
        exception: Exception,
        context: RequestContext,
        response: Response,
    ):
        if response.data:
            # response already set
            return

        LOG.debug("setting internal failure response for %s", exception)
        response.status_code = 500
        response.set_json(
            {
                "message": "Unexpected exception",
                "error": str(exception),
                "type": str(exception.__class__.__name__),
            }
        )
예제 #12
0
 def __call__(self, chain: HandlerChain, context: RequestContext,
              response: Response) -> None:
     if (not config.DISABLE_CORS_CHECKS
             and self.should_enforce_self_managed_service(context)
             and not self.is_cors_origin_allowed(context.request.headers)):
         LOG.info(
             "Blocked CORS request from forbidden origin %s",
             context.request.headers.get("origin")
             or context.request.headers.get("referer"),
         )
         response.status_code = 403
         chain.terminate()
예제 #13
0
 def return_response(self, method: str, path: str, data: MessagePayload,
                     headers: Headers,
                     response: Response) -> Optional[Response]:
     if headers.get("Accept") == APPLICATION_JSON:
         try:
             if response._content or b"".startswith(b"<"):
                 content = xmltodict.parse(to_str(response._content))
                 stripped_content = strip_xmlns(content)
                 response._content = stripped_content
         except Exception as e:
             LOG.debug("Unable to convert XML response to JSON", exc_info=e)
     return super().return_response(method, path, data, headers, response)
예제 #14
0
def convert_response(result: RequestsResponse) -> Response:
    """
    Utility function to convert a response for the requests library to our internal (Werkzeug based) Response object.
    """
    if result is None:
        return Response()

    if isinstance(result, LambdaResponse):
        headers = Headers(dict(result.headers))
        for k, values in result.multi_value_headers.items():
            for value in values:
                headers.add(k, value)
    else:
        headers = dict(result.headers)

    response = Response(status=result.status_code, headers=headers)

    if isinstance(result.content, dict):
        response.set_json(result.content)
    elif isinstance(result.content, (str, bytes)):
        response.data = result.content
    else:
        raise ValueError(f"Unhandled content type {type(result.content)}")

    return response
예제 #15
0
    def __call__(self, chain: HandlerChain, context: RequestContext,
                 response: Response):
        request = context.request

        # a werkzeug Request consumes form/multipart data from the socket stream, so we need to restore the payload here
        data = restore_payload(request)

        # TODO: rethink whether this proxy handling is necessary
        context.request.headers[
            HEADER_LOCALSTACK_REQUEST_URL] = context.request.base_url

        result = self.forward_request(
            context,
            method=request.method,
            path=request.full_path if request.query_string else request.path,
            data=data,
            headers=request.headers,
        )

        if type(result) == int:
            chain.respond(status_code=result)
            return

        if isinstance(result, tuple):
            # special case for Kinesis SubscribeToShard
            if len(result) == 2:
                response.status_code = 200
                response.set_response(result[0])
                response.headers.update(dict(result[1]))
                chain.stop()
                return

        if isinstance(result, RequestsResponse):
            response.status_code = result.status_code
            response.set_response(result.content)
            # make sure headers are set after the content, so potential content-length headers are overwritten
            response.headers.update(dict(result.headers))

            # make sure content-length is re-calculated correctly, unless it's a HEAD request
            if request.method != "HEAD":
                length = response.calculate_content_length()
                if length is not None:
                    response.headers["Content-Length"] = str(length)
            chain.stop()
            return

        raise ValueError("cannot create response for result %s" % result)
예제 #16
0
def handle_request(request: Request, region: str) -> Response:
    if request.is_json:
        # TODO: the response should be sent as JSON response
        raise NotImplementedError

    try:
        response, operation = try_call_sqs(request, region)
        del response["ResponseMetadata"]
        return serializer.serialize_to_response(response, operation)
    except UnknownOperationException:
        return Response("<UnknownOperationException/>", 404)
    except CommonServiceException as e:
        # use a dummy operation for the serialization to work
        op = service.operation_model(service.operation_names[0])
        return serializer.serialize_error_to_response(e, op)
    except Exception as e:
        LOG.exception("exception")
        op = service.operation_model(service.operation_names[0])
        return serializer.serialize_error_to_response(
            CommonServiceException(
                "InternalError", f"An internal error ocurred: {e}", status_code=500
            ),
            op,
        )
예제 #17
0
    def test_composite_handler_continues_handler_chain(self):
        inner1 = mock.MagicMock()
        inner2 = mock.MagicMock()
        outer1 = mock.MagicMock()
        outer2 = mock.MagicMock()
        response1 = mock.MagicMock()

        chain = HandlerChain()

        composite = CompositeHandler()
        composite.handlers.append(inner1)
        composite.handlers.append(inner2)

        chain.request_handlers.append(outer1)
        chain.request_handlers.append(composite)
        chain.request_handlers.append(outer2)
        chain.response_handlers.append(response1)

        chain.handle(RequestContext(), Response())
        outer1.assert_called_once()
        outer2.assert_called_once()
        inner1.assert_called_once()
        inner2.assert_called_once()
        response1.assert_called_once()
예제 #18
0
 def __call__(self, request: Request, endpoint: E,
              args: RequestArguments) -> Response:
     self.requests.append((request, endpoint, args))
     return Response()
예제 #19
0
 def handler(_request: Request, arg1) -> Response:  # invalid signature
     return Response("ok")
예제 #20
0
 def handler_bar(_request: Request, bar, baz) -> Dict[str, any]:
     response = Response()
     response.set_json({"bar": bar, "baz": baz})
     return response
예제 #21
0
 def handler_foo(_request: Request) -> Response:
     return Response("ok")
예제 #22
0
 def on_get(self, req, resp: Response):
     resp.set_json({"message": "GET/OK"})
예제 #23
0
 def ep_index2(_: Request, args) -> Response:
     response = Response()
     response.set_json(dict(method="2", **args))
     return response
예제 #24
0
 def ep_all(_: Request, args) -> Response:
     response = Response()
     response.set_json(dict(method="all", **args))
     return response
예제 #25
0
 def users(_: Request, args) -> Response:
     response = Response()
     response.set_json(args)
     return response
예제 #26
0
 def users(_: Request, args) -> Response:
     return Response(b"users")
예제 #27
0
 def index(_: Request, args) -> Response:
     return Response(b"index")
예제 #28
0
 def echo_json(request: Request, args) -> Response:
     response = Response()
     response.set_json(request.json)
     return response
예제 #29
0
 def __call__(self, chain: HandlerChain, context: RequestContext,
              response: Response):
     skeleton_response = self.skeleton.invoke(context)
     response.update_from(skeleton_response)
예제 #30
0
 def index(_: Request, args) -> Response:
     response = Response()
     response.set_json(args)
     return response