2020-09-16 20:31:15 +00:00
|
|
|
import pytest
|
2023-06-14 17:20:09 +00:00
|
|
|
from unit.applications.lang.python import ApplicationPython
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-12 13:16:59 +00:00
|
|
|
prerequisites = {'modules': {'python': 'any'}}
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
client = ApplicationPython()
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_value_leading_sp():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Custom-Header': ' ,',
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value leading sp status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['Custom-Header'] == ','
|
|
|
|
), 'value leading sp custom header'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_leading_htab():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Custom-Header': '\t,',
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value leading htab status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['Custom-Header'] == ','
|
|
|
|
), 'value leading htab custom header'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_trailing_sp():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Custom-Header': ', ',
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value trailing sp status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['Custom-Header'] == ','
|
|
|
|
), 'value trailing sp custom header'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_trailing_htab():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Custom-Header': ',\t',
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value trailing htab status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['Custom-Header'] == ','
|
|
|
|
), 'value trailing htab custom header'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_both_sp():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Custom-Header': ' , ',
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value both sp status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['Custom-Header'] == ','
|
|
|
|
), 'value both sp custom header'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_both_htab():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Custom-Header': '\t,\t',
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value both htab status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['Custom-Header'] == ','
|
|
|
|
), 'value both htab custom header'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_chars():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Custom-Header': r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~",
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value chars status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['Custom-Header']
|
|
|
|
== r"(),/:;<=>?@[\]{}\t !#$%&'*+-.^_`|~"
|
|
|
|
), 'value chars custom header'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_chars_edge():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.http(
|
|
|
|
b"""GET / HTTP/1.1
|
|
|
|
Host: localhost
|
|
|
|
Custom-Header: \x20\xFF
|
|
|
|
Connection: close
|
|
|
|
|
|
|
|
""",
|
|
|
|
raw=True,
|
|
|
|
encoding='latin1',
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'value chars edge status'
|
|
|
|
assert resp['headers']['Custom-Header'] == '\xFF', 'value chars edge'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_value_chars_below():
|
|
|
|
client.load('custom_header')
|
|
|
|
|
|
|
|
resp = client.http(
|
|
|
|
b"""GET / HTTP/1.1
|
|
|
|
Host: localhost
|
|
|
|
Custom-Header: \x1F
|
|
|
|
Connection: close
|
|
|
|
|
|
|
|
""",
|
|
|
|
raw=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 400, 'value chars below'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_field_leading_sp():
|
|
|
|
client.load('empty')
|
|
|
|
|
|
|
|
assert (
|
|
|
|
client.get(
|
2019-03-26 20:38:30 +00:00
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
2023-06-14 17:20:09 +00:00
|
|
|
' Custom-Header': 'blah',
|
2019-03-26 20:38:30 +00:00
|
|
|
'Connection': 'close',
|
|
|
|
}
|
2023-06-14 17:20:09 +00:00
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'field leading sp'
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_field_leading_htab():
|
|
|
|
client.load('empty')
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.get(
|
2019-03-26 20:38:30 +00:00
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
2023-06-14 17:20:09 +00:00
|
|
|
'\tCustom-Header': 'blah',
|
2019-03-26 20:38:30 +00:00
|
|
|
'Connection': 'close',
|
|
|
|
}
|
2023-06-14 17:20:09 +00:00
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'field leading htab'
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_field_trailing_sp():
|
|
|
|
client.load('empty')
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.get(
|
2019-03-26 20:38:30 +00:00
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
2023-06-14 17:20:09 +00:00
|
|
|
'Custom-Header ': 'blah',
|
2019-03-26 20:38:30 +00:00
|
|
|
'Connection': 'close',
|
|
|
|
}
|
2023-06-14 17:20:09 +00:00
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'field trailing sp'
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_field_trailing_htab():
|
|
|
|
client.load('empty')
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.get(
|
2019-03-26 20:38:30 +00:00
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
2023-06-14 17:20:09 +00:00
|
|
|
'Custom-Header\t': 'blah',
|
2019-03-26 20:38:30 +00:00
|
|
|
'Connection': 'close',
|
|
|
|
}
|
2023-06-14 17:20:09 +00:00
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'field trailing htab'
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_content_length_big():
|
|
|
|
client.load('empty')
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.post(
|
2019-03-26 20:38:30 +00:00
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
2023-06-14 17:20:09 +00:00
|
|
|
'Content-Length': str(2**64),
|
2019-03-26 20:38:30 +00:00
|
|
|
'Connection': 'close',
|
2023-06-14 17:20:09 +00:00
|
|
|
},
|
|
|
|
body='X' * 1000,
|
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'Content-Length big'
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_content_length_negative():
|
|
|
|
client.load('empty')
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.post(
|
2019-03-26 20:38:30 +00:00
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
2023-06-14 17:20:09 +00:00
|
|
|
'Content-Length': '-100',
|
2019-03-26 20:38:30 +00:00
|
|
|
'Connection': 'close',
|
2023-06-14 17:20:09 +00:00
|
|
|
},
|
|
|
|
body='X' * 1000,
|
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'Content-Length negative'
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_content_length_text():
|
|
|
|
client.load('empty')
|
2018-03-16 14:45:25 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.post(
|
2019-03-26 20:38:30 +00:00
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
2023-06-14 17:20:09 +00:00
|
|
|
'Content-Length': 'blah',
|
2019-03-26 20:38:30 +00:00
|
|
|
'Connection': 'close',
|
2023-06-14 17:20:09 +00:00
|
|
|
},
|
|
|
|
body='X' * 1000,
|
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'Content-Length text'
|
2018-03-16 14:45:25 +00:00
|
|
|
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_content_length_multiple_values():
|
|
|
|
client.load('empty')
|
2018-07-11 16:35:36 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.post(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Content-Length': '41, 42',
|
|
|
|
'Connection': 'close',
|
|
|
|
},
|
|
|
|
body='X' * 1000,
|
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'Content-Length multiple value'
|
2018-07-30 13:40:52 +00:00
|
|
|
|
2018-07-11 16:35:36 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_content_length_multiple_fields():
|
|
|
|
client.load('empty')
|
2018-07-11 16:35:36 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert (
|
|
|
|
client.post(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
'Content-Length': ['41', '42'],
|
|
|
|
'Connection': 'close',
|
|
|
|
},
|
|
|
|
body='X' * 1000,
|
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'Content-Length multiple fields'
|
2018-07-11 16:35:36 +00:00
|
|
|
|
2018-07-30 13:40:52 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
@pytest.mark.skip('not yet')
|
|
|
|
def test_http_header_host_absent():
|
|
|
|
client.load('host')
|
2018-07-11 16:35:36 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
resp = client.get(headers={'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 400, 'Host absent status'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_empty():
|
|
|
|
client.load('host')
|
|
|
|
|
|
|
|
resp = client.get(headers={'Host': '', 'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host empty status'
|
|
|
|
assert resp['headers']['X-Server-Name'] != '', 'Host empty SERVER_NAME'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_big():
|
|
|
|
client.load('empty')
|
|
|
|
|
|
|
|
assert (
|
|
|
|
client.get(headers={'Host': 'X' * 10000, 'Connection': 'close'})[
|
|
|
|
'status'
|
|
|
|
]
|
|
|
|
== 431
|
|
|
|
), 'Host big'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_port():
|
|
|
|
client.load('host')
|
|
|
|
|
|
|
|
resp = client.get(
|
|
|
|
headers={'Host': 'exmaple.com:7080', 'Connection': 'close'}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host port status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Server-Name'] == 'exmaple.com'
|
|
|
|
), 'Host port SERVER_NAME'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Http-Host'] == 'exmaple.com:7080'
|
|
|
|
), 'Host port HTTP_HOST'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_port_empty():
|
|
|
|
client.load('host')
|
|
|
|
|
|
|
|
resp = client.get(headers={'Host': 'exmaple.com:', 'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host port empty status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Server-Name'] == 'exmaple.com'
|
|
|
|
), 'Host port empty SERVER_NAME'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Http-Host'] == 'exmaple.com:'
|
|
|
|
), 'Host port empty HTTP_HOST'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_literal():
|
|
|
|
client.load('host')
|
|
|
|
|
|
|
|
resp = client.get(headers={'Host': '127.0.0.1', 'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host literal status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Server-Name'] == '127.0.0.1'
|
|
|
|
), 'Host literal SERVER_NAME'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_literal_ipv6():
|
|
|
|
client.load('host')
|
|
|
|
|
|
|
|
resp = client.get(headers={'Host': '[::1]:7080', 'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host literal ipv6 status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Server-Name'] == '[::1]'
|
|
|
|
), 'Host literal ipv6 SERVER_NAME'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Http-Host'] == '[::1]:7080'
|
|
|
|
), 'Host literal ipv6 HTTP_HOST'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_trailing_period():
|
|
|
|
client.load('host')
|
|
|
|
|
|
|
|
resp = client.get(headers={'Host': '127.0.0.1.', 'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host trailing period status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Server-Name'] == '127.0.0.1'
|
|
|
|
), 'Host trailing period SERVER_NAME'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Http-Host'] == '127.0.0.1.'
|
|
|
|
), 'Host trailing period HTTP_HOST'
|
2019-02-27 17:41:30 +00:00
|
|
|
|
2020-11-19 05:21:48 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
def test_http_header_host_trailing_period_2():
|
|
|
|
client.load('host')
|
2020-11-19 05:21:48 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
resp = client.get(headers={'Host': 'EXAMPLE.COM.', 'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host trailing period 2 status'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Server-Name'] == 'example.com'
|
|
|
|
), 'Host trailing period 2 SERVER_NAME'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Http-Host'] == 'EXAMPLE.COM.'
|
|
|
|
), 'Host trailing period 2 HTTP_HOST'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_case_insensitive():
|
|
|
|
client.load('host')
|
|
|
|
|
|
|
|
resp = client.get(headers={'Host': 'EXAMPLE.COM', 'Connection': 'close'})
|
|
|
|
|
|
|
|
assert resp['status'] == 200, 'Host case insensitive'
|
|
|
|
assert (
|
|
|
|
resp['headers']['X-Server-Name'] == 'example.com'
|
|
|
|
), 'Host case insensitive SERVER_NAME'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_double_dot():
|
|
|
|
client.load('empty')
|
|
|
|
|
|
|
|
assert (
|
|
|
|
client.get(headers={'Host': '127.0.0..1', 'Connection': 'close'})[
|
|
|
|
'status'
|
|
|
|
]
|
|
|
|
== 400
|
|
|
|
), 'Host double dot'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_slash():
|
|
|
|
client.load('empty')
|
|
|
|
|
|
|
|
assert (
|
|
|
|
client.get(headers={'Host': '/localhost', 'Connection': 'close'})[
|
|
|
|
'status'
|
|
|
|
]
|
|
|
|
== 400
|
|
|
|
), 'Host slash'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_header_host_multiple_fields():
|
|
|
|
client.load('empty')
|
|
|
|
|
|
|
|
assert (
|
|
|
|
client.get(
|
|
|
|
headers={
|
|
|
|
'Host': ['localhost', 'example.com'],
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
|
|
|
)['status']
|
|
|
|
== 400
|
|
|
|
), 'Host multiple fields'
|
|
|
|
|
|
|
|
|
|
|
|
def test_http_discard_unsafe_fields():
|
|
|
|
client.load('header_fields')
|
|
|
|
|
|
|
|
def check_status(header):
|
|
|
|
resp = client.get(
|
|
|
|
headers={
|
|
|
|
'Host': 'localhost',
|
|
|
|
header: 'blah',
|
|
|
|
'Connection': 'close',
|
|
|
|
}
|
2020-11-19 05:21:48 +00:00
|
|
|
)
|
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
assert resp['status'] == 200
|
|
|
|
return resp
|
|
|
|
|
|
|
|
resp = check_status("!Custom-Header")
|
|
|
|
assert 'CUSTOM' not in resp['headers']['All-Headers']
|
|
|
|
|
|
|
|
resp = check_status("Custom_Header")
|
|
|
|
assert 'CUSTOM' not in resp['headers']['All-Headers']
|
|
|
|
|
|
|
|
assert 'success' in client.conf(
|
|
|
|
{'http': {'discard_unsafe_fields': False}},
|
|
|
|
'settings',
|
|
|
|
)
|
|
|
|
|
|
|
|
resp = check_status("!#$%&'*+.^`|~Custom_Header")
|
|
|
|
assert 'CUSTOM' in resp['headers']['All-Headers']
|
|
|
|
|
|
|
|
assert 'success' in client.conf(
|
|
|
|
{'http': {'discard_unsafe_fields': True}},
|
|
|
|
'settings',
|
|
|
|
)
|
|
|
|
|
|
|
|
resp = check_status("!Custom-Header")
|
|
|
|
assert 'CUSTOM' not in resp['headers']['All-Headers']
|
2020-11-19 05:21:48 +00:00
|
|
|
|
2023-06-14 17:20:09 +00:00
|
|
|
resp = check_status("Custom_Header")
|
|
|
|
assert 'CUSTOM' not in resp['headers']['All-Headers']
|