def to_invocation_context( request: Request, url_params: Dict[str, Any] = None) -> ApiInvocationContext: """ Converts an HTTP Request object into an ApiInvocationContext. :param request: the original request :param url_params: the parameters extracted from the URL matching rules :return: the ApiInvocationContext """ method = request.method path = request.full_path if request.query_string else request.path data = restore_payload(request) headers = Headers(request.headers) # adjust the X-Forwarded-For header x_forwarded_for = headers.getlist("X-Forwarded-For") x_forwarded_for.append(request.remote_addr) x_forwarded_for.append(request.host) headers["X-Forwarded-For"] = ", ".join(x_forwarded_for) # set the x-localstack-edge header, it is used to parse the domain headers[HEADER_LOCALSTACK_EDGE_URL] = request.host_url.strip("/") # FIXME: Use the already parsed url params instead of parsing them into the ApiInvocationContext part-by-part. # We already would have all params at hand to avoid _all_ the parsing, but the parsing # has side-effects (f.e. setting the region in a thread local)! # It would be best to use a small (immutable) context for the already parsed params and the Request object # and use it everywhere. return ApiInvocationContext(method, path, data, headers, stage=url_params.get("stage"))
def test_headers(): # simple header tests headers = Headers() headers.add('Content-Type', 'text/plain') headers.add('X-Foo', 'bar') assert 'x-Foo' in headers assert 'Content-type' in headers headers['Content-Type'] = 'foo/bar' assert headers['Content-Type'] == 'foo/bar' assert len(headers.getlist('Content-Type')) == 1 # list conversion assert headers.to_list() == [ ('Content-Type', 'foo/bar'), ('X-Foo', 'bar') ] assert str(headers) == ( "Content-Type: foo/bar\r\n" "X-Foo: bar\r\n" "\r\n") assert str(Headers()) == "\r\n" # extended add headers.add('Content-Disposition', 'attachment', filename='foo') assert headers['Content-Disposition'] == 'attachment; filename=foo' headers.add('x', 'y', z='"') assert headers['x'] == r'y; z="\""' # defaults headers = Headers([ ('Content-Type', 'text/plain'), ('X-Foo', 'bar'), ('X-Bar', '1'), ('X-Bar', '2') ]) assert headers.getlist('x-bar') == ['1', '2'] assert headers.get('x-Bar') == '1' assert headers.get('Content-Type') == 'text/plain' assert headers.setdefault('X-Foo', 'nope') == 'bar' assert headers.setdefault('X-Bar', 'nope') == '1' assert headers.setdefault('X-Baz', 'quux') == 'quux' assert headers.setdefault('X-Baz', 'nope') == 'quux' headers.pop('X-Baz') # type conversion assert headers.get('x-bar', type=int) == 1 assert headers.getlist('x-bar', type=int) == [1, 2] # list like operations assert headers[0] == ('Content-Type', 'text/plain') assert headers[:1] == Headers([('Content-Type', 'text/plain')]) del headers[:2] del headers[-1] assert headers == Headers([('X-Bar', '1')]) # copying a = Headers([('foo', 'bar')]) b = a.copy() a.add('foo', 'baz') assert a.getlist('foo') == ['bar', 'baz'] assert b.getlist('foo') == ['bar'] headers = Headers([('a', 1)]) assert headers.pop('a') == 1 assert headers.pop('b', 2) == 2 assert_raises(KeyError, headers.pop, 'c') # set replaces and accepts same arguments as add a = Headers() a.set('Content-Disposition', 'useless') a.set('Content-Disposition', 'attachment', filename='foo') assert a['Content-Disposition'] == 'attachment; filename=foo'
def test_headers(): # simple header tests headers = Headers() headers.add("Content-Type", "text/plain") headers.add("X-Foo", "bar") assert "x-Foo" in headers assert "Content-type" in headers headers["Content-Type"] = "foo/bar" assert headers["Content-Type"] == "foo/bar" assert len(headers.getlist("Content-Type")) == 1 # list conversion assert headers.to_list() == [("Content-Type", "foo/bar"), ("X-Foo", "bar")] assert str(headers) == ("Content-Type: foo/bar\r\n" "X-Foo: bar\r\n" "\r\n") assert str(Headers()) == "\r\n" # extended add headers.add("Content-Disposition", "attachment", filename="foo") assert headers["Content-Disposition"] == "attachment; filename=foo" headers.add("x", "y", z='"') assert headers["x"] == r'y; z="\""' # defaults headers = Headers([("Content-Type", "text/plain"), ("X-Foo", "bar"), ("X-Bar", "1"), ("X-Bar", "2")]) assert headers.getlist("x-bar") == ["1", "2"] assert headers.get("x-Bar") == "1" assert headers.get("Content-Type") == "text/plain" assert headers.setdefault("X-Foo", "nope") == "bar" assert headers.setdefault("X-Bar", "nope") == "1" assert headers.setdefault("X-Baz", "quux") == "quux" assert headers.setdefault("X-Baz", "nope") == "quux" headers.pop("X-Baz") # type conversion assert headers.get("x-bar", type=int) == 1 assert headers.getlist("x-bar", type=int) == [1, 2] # list like operations assert headers[0] == ("Content-Type", "text/plain") assert headers[:1] == Headers([("Content-Type", "text/plain")]) del headers[:2] del headers[-1] assert headers == Headers([("X-Bar", "1")]) # copying a = Headers([("foo", "bar")]) b = a.copy() a.add("foo", "baz") assert a.getlist("foo") == ["bar", "baz"] assert b.getlist("foo") == ["bar"] headers = Headers([("a", 1)]) assert headers.pop("a") == 1 assert headers.pop("b", 2) == 2 assert_raises(KeyError, headers.pop, "c") # set replaces and accepts same arguments as add a = Headers() a.set("Content-Disposition", "useless") a.set("Content-Disposition", "attachment", filename="foo") assert a["Content-Disposition"] == "attachment; filename=foo"
def test_headers(): # simple header tests headers = Headers() headers.add('Content-Type', 'text/plain') headers.add('X-Foo', 'bar') assert 'x-Foo' in headers assert 'Content-type' in headers headers['Content-Type'] = 'foo/bar' assert headers['Content-Type'] == 'foo/bar' assert len(headers.getlist('Content-Type')) == 1 # list conversion assert headers.to_list() == [('Content-Type', 'foo/bar'), ('X-Foo', 'bar')] assert str(headers) == ("Content-Type: foo/bar\r\n" "X-Foo: bar\r\n" "\r\n") assert str(Headers()) == "\r\n" # extended add headers.add('Content-Disposition', 'attachment', filename='foo') assert headers['Content-Disposition'] == 'attachment; filename=foo' headers.add('x', 'y', z='"') assert headers['x'] == r'y; z="\""' # defaults headers = Headers([('Content-Type', 'text/plain'), ('X-Foo', 'bar'), ('X-Bar', '1'), ('X-Bar', '2')]) assert headers.getlist('x-bar') == ['1', '2'] assert headers.get('x-Bar') == '1' assert headers.get('Content-Type') == 'text/plain' assert headers.setdefault('X-Foo', 'nope') == 'bar' assert headers.setdefault('X-Bar', 'nope') == '1' assert headers.setdefault('X-Baz', 'quux') == 'quux' assert headers.setdefault('X-Baz', 'nope') == 'quux' headers.pop('X-Baz') # type conversion assert headers.get('x-bar', type=int) == 1 assert headers.getlist('x-bar', type=int) == [1, 2] # list like operations assert headers[0] == ('Content-Type', 'text/plain') assert headers[:1] == Headers([('Content-Type', 'text/plain')]) del headers[:2] del headers[-1] assert headers == Headers([('X-Bar', '1')]) # copying a = Headers([('foo', 'bar')]) b = a.copy() a.add('foo', 'baz') assert a.getlist('foo') == ['bar', 'baz'] assert b.getlist('foo') == ['bar'] headers = Headers([('a', 1)]) assert headers.pop('a') == 1 assert headers.pop('b', 2) == 2 assert_raises(KeyError, headers.pop, 'c') # set replaces and accepts same arguments as add a = Headers() a.set('Content-Disposition', 'useless') a.set('Content-Disposition', 'attachment', filename='foo') assert a['Content-Disposition'] == 'attachment; filename=foo'