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

tests for the content-length and content-type headers with an empty b… #769

Merged
merged 7 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
184 changes: 184 additions & 0 deletions http2_general/test_h2_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
analises its return code.
"""

import string

from h2.errors import ErrorCodes
from hpack import HeaderTuple
from hyperframe import frame
Expand Down Expand Up @@ -1418,3 +1420,185 @@ def test_not_blocked_by_max_headers_count(self, name, huffman):

deproxy_cl.wait_for_response(strict=True)
self.assertEqual(deproxy_cl.last_response.status, "200")


class CustomTemplate(string.Template):
delimiter = "&"


@marks.parameterize_class(
[
{"name": "MethodHEAD", "method": "HEAD", "statuses": [200]},
{"name": "MethodGET", "method": "GET", "statuses": [200, 302, 304, 400, 401, 404, 500]},
{
"name": "MethodPOST",
"method": "POST",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
{
"name": "MethodDELETE",
"method": "DELETE",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
{
"name": "MethodPATCH",
"method": "PATCH",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
{
"name": "MethodPUT",
"method": "PUT",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
]
)
class TestNoContentLengthInMethod(tester.TempestaTest):
backends = [
{
"id": "deproxy",
"type": "deproxy",
"port": "8000",
}
]

tempesta = {
"config": """
listen 443 proto=https,h2;
access_log dmesg;

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

frang_limits {http_methods OPTIONS HEAD GET PUT POST PUT PATCH DELETE;}
server ${server_ip}:8000;
"""
}

clients = [
{
"id": "deproxy",
"type": "deproxy_h2",
"addr": "${tempesta_ip}",
"port": "443",
"ssl": True,
},
]
method: str = None
statuses: list[int] = None

@property
def statuses_description(self) -> dict[int, str]:
return {
200: "OK",
201: "Created",
302: "Found",
304: "Not Modified",
400: "Bad Request",
401: "Unauthorized",
403: "Forbidden",
404: "Not Found",
500: "Internal Server Error",
}

def test_request_success(self):
self.start_all_services()
self.disable_deproxy_auto_parser()

server = self.get_server("deproxy")
client = self.get_client("deproxy")
client.start()

for status in self.statuses:
with self.subTest(status=status):
server.set_response(
f"HTTP/1.1 {status} {self.statuses_description[status]}\r\n"
"Server: debian\r\n"
"Content-Length: 0\r\n\r\n\r\n"
)
client.send_request(
request=client.create_request(method=self.method, headers=[]),
expected_status_code=str(status),
)

self.assertEqual(
client.last_response.headers["content-length"],
"0",
msg=f"Tempesta should proxy the Content-Length header for the "
f"`{self.method} {status} {self.statuses_description[status]}` status code also",
)


@marks.parameterize_class(
[
{
"name": "POST",
"method": "POST",
},
{
"name": "PUT",
"method": "PUT",
},
{
"name": "PATCH",
"method": "PATCH",
},
{
"name": "DELETE",
"method": "DELETE",
},
]
)
class TestContentTypeWithEmptyBody(tester.TempestaTest):
backends = [
{
"id": "deproxy",
"type": "deproxy",
"port": "8000",
"response": "static",
"response_content": (
"HTTP/1.1 200 OK\r\n"
"Server: debian\r\n"
"Content-Length: 0\r\n"
"Content-Type: text/html; charset=utf-8\r\n\r\n\r\n"
),
}
]

tempesta = {
"config": """
listen 443 proto=https,h2;
access_log dmesg;

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

frang_limits {http_methods OPTIONS HEAD GET PUT POST PUT PATCH DELETE;}
server ${server_ip}:8000;
"""
}

clients = [
{
"id": "deproxy",
"type": "deproxy_h2",
"addr": "${tempesta_ip}",
"port": "443",
"ssl": True,
},
]
method: str = None

def test_request_success(self):
self.start_all_services()
client = self.get_client("deproxy")
client.send_request(
request=client.create_request(method=self.method, headers=[]),
expected_status_code="200",
)
self.assertEqual(
client.last_response.headers["content-type"],
"text/html; charset=utf-8",
msg="Tempesta should proxy the Content-Type header for the CRUD method with empty body also",
)
187 changes: 186 additions & 1 deletion http_general/test_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
Tests for correct handling of HTTP/1.1 headers.
"""

