blob: 60a4afa8af9c5fcb9894dbd9c583da861587950f [file]
import re
import pytest
from pyhttpd.conf import HttpdConf
from .env import TCPFaker
class _ResponseFaker(TCPFaker):
def _make_response(self, data):
first_line = data.split(b"\r\n")[0].decode("latin-1")
path = first_line.split(" ")[1] if " " in first_line else "/"
if "/content-type" in path:
return """HTTP/1.1 200 OK\r\nContent-Type:
text/html\x00extra\r\n\r\n""".encode()
if "/forwarded" in path:
headers = data.split(b"\r\n\r\n")[0].decode("latin-1")
forwarded = []
for line in headers.split("\r\n"):
if line.lower().startswith("x-forwarded-"):
forwarded.append(line)
return ("HTTP/1.1 200 OK\r\n" + "\r\n".join(
forwarded) + "\r\n\r\n").encode()
if "/balancer" in path:
headers = data.split(b"\r\n\r\n")[0].decode("latin-1")
body_lines = []
for line in headers.split("\r\n"):
if ": " in line:
name, value = line.split(": ", 1)
body_lines.append(f"{name.upper()} = {value}")
body = "\r\n".join(body_lines)
return (
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
f"Content-Length: {len(body.encode())}\r\n"
"\r\n"
+ body
).encode()
return super()._make_response(data)
class TestProxyResponse:
@pytest.fixture(autouse=True, scope='class')
def _class_scope(self, env):
faker = _ResponseFaker("127.0.0.1", env.http_port2)
faker.start()
conf = HttpdConf(env)
conf.add([
'<Proxy "balancer://xqacluster">',
f' BalancerMember "http://127.0.0.1:{env.http_port2 + 1}"',
f' BalancerMember "http://127.0.0.1:{env.http_port2}"',
' ProxySet forcerecovery=Off',
'</Proxy>',
])
conf.start_vhost(domains=[f"test1.{env.http_tld}"], port=env.http_port,
doc_root="htdocs", with_ssl=False)
conf.add([
"ProxyPass /balancer balancer://xqacluster/balancer",
f"ProxyPass / http://127.0.0.1:{env.http_port2}/",
f"ProxyPassReverse / http://127.0.0.1:{env.http_port2}/",
])
if env.has_shared_module("remoteip"):
conf.add([
"RemoteIPHeader X-Forwarded-For",
"RemoteIPTrustedProxy 0.0.0.0",
])
conf.end_vhost()
conf.install()
assert env.apache_restart() == 0
yield
faker.stop()
# check Content-Type
def test_proxy_03_001(self, env):
if not env.httpd_is_at_least("2.4.55"):
pytest.skip(f'need at least httpd 2.4.55 for this')
r = env.curl_get(env.mkurl("http", "test1", "/content-type"))
assert r.response["status"] == 502
env.httpd_error_log.ignore_recent(
lognos=["AH01106", "AH10404"]
)
# checks X-Forwarded headers
def test_proxy_03_002(self, env):
if not env.httpd_is_at_least("2.4.54"):
pytest.skip(f'need at least httpd 2.4.54 for this')
r = env.curl_get(env.mkurl("http", "test1", "/forwarded"), options=[
'-H', 'Connection: close, X-Forwarded-For, X-Forwarded-Host, '
'X-Forwarded-Server',
])
assert r.response["status"] == 200
assert "x-forwarded-for" in r.response["header"]
assert "x-forwarded-host" in r.response["header"]
assert "x-forwarded-server" in r.response["header"]
# check body is preserved after failover
def test_proxy_03_003(self, env):
if not env.httpd_is_at_least("2.4.42"):
pytest.skip(f'need at least httpd 2.4.42 for this')
post_body = "123testing"
r = env.curl_get(
env.mkurl("http", "test1", "/balancer"),
options=['--data', post_body, '-H', 'Content-Type: text/plain; '
'charset=utf-8']
)
assert r.response["status"] == 200
body = r.response["body"].decode("latin-1")
m = re.search(r'CONTENT-LENGTH = (\d+)', body, re.IGNORECASE)
assert m is not None
assert int(m.group(1)) == len(post_body)
env.httpd_error_log.ignore_recent(
lognos=["AH00957", "AH00959", "AH01114"]
)