Skip to content

Commit 16f91f3

Browse files
committed
chore(tests): add e2e tests for the new cookies
1 parent ca127ad commit 16f91f3

File tree

7 files changed

+199
-75
lines changed

7 files changed

+199
-75
lines changed

aws_lambda_powertools/shared/cookies.py

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55

66

77
class SameSite(Enum):
8+
"""
9+
SameSite allows a server to define a cookie attribute making it impossible for
10+
the browser to send this cookie along with cross-site requests. The main
11+
goal is to mitigate the risk of cross-origin information leakage, and provide
12+
some protection against cross-site request forgery attacks.
13+
14+
See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
15+
"""
16+
817
DEFAULT_MODE = ""
918
LAX_MODE = "Lax"
1019
STRICT_MODE = "Strict"
@@ -16,26 +25,58 @@ def _format_date(timestamp: datetime) -> str:
1625

1726

1827
class Cookie:
28+
"""
29+
A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
30+
HTTP response or the Cookie header of an HTTP request.
31+
32+
See https://tools.ietf.org/html/rfc6265 for details.
33+
"""
34+
1935
def __init__(
2036
self,
2137
name: str,
2238
value: str,
23-
path: Optional[str] = None,
24-
domain: Optional[str] = None,
39+
path: str = "",
40+
domain: str = "",
41+
secure: bool = True,
42+
http_only: bool = False,
2543
expires: Optional[datetime] = None,
2644
max_age: Optional[int] = None,
27-
secure: Optional[bool] = None,
28-
http_only: Optional[bool] = None,
2945
same_site: Optional[SameSite] = None,
3046
custom_attributes: Optional[List[str]] = None,
3147
):
48+
"""
49+
50+
Parameters
51+
----------
52+
name: str
53+
The name of this cookie, for example session_id
54+
value: str
55+
The cookie value, for instance an uuid
56+
path: str
57+
The path for which this cookie is valid. Optional
58+
domain: str
59+
The domain for which this cookie is valid. Optional
60+
secure: bool
61+
Marks the cookie as secure, only sendable to the server with an encrypted request over the HTTPS protocol
62+
http_only: bool
63+
Enabling this attribute makes the cookie inaccessible to the JavaScript `Document.cookie` API
64+
expires: Optional[datetime]
65+
Defines a date where the permanent cookie expires.
66+
max_age: Optional[int]
67+
Defines the period of time after which the cookie is invalid. Use negative values to force cookie deletion.
68+
same_site: Optional[SameSite]
69+
Determines if the cookie should be sent to third party websites
70+
custom_attributes: Optional[List[str]]
71+
List of additional custom attributes to set on the cookie
72+
"""
3273
self.name = name
3374
self.value = value
3475
self.path = path
3576
self.domain = domain
77+
self.secure = secure
3678
self.expires = expires
3779
self.max_age = max_age
38-
self.secure = secure
3980
self.http_only = http_only
4081
self.same_site = same_site
4182
self.custom_attributes = custom_attributes
@@ -44,10 +85,10 @@ def __str__(self) -> str:
4485
payload = StringIO()
4586
payload.write(f"{self.name}={self.value}")
4687

47-
if self.path and len(self.path) > 0:
88+
if self.path:
4889
payload.write(f"; Path={self.path}")
4990

50-
if self.domain and len(self.domain) > 0:
91+
if self.domain:
5192
payload.write(f"; Domain={self.domain}")
5293

5394
if self.expires:
@@ -56,7 +97,8 @@ def __str__(self) -> str:
5697
if self.max_age:
5798
if self.max_age > 0:
5899
payload.write(f"; MaxAge={self.max_age}")
59-
if self.max_age < 0:
100+
else:
101+
# negative or zero max-age should be set to 0
60102
payload.write("; MaxAge=0")
61103

62104
if self.http_only:

tests/e2e/event_handler/handlers/alb_handler.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
1-
from typing import Dict
2-
31
from aws_lambda_powertools.event_handler import ALBResolver, Response, content_types
42

53
app = ALBResolver()
64

75

