Skip to content

Commit

Permalink
Fix tests according changes in Tempesta FW
Browse files Browse the repository at this point in the history
  • Loading branch information
EvgeniiMekhanik committed Sep 13, 2024
1 parent 06644dd commit 5116147
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 37 deletions.
65 changes: 50 additions & 15 deletions cache/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -1751,13 +1751,15 @@ class TestCacheResponseWithCache(tester.TempestaTest):
server ${server_ip}:8000;
cache 2;
cache_methods GET HEAD;
cache_fulfill * *;
tls_match_any_server_name;
vhost default {
proxy_pass default;
tls_certificate ${tempesta_workdir}/tempesta.crt;
tls_certificate_key ${tempesta_workdir}/tempesta.key;
tls_match_any_server_name;
}
""",
}
Expand All @@ -1780,7 +1782,13 @@ def encode_chunked(self, data, chunk_size=256):
result += f"{chunk}\r\n"
return result + "0\r\n\r\n"

def test(self):
@parameterize.expand(
[
param(name="GET", method="GET", trailers_expected=True),
param(name="HEAD", method="HEAD", trailers_expected=False),
]
)
def test(self, name, method, trailers_expected):
self.start_all_services()

srv: StaticDeproxyServer = self.get_server("deproxy")
Expand All @@ -1791,33 +1799,60 @@ def test(self):
+ f"Date: {deproxy.HttpMessage.date_time_string()}\r\n"
+ "Server: Deproxy Server\r\n"
+ "Transfer-Encoding: chunked\r\n"
+ "Trailer: X-Token\r\n\r\n"
+ "Trailer: X-Token1 X-Token2\r\n\r\n"
+ self.encode_chunked(string.ascii_letters, 16)[:-2]
+ f"X-Token: value\r\n\r\n"
+ f"X-Token1: value1\r\n"
+ f"X-Token2: value2\r\n\r\n"
)

client = self.get_client("deproxy")
request = client.create_request(method="GET", headers=[])
client.send_request(request, "200")

if isinstance(self, TestCacheResponseWithCacheH2):
self.assertFalse(client.last_response.headers.get("Trailer"))
self.assertFalse(client.last_response.headers.get("Transfer-Encoding"), "chunked")
else:
self.assertTrue(client.last_response.headers.get("Trailer"), "X-Token1 X-Token2")
self.assertTrue(client.last_response.headers.get("Transfer-Encoding"), "chunked")
self.assertFalse(client.last_response.headers.get("X-Token1"))
self.assertFalse(client.last_response.headers.get("X-Token2"))

self.assertEqual(
# headers for h2 and trailer for http1
client.last_response.headers.get("X-Token")
or client.last_response.trailer.get("X-Token"),
"value",
client.last_response.trailer.get("X-Token1"),
"value1",
"Moved trailer header value mismatch the original one",
)
self.assertEqual(
client.last_response.trailer.get("X-Token2"),
"value2",
"Moved trailer header value mismatch the original one",
)

request = client.create_request(method=method, headers=[])
client.send_request(request, "200")
self.assertIn("age", client.last_response.headers)

self.assertEqual(
# headers for h2 and trailer for http1
client.last_response.headers.get("X-Token")
or client.last_response.trailer.get("X-Token"),
"value",
"Moved trailer header value mismatch the original one",
)
if trailers_expected:
self.assertEqual(
client.last_response.trailer.get("X-Token1"),
"value1",
"Moved trailer header value mismatch the original one",
)
self.assertEqual(
client.last_response.trailer.get("X-Token2"),
"value2",
"Moved trailer header value mismatch the original one",
)

if isinstance(self, TestCacheResponseWithCacheH2):
self.assertFalse(client.last_response.headers.get("Trailer"))
self.assertFalse(client.last_response.headers.get("Transfer-Encoding"), "chunked")
else:
self.assertTrue(client.last_response.headers.get("Trailer"), "X-Token1 X-Token2")
self.assertTrue(client.last_response.headers.get("Transfer-Encoding"), "chunked")
self.assertFalse(client.last_response.headers.get("X-Token1"))
self.assertFalse(client.last_response.headers.get("X-Token2"))


# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
18 changes: 16 additions & 2 deletions encoding/test_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ class TestH2ChunkedWithTrailer(tester.TempestaTest, CommonUtils):

token = "value"
payload = BODY_PAYLOAD
h2 = True

clients = [
{
Expand Down Expand Up @@ -542,9 +543,18 @@ def test(self):
with self.subTest(response_from=from_):
client.send_request(self.request, "200")
response = client.last_response
if self.h2:
self.assertFalse(client.last_response.headers.get("Trailer"))
self.assertFalse(
client.last_response.headers.get("Transfer-Encoding"), "chunked"
)
else:
self.assertTrue(client.last_response.headers.get("Trailer"), "X-Token")
self.assertTrue(
client.last_response.headers.get("Transfer-Encoding"), "chunked"
)
self.assertEqual(
# headers for h2 and trailer for http1
response.headers.get("X-Token") or response.trailer.get("X-Token"),
response.trailer.get("X-Token"),
self.token,
"Moved trailer header value mismatch the original one",
)
Expand All @@ -566,6 +576,8 @@ class TestH1ChunkedWithTrailer(TestH2ChunkedWithTrailer, CommonUtils):
"GET / HTTP/1.1\r\n" "Host: localhost\r\n" "Accept-Encoding: gzip, br, chunked\r\n" "\r\n"
)

h2 = False


class TestH2ChunkedWithLongBodyAndTrailer(TestH2ChunkedWithTrailer):
"""
Expand All @@ -576,11 +588,13 @@ class TestH2ChunkedWithLongBodyAndTrailer(TestH2ChunkedWithTrailer):

