Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 7ef8be4

Browse files
author
bweigel
committed
adds cloudfront event for Lambda@Edge
1 parent af822bd commit 7ef8be4

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

lawip/cf_event.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from collections import namedtuple
2+
from typing import Dict
3+
4+
HeaderDict = namedtuple("HeaderDict", ['key', 'value'])
5+
6+
7+
def parse_headers(headers):
8+
return {hdr_name: HeaderDict(header[0].get("key", None),
9+
header[0].get("value", None)) for hdr_name, header in headers.items()}
10+
11+
12+
class CfConfig:
13+
def __init__(self, distribution_id: str, request_id: str):
14+
self._distribution_id = distribution_id
15+
self._request_id = request_id
16+
17+
@classmethod
18+
def from_json(cls, config):
19+
return cls(config["distributionId"],
20+
config["requestId"])
21+
22+
@property
23+
def distribution_id(self) -> str:
24+
return self._distribution_id
25+
26+
@property
27+
def request_id(self) -> str:
28+
return self._request_id
29+
30+
31+
class CfRequest:
32+
def __init__(self, client_ip: str,
33+
querystring: str,
34+
uri: str,
35+
method: str,
36+
headers: Dict[str, HeaderDict],
37+
origin):
38+
self._client_ip = client_ip
39+
self._querystring = querystring
40+
self._uri = uri
41+
self._http_method = method
42+
self._headers = headers
43+
self._origin = origin
44+
45+
@classmethod
46+
def from_json(cls, request):
47+
return cls(request["clientIp"],
48+
request["querystring"],
49+
request["uri"],
50+
request["method"],
51+
parse_headers(request["headers"]),
52+
request.get("origin", None))
53+
54+
@property
55+
def client_ip(self) -> str:
56+
return self._client_ip
57+
58+
@property
59+
def querystring(self) -> str:
60+
return self._querystring
61+
62+
@property
63+
def uri(self) -> str:
64+
return self._uri
65+
66+
@property
67+
def http_method(self) -> str:
68+
return self._http_method
69+
70+
@property
71+
def headers(self) -> Dict[str, HeaderDict]:
72+
return self._headers
73+
74+
@property
75+
def origin(self):
76+
return self._origin
77+
78+
79+
class CfResponse:
80+
def __init__(self, status: str, status_description: str, headers: Dict[str, HeaderDict]):
81+
self._status = status
82+
self._status_description = status_description
83+
self._headers = headers
84+
85+
@classmethod
86+
def from_json(cls, response):
87+
if response is not None:
88+
return cls(response["status"],
89+
response["statusDescription"],
90+
parse_headers(response["headers"]))
91+
92+
@property
93+
def status(self) -> str:
94+
return self._status
95+
96+
@property
97+
def status_description(self) -> str:
98+
return self._status_description
99+
100+
@property
101+
def headers(self) -> Dict[str, HeaderDict]:
102+
return self._headers
103+
104+
105+
class CfRecord:
106+
def __init__(self, config: CfConfig,
107+
request: CfRequest,
108+
response: CfResponse):
109+
self._config = config
110+
self._request = request
111+
self._response = response
112+
113+
@classmethod
114+
def from_json(cls, cf):
115+
return cls(CfConfig.from_json(cf["config"]),
116+
CfRequest.from_json(cf["request"]),
117+
CfResponse.from_json(cf.get("response", None)))
118+
119+
@property
120+
def config(self) -> CfConfig:
121+
return self._config
122+
123+
@property
124+
def request(self) -> CfRequest:
125+
return self._request
126+
127+
@property
128+
def response(self) -> CfResponse:
129+
return self._response
130+
131+
132+
class CloudfrontEvent:
133+
def __init__(self, records: [CfRecord]):
134+
self._records = records
135+
136+
@classmethod
137+
def from_event(cls, event):
138+
return cls([CfRecord.from_json(record["cf"]) for record in event["Records"]])
139+
140+
@property
141+
def records(self) -> [CfRecord]:
142+
return self._records
143+
144+
@property
145+
def first_record(self) -> CfRecord:
146+
return self._records[0]

lawip/test/test_cf_event.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from unittest2 import TestCase
2+
3+
from lawip.cf_event import CloudfrontEvent
4+
from lawip.http_proxy_event import ApiGwProxyEvent
5+
6+
from lawip.test.util import get_event_dict
7+
8+
9+
class TestProxyEvent(TestCase):
10+
def setUp(self):
11+
request_event_dict = get_event_dict("cf_request_event.json")
12+
response_event_dict = get_event_dict("cf_response_event.json")
13+
self.req_event = CloudfrontEvent.from_event(request_event_dict).first_record
14+
self.resp_event = CloudfrontEvent.from_event(response_event_dict).first_record
15+
16+
def test_request(self):
17+
evt = self.req_event
18+
self.assertEqual(evt.config.request_id, "MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE==")
19+
self.assertIsNone(evt.response)
20+
self.assertEqual(evt.request.querystring, "size=large")
21+
22+
def test_response(self):
23+
evt = self.resp_event
24+
self.assertEqual(evt.config.request_id, "xGN7KWpVEmB9Dp7ctcVFQC4E-nrcOcEKS3QyAez--06dV7TEXAMPLE==")
25+
self.assertEqual(evt.response.status, "200")
26+
self.assertEqual(evt.request.client_ip, "2001:0db8:85a3:0:0:8a2e:0370:7334")

0 commit comments

Comments
 (0)