86
@app.post("/todos")
97
def hello():
10-
payload: Dict = app.current_event.json_body
8+
payload = app.current_event.json_body
9+
10+
body = payload.get("body", "Hello World")
11+
status_code = payload.get("status_code", 200)
12+
headers = payload.get("headers", {})
13+
cookies = payload.get("cookies", [])
14+
content_type = headers.get("Content-Type", content_types.TEXT_PLAIN)
1115

1216
return Response(
13-
status_code=200,
14-
content_type=content_types.TEXT_PLAIN,
15-
body="Hello world",
16-
cookies=payload["cookies"],
17-
headers=payload["headers"],
17+
status_code=status_code,
18+
content_type=content_type,
19+
body=body,
20+
cookies=cookies,
21+
headers=headers,
1822
)
1923

2024

tests/e2e/event_handler/handlers/api_gateway_http_handler.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,22 @@
33
app = APIGatewayHttpResolver()
44

55

6-
@app.get("/todos")
6+
@app.post("/todos")
77
def hello():
8+
payload = app.current_event.json_body
9+
10+
body = payload.get("body", "Hello World")
11+
status_code = payload.get("status_code", 200)
12+
headers = payload.get("headers", {})
13+
cookies = payload.get("cookies", [])
14+
content_type = headers.get("Content-Type", content_types.TEXT_PLAIN)
15+
816
return Response(
9-
status_code=200,
10-
content_type=content_types.TEXT_PLAIN,
11-
body="Hello world",
12-
cookies=["CookieMonster", "MonsterCookie"],
13-
headers={"Foo": ["bar", "zbr"]},
17+
status_code=status_code,
18+
content_type=content_type,
19+
body=body,
20+
cookies=cookies,
21+
headers=headers,
1422
)
1523

1624

tests/e2e/event_handler/handlers/api_gateway_rest_handler.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,22 @@
33
app = APIGatewayRestResolver()
44

55

6-
@app.get("/todos")
6+
@app.post("/todos")
77
def hello():
8+
payload = app.current_event.json_body
9+
10+
body = payload.get("body", "Hello World")
11+
status_code = payload.get("status_code", 200)
12+
headers = payload.get("headers", {})
13+
cookies = payload.get("cookies", [])
14+
content_type = headers.get("Content-Type", content_types.TEXT_PLAIN)
15+
816
return Response(
9-
status_code=200,
10-
content_type=content_types.TEXT_PLAIN,
11-
body="Hello world",
12-
cookies=["CookieMonster", "MonsterCookie"],
13-
headers={"Foo": ["bar", "zbr"]},
17+
status_code=status_code,
18+
content_type=content_type,
19+
body=body,
20+
cookies=cookies,
21+
headers=headers,
1422
)
1523

1624

tests/e2e/event_handler/handlers/lambda_function_url_handler.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ def hello():
1111
status_code = payload.get("status_code", 200)
1212
headers = payload.get("headers", {})
1313
cookies = payload.get("cookies", [])
14+
content_type = headers.get("Content-Type", content_types.TEXT_PLAIN)
1415

1516
return Response(
1617
status_code=status_code,
17-
content_type=headers.get("Content-Type", content_types.TEXT_PLAIN),
18+
content_type=content_type,
1819
body=body,
1920
cookies=cookies,
2021
headers=headers,

tests/e2e/event_handler/infrastructure.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def _create_api_gateway_http(self, function: Function):
6161
apigw = apigwv2.HttpApi(self.stack, "APIGatewayHTTP", create_default_stage=True)
6262
apigw.add_routes(
6363
path="/todos",
64-
methods=[apigwv2.HttpMethod.GET],
64+
methods=[apigwv2.HttpMethod.POST],
6565
integration=apigwv2integrations.HttpLambdaIntegration("TodosIntegration", function),
6666
)
6767

@@ -71,7 +71,7 @@ def _create_api_gateway_rest(self, function: Function):
7171
apigw = apigwv1.RestApi(self.stack, "APIGatewayRest", deploy_options=apigwv1.StageOptions(stage_name="dev"))
7272

7373
todos = apigw.root.add_resource("todos")
74-
todos.add_method("GET", apigwv1.LambdaIntegration(function, proxy=True))
74+
todos.add_method("POST", apigwv1.LambdaIntegration(function, proxy=True))
7575

7676
CfnOutput(self.stack, "APIGatewayRestUrl", value=apigw.url)
7777

0 commit comments

Comments
 (0)