from helpers import deproxy, dmesg
import string

from helpers import deproxy
from test_suite import marks, tester

__author__ = "Tempesta Technologies, Inc."
Expand Down Expand Up @@ -592,3 +594,186 @@ def test_different_host_in_uri_and_headers(self, name, request, expected_status_
expected_status_code=expected_status_code,
)
self.assertIn("age", client.last_response.headers)


class CustomTemplate(string.Template):
delimiter = "&"


@marks.parameterize_class(
[
{"name": "MethodHEAD", "method": "HEAD", "statuses": [200]},
{"name": "MethodGET", "method": "GET", "statuses": [200, 302, 304, 400, 401, 404, 500]},
{
"name": "MethodPOST",
"method": "POST",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
{
"name": "MethodDELETE",
"method": "DELETE",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
{
"name": "MethodPATCH",
"method": "PATCH",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
{
"name": "MethodPUT",
"method": "PUT",
"statuses": [200, 201, 302, 304, 400, 401, 404, 500],
},
]
)
class TestNoContentLengthInMethod(tester.TempestaTest):
backends = [
{
"id": "deproxy",
"type": "deproxy",
"port": "8000",
}
]

tempesta = {
"config": """
listen 443 proto=https;
access_log dmesg;

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

frang_limits {http_methods OPTIONS HEAD GET PUT POST PUT PATCH DELETE;}
server ${server_ip}:8000;
"""
}

clients = [
{
"id": "deproxy",
"type": "deproxy",
"addr": "${tempesta_ip}",
"port": "443",
"ssl": True,
},
]
method: str = None
statuses: list[int] = None

@property
def statuses_description(self) -> dict[int, str]:
return {
200: "OK",
201: "Created",
302: "Found",
304: "Not Modified",
400: "Bad Request",
401: "Unauthorized",
403: "Forbidden",
404: "Not Found",
500: "Internal Server Error",
}

def test_request_success(self):
self.start_all_services()
self.disable_deproxy_auto_parser()

server = self.get_server("deproxy")
client = self.get_client("deproxy")
client.start()

for status in self.statuses:
with self.subTest(status=status):
server.set_response(
f"HTTP/1.1 {status} {self.statuses_description[status]}\r\n"
"Server: debian\r\n"
"Content-Length: 0\r\n\r\n\r\n"
)

client.send_request(
request=client.create_request(method=self.method, headers=[]),
expected_status_code=str(status),
)

self.assertEqual(
client.last_response.headers["content-length"],
"0",
msg=f"Tempesta should proxy the Content-Length header for the "
f"`{self.method} {status} {self.statuses_description[status]}` status code also",
)


@marks.parameterize_class(
[
{
"name": "POST",
"method": "POST",
},
{
"name": "PUT",
"method": "PUT",
},
{
"name": "PATCH",
"method": "PATCH",
},
{
"name": "DELETE",
"method": "DELETE",
},
]
)
class TestContentTypeWithEmptyBody(tester.TempestaTest):
backends = [
{
"id": "deproxy",
"type": "deproxy",
"port": "8000",
"response": "static",
"response_content": (
"HTTP/1.1 200 OK\r\n"
"Server: debian\r\n"
"Content-Length: 0\r\n"
"Content-Type: text/html; charset=utf-8\r\n\r\n\r\n"
),
}
]

tempesta = {
"config": """
listen 443 proto=https;
access_log dmesg;

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

frang_limits {http_methods OPTIONS HEAD GET PUT POST PUT PATCH DELETE;}
server ${server_ip}:8000;
"""
}

clients = [
{
"id": "deproxy",
"type": "deproxy",
"addr": "${tempesta_ip}",
"port": "443",
"ssl": True,
},
]
method: str = None

def test_request_success(self):
self.start_all_services()
client = self.get_client("deproxy")
client.send_request(
request=client.create_request(method=self.method, headers=[]),
expected_status_code="200",
)
self.assertEqual(
client.last_response.headers["content-type"],
"text/html; charset=utf-8",
msg="Tempesta should proxy the Content-Type header for the CRUD method with empty body also",
)
Loading