Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic tests for new JS challenge behaviour #551

Merged
merged 20 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9b13948
Fix JS tests according changes in Tempesta
EvgeniiMekhanik Dec 1, 2023
71caf84
Enable and fix redirect mark tests.
EvgeniiMekhanik Nov 15, 2023
415f38c
Implement tests for JS pipelined requests
EvgeniiMekhanik Nov 15, 2023
498af60
added negative tests for sticky cookie with `max_misses`
RomanBelozerov Dec 4, 2023
d851a93
reworked JS challenge tests. The main motivation - old tests checked …
RomanBelozerov Dec 5, 2023
60c9f52
added tests to parse the `Cookie` headers.
RomanBelozerov Dec 6, 2023
a3cec66
small fix for js tests:
RomanBelozerov Dec 18, 2023
d126062
Fixes after review
EvgeniiMekhanik Dec 18, 2023
e0d7577
fixed bug when the HTTP/2 request contain duplicate headers.
RomanBelozerov Dec 19, 2023
1b37653
Implement test for multiple cookie headers in http_chain
EvgeniiMekhanik Dec 20, 2023
1f37d8c
added h2 tests for multiple cookie headers in http_chain
RomanBelozerov Dec 20, 2023
b4526ab
Implement test for multiple set-cookie headers in response
EvgeniiMekhanik Dec 20, 2023
36fae45
Fix according changes in Tempesta
EvgeniiMekhanik Dec 21, 2023
d508c8f
Fixes after rebase
EvgeniiMekhanik Apr 9, 2024
c2cc43f
Check servicing non-challengeable resources from cache.
EvgeniiMekhanik Apr 10, 2024
e5c8519
Add tests to check cookie options and js_challenge.
EvgeniiMekhanik Apr 15, 2024
ab9c775
Add tests for method override and expire cookies
EvgeniiMekhanik Apr 16, 2024
8e0b866
Do not increment max misses for non challengeble requests
EvgeniiMekhanik Apr 16, 2024
256ea15
Several fixes after rebase
EvgeniiMekhanik Apr 18, 2024
07556ff
Fix sending pipelined requests
EvgeniiMekhanik May 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion framework/deproxy_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,11 @@ def make_requests(self, requests: list[deproxy.Request | str], pipelined=False)
request if isinstance(request, str) else request.msg for request in requests
]

req_buf_len = len(self.request_buffers)
self._add_to_request_buffers("".join(requests))
self.valid_req_num += len(requests)

