Skip to content

Commit

Permalink
updated frang tests for http_host_required.
Browse files Browse the repository at this point in the history
added h2 and http1 tests for parse host from headers and uri.
added h2 and http1 tests for host with http_rules
  • Loading branch information
RomanBelozerov committed May 2, 2023
1 parent 5095a7e commit 714d298
Show file tree
Hide file tree
Showing 6 changed files with 440 additions and 26 deletions.
99 changes: 99 additions & 0 deletions http2_general/test_h2_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,105 @@ def test_request_with_some_data(self):
self.assertIn(response_header, client.last_response.headers.headers)


class TestH2Host(H2Base):
def test_host_missing(self):
self.start_all_services()
client = self.get_client("deproxy")
client.parsing = False

client.send_request(
request=[
(":path", "/"),
(":scheme", "https"),
(":method", "GET"),
],
expected_status_code="400",
)

def test_empty_authority_header(self):
self.start_all_services()
client = self.get_client("deproxy")
client.parsing = False

client.send_request(
request=[(":path", "/"), (":scheme", "https"), (":method", "GET"), (":authority", "")],
expected_status_code="400",
)

def test_empty_host_header(self):
self.start_all_services()
client = self.get_client("deproxy")
client.parsing = False

client.send_request(
request=[(":path", "/"), (":scheme", "https"), (":method", "GET"), ("host", "")],
expected_status_code="400",
)

def test_host_authority_ok(self):
self.start_all_services()
client = self.get_client("deproxy")
client.parsing = False

client.send_request(
request=[
(":path", "/"),
(":scheme", "https"),
(":method", "GET"),
(":authority", "localhost"),
],
expected_status_code="200",
)

def test_host_header_ok(self):
self.start_all_services()
client = self.get_client("deproxy")
client.parsing = False

client.send_request(
request=[
(":path", "/"),
(":scheme", "https"),
(":method", "GET"),
("host", "localhost"),
],
expected_status_code="200",
)

def test_different_host_and_authority_headers(self):
self.start_all_services()
client = self.get_client("deproxy")
client.parsing = False

client.send_request(
request=[
(":path", "/"),
(":scheme", "https"),
(":method", "GET"),
(":authority", "deproxy"),
("host", "localhost"),
],
expected_status_code="200",
)

def test_forwarded_and_empty_host_header(self):
"""Host header must be present. Forwarded header does not set host header."""
self.start_all_services()
client = self.get_client("deproxy")
client.parsing = False

client.send_request(
request=[
(":path", "/"),
(":scheme", "https"),
(":method", "GET"),
("host", ""),
("forwarded", "host=localhost"),
],
expected_status_code="400",
)


