Skip to content

Commit 48970f1

Browse files
rdallmandenismakogon
authored andcommitted
fix gateway headers / headers casing (#88)
the http library we're using automatically lower cases headers, and we weren't properly handling different cases when encapsulating certain headers such as content type and the gateway headers. this changes most of the headers to be turned into lower case to check them and lower cases them going out of the response in order to test them as well. over the wire itself, fn via the go http library will end up turning these into the canonical header casing, but for consistency in python this seems ideal. there are tests to ensure these are checked properly in various cases now. closes #87
1 parent 1ccd6bd commit 48970f1

6 files changed

Lines changed: 36 additions & 24 deletions

File tree

fdk/constants.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,32 @@
1616

1717
ASYNC_IO_READ_BUFFER = 65536
1818
DEFAULT_DEADLINE = 30
19+
1920
HTTPSTREAM = "http-stream"
2021
INTENT_HTTP_REQUEST = "httprequest"
22+
23+
# env vars
2124
FN_FORMAT = "FN_FORMAT"
2225
FN_LISTENER = "FN_LISTENER"
23-
FN_INTENT = "Fn-Intent"
24-
FN_HTTP_PREFIX = "Fn-Http-H-"
25-
FN_HTTP_STATUS = "Fn-Http-Status"
26+
FN_APP_ID = "FN_APP_ID"
27+
FN_ID = "FN_FN_ID"
28+
FN_LOGFRAME_NAME = "FN_LOGFRAME_NAME"
29+
FN_LOGFRAME_HDR = "FN_LOGFRAME_HDR"
30+
31+
# headers are lower case TODO(denis): why?
32+
FN_INTENT = "fn-intent"
33+
FN_HTTP_PREFIX = "fn-http-h-"
34+
FN_HTTP_STATUS = "fn-http-status"
2635
FN_DEADLINE = "fn-deadline"
27-
FN_FDK_VERSION = "Fn-Fdk-Version"
36+
FN_FDK_VERSION = "fn-fdk-version"
2837
FN_HTTP_REQUEST_URL = "fn-http-request-url"
2938
FN_CALL_ID = "fn-call-id"
3039
FN_HTTP_METHOD = "fn-http-method"
31-
FN_APP_ID = "FN_APP_ID"
32-
FN_ID = "FN_FN_ID"
33-
CONTENT_TYPE = "Content-Type"
34-
CONTENT_LENGTH = "Content-Length"
40+
CONTENT_TYPE = "content-type"
41+
CONTENT_LENGTH = "content-length"
42+
3543
FN_ENFORCED_RESPONSE_CODES = [200, 502, 504]
3644
FN_DEFAULT_RESPONSE_CODE = 200
37-
FN_LOGFRAME_NAME = "FN_LOGFRAME_NAME"
38-
FN_LOGFRAME_HDR = "FN_LOGFRAME_HDR"
3945

4046

4147
# todo: python 3.8 is on its way, make more flexible

fdk/context.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from fdk import constants
2020
from fdk import headers as hs
21+
from fdk import log
2122

2223

2324
class InvokeContext(object):
@@ -63,6 +64,8 @@ def __init__(self, app_id, fn_id, call_id,
6364
self.__response_headers = {}
6465
self.__fn_format = fn_format
6566

67+
log.log("request headers. gateway: {0} {1}"
68+
.format(self.__is_gateway(), headers))
6669
if self.__is_gateway():
6770
self.__headers = hs.decap_headers(self.__headers)
6871

@@ -92,11 +95,12 @@ def Deadline(self):
9295
return self.__deadline
9396

9497
def SetResponseHeaders(self, headers, status_code):
98+
log.log("setting headers. gateway: {0}".format(self.__is_gateway()))
9599
if self.__is_gateway():
96100
headers = hs.encap_headers(headers, status=status_code)
97101

98102
for k, v in headers.items():
99-
self.__response_headers[k] = v
103+
self.__response_headers[k.lower()] = v
100104

101105
def GetResponseHeaders(self):
102106
return self.__response_headers

fdk/headers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def decap_headers(hdsr):
1919
ctx_headers = {}
2020
if hdsr is not None:
2121
for k, v in hdsr.items():
22+
k = k.lower()
2223
if k.startswith(constants.FN_HTTP_PREFIX):
2324
ctx_headers[k.lstrip(constants.FN_HTTP_PREFIX)] = v
2425
else:
@@ -30,6 +31,7 @@ def encap_headers(headers, status=None):
3031
new_headers = {}
3132
if headers is not None:
3233
for k, v in headers.items():
34+
k = k.lower()
3335
if (k == constants.CONTENT_TYPE or
3436
k == constants.FN_FDK_VERSION or
3537
k.startswith(constants.FN_HTTP_PREFIX)):

fdk/runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,6 @@ async def handle_request(handler_code, format_def, **kwargs):
101101
headers=headers, status_code=200)
102102

103103
except (Exception, TimeoutError) as ex:
104-
log.log("exception appeared")
104+
log.log("exception appeared: {0}".format(ex))
105105
traceback.print_exc(file=sys.stderr)
106-
return errors.DispatchException(ctx, 502, str(ex), ).response()
106+
return errors.DispatchException(ctx, 502, str(ex)).response()

fdk/tests/funcs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,15 @@ async def coro(ctx, **kwargs):
9292
def valid_xml(ctx, **kwargs):
9393
return response.Response(
9494
ctx, response_data=xml, headers={
95-
"Content-Type": "application/xml",
95+
"content-type": "application/xml",
9696
}
9797
)
9898

9999

100100
def invalid_xml(ctx, **kwargs):
101101
return response.Response(
102102
ctx, response_data=json.dumps(xml), headers={
103-
"Content-Type": "application/xml",
103+
"content-type": "application/xml",
104104
}
105105
)
106106

fdk/tests/test_http_stream.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async def test_override_content_type():
3232

3333
assert 200 == status
3434
assert "OK" == content
35-
assert "application/json" in headers.get("Content-Type")
35+
assert "application/json" in headers.get("content-type")
3636
assert version.VERSION == headers.get(constants.FN_FDK_VERSION)
3737

3838

@@ -74,8 +74,8 @@ async def test_encap_headers_gw():
7474
call = await fixtures.setup_fn_call(
7575
funcs.encaped_header,
7676
headers={
77-
"Custom-Header-Maybe": "yo",
78-
"Content-Type": "application/yo"
77+
"custom-header-maybe": "yo",
78+
"content-type": "application/yo"
7979
},
8080
gateway=True,
8181
)
@@ -84,25 +84,25 @@ async def test_encap_headers_gw():
8484
# make sure that content type is not encaped, and custom header is
8585
# when coming out of the fdk
8686
assert 200 == status
87-
assert "application/yo" in headers.get("Content-Type")
88-
assert "yo" in headers.get("Fn-Http-H-Custom-Header-Maybe")
87+
assert "application/yo" in headers.get("content-type")
88+
assert "yo" in headers.get("fn-http-h-custom-header-maybe")
8989

9090

9191
@pytest.mark.asyncio
9292
async def test_encap_headers():
9393
call = await fixtures.setup_fn_call(
9494
funcs.encaped_header,
9595
headers={
96-
"Custom-Header-Maybe": "yo",
97-
"Content-Type": "application/yo"
96+
"custom-header-maybe": "yo",
97+
"content-type": "application/yo"
9898
}
9999
)
100100
content, status, headers = await call
101101

102102
# make sure that custom header is not encaped out of fdk
103103
assert 200 == status
104-
assert "application/yo" in headers.get("Content-Type")
105-
assert "yo" in headers.get("Custom-Header-Maybe")
104+
assert "application/yo" in headers.get("content-type")
105+
assert "yo" in headers.get("custom-header-maybe")
106106

107107

108108
@pytest.mark.asyncio

0 commit comments

Comments
 (0)