payload = 90000 * "x"
token = "a" * 30000
h2 = True


class TestH1ChunkedWithLongBodyAndTrailer(TestH1ChunkedWithTrailer):
payload = 90000 * "x"
token = "a" * 30000
h2 = False


class TestH2ChunkedExtensionRemoved(tester.TempestaTest, CommonUtils):
Expand Down
51 changes: 32 additions & 19 deletions framework/deproxy_auto_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,18 +152,24 @@ def __prepare_expected_response_for_request(
from Tempesta because deproxy server does not know about client protocol and the response
maybe from cache.
"""
chunked_blen = 0
if http2:
expected_response = H2Response.convert_http1_to_http2(self.__expected_response)
else:
expected_response = copy.deepcopy(self.__expected_response)

if "Transfer-Encoding" in expected_response.headers:
# Calculate expected body len (which will used to set content-length)
# for chunked response on HEAD request.
chunked_blen = expected_response.chunked_body_len()

self.__prepare_body_for_HEAD_request(expected_response)

self.__prepare_hop_by_hop_headers(expected_response)

is_cache = "age" in received_response.headers
if http2 or is_cache:
self.__prepare_chunked_expected_response(expected_response, http2)
self.__prepare_chunked_expected_response(expected_response, http2, chunked_blen)

if not http2 or is_cache:
self.__add_content_length_header_to_expected_response(expected_response)
Expand Down Expand Up @@ -202,14 +208,15 @@ def __prepare_hop_by_hop_headers(self, message: HttpMessage) -> None:
message.headers.delete_all("upgrade")

def __prepare_chunked_expected_response(
self, expected_response: Response | H2Response, http2: bool
self, expected_response: Response | H2Response, http2: bool, chunked_blen: int
) -> None:
"""
For http2:
- Tempesta convert Transfer-Encoding header to Content-Encoding
For cache response:
- Tempesta store response with Content-Encoding and Content-length headers
"""
method_is_head = self.__client_request.method == "HEAD"
if "Transfer-Encoding" in expected_response.headers:
dbg(
4,
Expand All @@ -218,27 +225,33 @@ def __prepare_chunked_expected_response(
),
)

te = expected_response.headers.get("Transfer-Encoding")
ce = ",".join(te.split(", ")[:-1])
expected_response.headers.delete_all("Transfer-Encoding")
if ce:
dbg(
4,
self.__dbg_msg.format(
"Response: Transfer-Encoding header convert to Content-Encoding"
),
if http2:
te = expected_response.headers.get("Transfer-Encoding")
ce = ",".join(te.split(", ")[:-1])
expected_response.headers.delete_all("Transfer-Encoding")
if ce:
dbg(
4,
self.__dbg_msg.format(
"Response: Transfer-Encoding header convert to Content-Encoding"
),
)
expected_response.headers.add("content-encoding", ce)
expected_response.convert_chunked_body(
http2, len(expected_response.trailer.headers), method_is_head
)
if http2:
expected_response.headers.add(
"content-length",
str(len(expected_response.body)) if not method_is_head else str(chunked_blen),
)
expected_response.headers.add("content-encoding", ce)
expected_response.convert_chunked_body()
expected_response.headers.add("content-length", str(len(expected_response.body)))

if http2:
return
expected_response.headers.delete_all("Trailer")

for name, value in expected_response.trailer.headers:
dbg(4, self.__dbg_msg.format(f"Response: Trailer '{name}' moved to headers."))
expected_response.trailer.delete_all(name)
expected_response.headers.add(name, value)
if method_is_head:
for name, value in expected_response.trailer.headers:
expected_response.trailer.delete_all(name)

def __add_content_length_header_to_expected_response(
self, expected_response: Response | H2Response
Expand Down
12 changes: 11 additions & 1 deletion helpers/deproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,19 @@ def read_chunked_body(self, stream):
# Parsing trailer will eat last CRLF
self.parse_trailer(stream)

def convert_chunked_body(self):
def convert_chunked_body(self, http2, trailers, method_is_head):
chunked_lines = self.body.split("\r\n")
self.body = "".join(chunked_lines[1::2])
if not http2 and not method_is_head:
result = f"{hex(len(self.body))[2:]}\r\n"
result += f"{self.body}\r\n"
self.body = result + "0\r\n"
if not trailers:
self.body += "\r\n"

def chunked_body_len(self):
chunked_lines = self.body.split("\r\n")
return len("".join(chunked_lines[1::2]))

def read_sized_body(self, stream):
"""RFC 7230. 3.3.3 #5"""
Expand Down
2 changes: 2 additions & 0 deletions http2_general/test_h2_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,8 @@ def test_trailers_in_reponse(self, name, response):

client = self.get_client("deproxy")
client.send_request(self.get_request, "200")
self.assertFalse(client.last_response.headers.get("Trailer"))
self.assertFalse(client.last_response.headers.get("Transfer-Encoding"), "chunked")


class CurlTestBase(tester.TempestaTest):
Expand Down

0 comments on commit 5116147

Please sign in to comment.