class CurlTestBase(tester.TempestaTest):
clients = [
{
Expand Down
95 changes: 93 additions & 2 deletions http_general/test_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@


class BackendSetCoookie(tester.TempestaTest):

backends = [
{
"id": "set-cookie-1",
Expand Down Expand Up @@ -107,7 +106,6 @@ def test_request_success(self):


class RepeatedHeaderCache(tester.TempestaTest):

backends = [
{
"id": "headers",
Expand Down Expand Up @@ -200,3 +198,96 @@ def test_small_header_name_accepted(self):
self.assertTrue(client.wait_for_response(timeout=1))
self.assertEqual(client.last_response.status, "200")
client.stop()


class TestHost(tester.TempestaTest):
backends = [
{
"id": "deproxy",
"type": "deproxy",
"port": "8000",
"response": "static",
"response_content": (
"HTTP/1.1 200 OK\r\n"
+ "Date: test\r\n"
+ "Server: debian\r\n"
+ "Content-Length: 0\r\n\r\n"
),
}
]

tempesta = {
"config": """
listen 80;
server ${server_ip}:8000;
block_action attack reply;
block_action error reply;
"""
}

clients = [
{
"id": "deproxy",
"type": "deproxy",
"addr": "${tempesta_ip}",
"port": "80",
},
]

def test_host_missing(self):
self.start_all_services()
client = self.get_client("deproxy")

client.send_request(
request=f"GET / HTTP/1.1\r\n\r\n",
expected_status_code="400",
)

def test_host_header_empty(self):
self.start_all_services()
client = self.get_client("deproxy")

client.send_request(
request=f"GET / HTTP/1.1\r\nHost:\r\n\r\n",
expected_status_code="400",
)

def test_host_header_ok(self):
self.start_all_services()
client = self.get_client("deproxy")

client.send_request(
request=f"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n",
expected_status_code="200",
)

def test_host_in_uri_without_host_header(self):
self.start_all_services()
client = self.get_client("deproxy")

client.send_request(
request=f"GET http://[email protected]/ HTTP/1.1\r\n\r\n",
expected_status_code="400",
)

def test_different_host_in_uri_and_headers(self):
self.start_all_services()
client = self.get_client("deproxy")

client.send_request(
request=f"GET http://[email protected]/ HTTP/1.1\r\nHost: localhost\r\n\r\n",
expected_status_code="200",
)

def test_forwarded_and_empty_host_header(self):
"""Host header must be present. Forwarded header does not set host header."""
self.start_all_services()
client = self.get_client("deproxy")

client.send_request(
request=(
f"GET http://[email protected]/ HTTP/1.1\r\nForwarded: host=localhost\r\n\r\n"
),
expected_status_code="400",
)
28 changes: 16 additions & 12 deletions t_frang/test_host_required.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
__license__ = "GPL2"

WARN_UNKNOWN = "frang: Request authority is unknown"
WARN_DIFFER = "frang: Request authority in URI differs from host header"
WARN_DIFFER = "frang: Request host from absolute URI differs from Host header for"
WARN_IP_ADDR = "frang: Host header field contains IP address"
WARN_HEADER_FORWARDED = "Request authority in URI differs from forwarded"
WARN_HEADER_FORWARDED2 = "frang: Request authority differs from forwarded"
WARN_HEADER_FORWARDED = "frang: Request authority differs from forwarded for"
WARN_HEADER_HOST = "frang: Request :authority differs from Host for"
WARN_INVALID_AUTHORITY = "Invalid authority"


class FrangHostRequiredTestCase(FrangTestCase):
Expand Down Expand Up @@ -42,14 +43,14 @@ def test_empty_host_header(self):
client = self.base_scenario(
frang_config="http_host_required true;", requests=["GET / HTTP/1.1\r\nHost: \r\n\r\n"]
)
self.check_response(client, status_code="403", warning_msg=WARN_UNKNOWN)
self.check_response(client, status_code="400", warning_msg=WARN_INVALID_AUTHORITY)

def test_host_header_missing(self):
"""Test with missing header `host`."""
client = self.base_scenario(
frang_config="http_host_required true;", requests=["GET / HTTP/1.1\r\n\r\n"]
)
self.check_response(client, status_code="403", warning_msg=WARN_UNKNOWN)
self.check_response(client, status_code="400", warning_msg=WARN_INVALID_AUTHORITY)

def test_host_header_with_old_proto(self):
"""
Expand Down Expand Up @@ -87,7 +88,7 @@ def test_host_header_mismatch_empty(self):
frang_config="http_host_required true;",
requests=["GET http://[email protected]/ HTTP/1.1\r\nHost: \r\n\r\n"],
)
self.check_response(client, status_code="403", warning_msg=WARN_UNKNOWN)
self.check_response(client, status_code="403", warning_msg=WARN_DIFFER)

def test_host_header_forwarded(self):
"""Test with invalid host in `Forwarded` header."""
Expand Down Expand Up @@ -179,7 +180,8 @@ def test_host_header_as_ip6(self):
def test_disabled_host_http_required(self):
"""Test disable `http_host_required`."""
client = self.base_scenario(
frang_config="http_host_required false;", requests=["GET / HTTP/1.1\r\n\r\n"]
frang_config="http_host_required false;",
requests=["GET http://[email protected]/ HTTP/1.1\r\nHost: example.com\r\n\r\n"],
)
self.check_response(client, status_code="200", warning_msg="frang: ")

Expand Down Expand Up @@ -291,7 +293,8 @@ def test_h2_host_and_authority_headers_missing(self):
headers=[
(":path", "/"),
],
expected_warning="frang: Request authority is unknown for",
expected_warning=WARN_INVALID_AUTHORITY,
status_code="400",
)

def test_h2_host_header_as_ip(self):
Expand Down Expand Up @@ -338,7 +341,7 @@ def test_h2_missmatch_forwarded_header(self):
"""Test with missmath header `forwarded`."""
self._test(
headers=[(":path", "/"), (":authority", "localhost"), ("forwarded", "host=qwerty")],
expected_warning=WARN_HEADER_FORWARDED2,
expected_warning=WARN_HEADER_FORWARDED,
)

def test_h2_double_different_forwarded_headers(self):
Expand All @@ -350,19 +353,20 @@ def test_h2_double_different_forwarded_headers(self):
("forwarded", "host=tempesta.com"),
("forwarded", "host=tempesta-tech.com"),
],
expected_warning=WARN_HEADER_FORWARDED2,
expected_warning=WARN_HEADER_FORWARDED,
)

def test_h2_different_host_and_authority_header(self):
self._test(
headers=[(":path", "/"), (":authority", "localhost"), ("host", "host")],
expected_warning="frang: Request authority differs between headers for",
expected_warning=WARN_HEADER_HOST,
)

def _test(
self,
headers: list,
expected_warning: str = WARN_UNKNOWN,
status_code: str = "403",
):
"""
Test base scenario for process different requests.
Expand All @@ -374,7 +378,7 @@ def _test(
head.extend(headers)

client = self.base_scenario(frang_config="http_host_required true;", requests=[head])
self.check_response(client, status_code="403", warning_msg=expected_warning)
self.check_response(client, status_code=status_code, warning_msg=expected_warning)

def test_disabled_host_http_required(self):
client = self.base_scenario(
Expand Down
Loading

0 comments on commit 714d298

Please sign in to comment.