|
2 | 2 | import json |
3 | 3 | import os |
4 | 4 | import logging |
| 5 | +import socket |
5 | 6 | import time |
6 | 7 |
|
7 | 8 | import pytest |
@@ -66,6 +67,28 @@ def send_requests(conn, num_requests, headers, json_payload): |
66 | 67 | return responses |
67 | 68 |
|
68 | 69 |
|
| 70 | +def send_raw_http1_request(port, request): |
| 71 | + response = bytearray() |
| 72 | + |
| 73 | + with socket.create_connection(("127.0.0.1", port), timeout=2) as connection: |
| 74 | + connection.settimeout(2) |
| 75 | + connection.sendall(request) |
| 76 | + |
| 77 | + while len(response) < 4096 and b"\r\n" not in response: |
| 78 | + try: |
| 79 | + data = connection.recv(4096 - len(response)) |
| 80 | + except ConnectionResetError: |
| 81 | + break |
| 82 | + except socket.timeout: |
| 83 | + pytest.fail("HTTP/1 server did not respond or close the connection") |
| 84 | + |
| 85 | + if not data: |
| 86 | + break |
| 87 | + response.extend(data) |
| 88 | + |
| 89 | + return bytes(response) |
| 90 | + |
| 91 | + |
69 | 92 | def test_send_data(): |
70 | 93 | try: |
71 | 94 | service = Service("in_http_config") |
@@ -150,6 +173,88 @@ def test_in_http_rejects_get_requests(): |
150 | 173 | assert result["status_code"] >= 400 |
151 | 174 |
|
152 | 175 |
|
| 176 | +def test_in_http_accepts_post_with_empty_generic_headers(): |
| 177 | + service = Service("in_http_config") |
| 178 | + body = b'{"message":"empty-header"}' |
| 179 | + request = ( |
| 180 | + b"POST / HTTP/1.1\r\n" |
| 181 | + b"Host: localhost\r\n" |
| 182 | + b"Content-Type: application/json\r\n" |
| 183 | + + f"Content-Length: {len(body)}\r\n".encode() |
| 184 | + + b"X-Empty:\r\n" |
| 185 | + b"X-Empty-Whitespace: \t\r\n" |
| 186 | + b"Connection: close\r\n" |
| 187 | + b"\r\n" |
| 188 | + + body |
| 189 | + ) |
| 190 | + |
| 191 | + try: |
| 192 | + service.start() |
| 193 | + response = send_raw_http1_request(service.flb_listener_port, request) |
| 194 | + forwarded_payloads = service.read_forwarded_payloads() |
| 195 | + finally: |
| 196 | + service.stop() |
| 197 | + |
| 198 | + assert b"HTTP/1.1 201" in response |
| 199 | + assert len(forwarded_payloads) == 1 |
| 200 | + assert forwarded_payloads[0][0]["message"] == "empty-header" |
| 201 | + |
| 202 | + |
| 203 | +def test_in_http_accepts_empty_connection_and_transfer_encoding(): |
| 204 | + service = Service("in_http_config") |
| 205 | + body = b'{"message":"empty-semantic-headers"}' |
| 206 | + request = ( |
| 207 | + b"POST / HTTP/1.1\r\n" |
| 208 | + b"Host: localhost\r\n" |
| 209 | + b"Content-Type: application/json\r\n" |
| 210 | + + f"Content-Length: {len(body)}\r\n".encode() |
| 211 | + + b"Connection:\r\n" |
| 212 | + b"Transfer-Encoding: \t\r\n" |
| 213 | + b"Connection: close\r\n" |
| 214 | + b"\r\n" |
| 215 | + + body |
| 216 | + ) |
| 217 | + |
| 218 | + try: |
| 219 | + service.start() |
| 220 | + response = send_raw_http1_request(service.flb_listener_port, request) |
| 221 | + forwarded_payloads = service.read_forwarded_payloads() |
| 222 | + finally: |
| 223 | + service.stop() |
| 224 | + |
| 225 | + assert b"HTTP/1.1 201" in response |
| 226 | + assert len(forwarded_payloads) == 1 |
| 227 | + assert forwarded_payloads[0][0]["message"] == "empty-semantic-headers" |
| 228 | + |
| 229 | + |
| 230 | +@pytest.mark.parametrize("header_value", [b"", b" \t"], ids=["empty", "whitespace"]) |
| 231 | +@pytest.mark.parametrize( |
| 232 | + "following_data", |
| 233 | + [b"1-X: value\r\nConnection: close\r\n\r\n1", b"\r\n1"], |
| 234 | + ids=["numeric-header", "numeric-body"], |
| 235 | +) |
| 236 | +def test_in_http_rejects_empty_content_length(header_value, following_data): |
| 237 | + service = Service("in_http_config") |
| 238 | + request = ( |
| 239 | + b"POST / HTTP/1.1\r\n" |
| 240 | + b"Host: localhost\r\n" |
| 241 | + b"Content-Type: application/json\r\n" |
| 242 | + b"Content-Length:" + header_value + b"\r\n" |
| 243 | + + following_data |
| 244 | + ) |
| 245 | + |
| 246 | + try: |
| 247 | + service.start() |
| 248 | + response = send_raw_http1_request(service.flb_listener_port, request) |
| 249 | + time.sleep(0.5) |
| 250 | + forwarded_payloads = list(data_storage["payloads"]) |
| 251 | + finally: |
| 252 | + service.stop() |
| 253 | + |
| 254 | + assert response == b"" or b"HTTP/1.1 400" in response |
| 255 | + assert forwarded_payloads == [] |
| 256 | + |
| 257 | + |
153 | 258 | @pytest.mark.parametrize( |
154 | 259 | "case", |
155 | 260 | [ |
|
0 commit comments