self.nrreq += len(self.request_buffers)
self.nrreq += len(self.request_buffers) - req_buf_len
else:
for request in requests:
self.make_request(request)
Expand Down
6 changes: 3 additions & 3 deletions helpers/deproxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,9 +681,9 @@ def create(
request.method = method
request.uri = uri
request.version = version
request.headers = HeaderCollection(
**{header[0]: header[1] for header in pseudo_headers + headers}
)
request.headers = HeaderCollection()
for header in pseudo_headers + headers:
request.headers.add(name=header[0], value=header[1])
request.body = body
request.build_message()

Expand Down
5 changes: 3 additions & 2 deletions helpers/nginx.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ def set_workdir(self, workdir):

def set_resourse_location(self, location=""):
if not location:
location = tf_cfg.cfg.get("Server", "resources")
self.location = "root %s" % location
self.location = "return 200"
else:
self.location = "root %s" % location
self.update_config()

def set_return_code(self, code=200):
Expand Down
2 changes: 1 addition & 1 deletion http2_general/test_h2_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ class TestH2FrameEnabledDisabledTsoGroGsoStickyCookie(
proxy_pass default;
sticky {
sticky_sessions;
cookie enforce;
cookie enforce max_misses=0;
secret "f00)9eR59*_/22";
}
}
Expand Down
156 changes: 123 additions & 33 deletions http2_general/test_h2_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from hyperframe import frame

from framework import tester
from framework.parameterize import param, parameterize
from framework.parameterize import param, parameterize, parameterize_class
from helpers import tf_cfg
from helpers.deproxy import HttpMessage
from http2_general.helpers import H2Base
Expand Down Expand Up @@ -91,6 +91,21 @@
%s
"""

DEPROXY_CLIENT_HTTP = {
"id": "deproxy",
"type": "deproxy",
"addr": "${tempesta_ip}",
"port": "80",
}

DEPROXY_CLIENT_H2 = {
"id": "deproxy",
"type": "deproxy_h2",
"addr": "${tempesta_ip}",
"port": "443",
"ssl": True,
}


class HeadersParsing(H2Base):
def test_small_header_in_request(self):
Expand Down Expand Up @@ -151,6 +166,108 @@ def test_long_header_name_in_response(self):
client.send_request(self.post_request, status_code)


@parameterize_class(
[
{"name": "Http", "clients": [DEPROXY_CLIENT_HTTP]},
{"name": "H2", "clients": [DEPROXY_CLIENT_H2]},
]
)
class CookieParsing(tester.TempestaTest):
cookie = {"name": "cname", "value": "123456789"}

backends = [
{
"id": "deproxy",
"type": "deproxy",
"port": "8000",
"response": "static",
"response_content": "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
}
]

tempesta = {
"config": """
listen 80;
listen 443 proto=h2;

tls_certificate ${tempesta_workdir}/tempesta.crt;
tls_certificate_key ${tempesta_workdir}/tempesta.key;
tls_match_any_server_name;

server ${server_ip}:8000;

block_action attack reply;

sticky {
cookie enforce;
}
"""
}

@parameterize.expand(
[
param(name="single_cookie", cookies="{0}", expected_status_code="200"),
param(
name="many_cookie_first",
cookies="{0}; cookie1=value1; cookie2=value2",
expected_status_code="200",
),
param(
name="many_cookie_last",
cookies="cookie1=value1; cookie2=value2; {0}",
expected_status_code="200",
),
param(
name="many_cookie_between",
cookies="cookie1=value1; {0}; cookie2=value2",
expected_status_code="200",
),
param(name="duplicate_cookie", cookies="{0}; {0}", expected_status_code="500"),
param(
name="many_cookie_and_name_as_substring_other_name_1",
cookies="cookie1__tfw=value1; {0}",
expected_status_code="200",
),
param(
name="many_cookie_and_name_as_substring_other_name_2",
cookies="__tfwcookie1=value1; {0}",
expected_status_code="200",
),
param(
name="many_cookie_and_name_as_substring_other_value_1",
cookies="cookie1=value1__tfw; {0}",
expected_status_code="200",
),
param(
name="many_cookie_and_name_as_substring_other_value_2",
cookies="cookie1=__tfwvalue1; {0}",
expected_status_code="200",
),
]
)
def test(self, name, cookies, expected_status_code):
self.start_all_services()

client = self.get_client("deproxy")

client.send_request(client.create_request("GET", []), "302")
# get a sticky cookie from a response headers
tfw_cookie = client.last_response.headers.get("set-cookie").split("; ")[0].split("=")

sticky_cookie = f"{tfw_cookie[0]}={tfw_cookie[1]}"
for _ in range(2): # first as string and second as bytes from dynamic table
client.send_request(
request=client.create_request(
method="GET",
headers=[("cookie", cookies.format(sticky_cookie))],
),
expected_status_code=expected_status_code,
)
if expected_status_code != "200":
self.assertTrue(client.wait_for_connection_close())
break


class DuplicateSingularHeader(H2Base):
def test_two_header_as_bytes_from_dynamic_table(self):
client = self.get_client("deproxy")
Expand Down Expand Up @@ -1302,12 +1419,7 @@ def __do_test_replacement(self, client, server, content_type, expected_content_t
):
request = client.create_request(
method="POST",
headers=[
(":authority", "localhost"),
(":path", "/"),
(":scheme", "https"),
("content-type", content_type.format(*state)),
],
headers=[("content-type", content_type.format(*state))],
)

client.send_request(request, "200")
Expand All @@ -1322,12 +1434,7 @@ def test_content_length_field_from_hpack_table(self):

request = client.create_request(
method="POST",
headers=[
(":authority", "localhost"),
(":path", "/"),
(":scheme", "https"),
("content-length", "10"),
],
headers=[("content-length", "10")],
body="aaaaaaaaaa",
)

Expand All @@ -1354,12 +1461,7 @@ def test_method_override_from_hpack_table(self):

request = client.create_request(
method="GET",
headers=[
(":authority", "localhost"),
(":path", "/"),
(":scheme", "https"),
("x-http-method-override", "HEAD"),
],
headers=[("x-http-method-override", "HEAD")],
)

tempesta = self.get_tempesta()
Expand All @@ -1381,12 +1483,7 @@ def test_pragma_from_hpack_table(self):

request = client.create_request(
method="GET",
headers=[
(":authority", "localhost"),
(":path", "/"),
(":scheme", "https"),
("pragma", "no-cache"),
],
headers=[("pragma", "no-cache")],
)

tempesta = self.get_tempesta()
Expand All @@ -1397,14 +1494,7 @@ def test_pragma_from_hpack_table(self):
client.send_request(request, "200")
self.assertEqual(2, len(server.requests))

request = client.create_request(
method="GET",
headers=[
(":authority", "localhost"),
(":path", "/"),
(":scheme", "https"),
],
)
request = client.create_request(method="GET", headers=[])

client.send_request(request, "200")
self.assertEqual(3, len(server.requests))
Expand Down
41 changes: 33 additions & 8 deletions selftests/test_deproxy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from h2.exceptions import ProtocolError

from framework import deproxy_client, tester
from framework.parameterize import param, parameterize
from helpers import chains, deproxy, tempesta, tf_cfg
from testers import functional

Expand Down Expand Up @@ -155,6 +156,24 @@ def test_make_request(self):
self.assertTrue(deproxy_cl.wait_for_response(timeout=0.5))
self.assertEqual(deproxy_cl.last_response.status, "200")

def test_duplicate_headers(self):
client = self.get_client("deproxy")
server = self.get_server("deproxy")

self.start_all_services()
client.send_request(
request=client.create_request(
method="GET",
headers=[
("cookie", "name1=value1"),
("cookie", "name2=value2"),
],
),
expected_status_code="200",
)

self.assertEqual(server.last_request.headers.get("cookie"), "name1=value1; name2=value2")

def test_parsing_make_request(self):
self.start_all()

Expand Down Expand Up @@ -367,20 +386,26 @@ def test_many_make_request_2(self):
self.assertEqual(client.last_response.status, "400")
self.assertEqual(len(client.responses), 1)

def test_make_requests(self):
def __send_requests(self, client, request, count, expected_len, pipelined):
client.make_requests([request] * count, pipelined=pipelined)
client.wait_for_response(timeout=3)

self.assertEqual(len(client.responses), expected_len)
for res in client.responses:
self.assertEqual(res.status, "200")

@parameterize.expand(
[param(name="not_pipelined", pipelined=False), param(name="pipelined", pipelined=True)]
)
def test_make_requests(self, name, pipelined):
self.start_all()
client: deproxy_client.DeproxyClient = self.get_client("deproxy")
client.parsing = True

request = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"

messages = 5
client.make_requests([request] * messages)
client.wait_for_response(timeout=3)

self.assertEqual(len(client.responses), messages)
for res in client.responses:
self.assertEqual(res.status, "200")
self.__send_requests(client, request, 3, 3, pipelined)
self.__send_requests(client, request, 3, 6, pipelined)

def test_parsing_make_requests(self):
self.start_all()
Expand Down
Loading