blob: d495a6e9554393dd129082189338eb8e5a63feda [file]
import inspect
import logging
import os
import socket
import sys
from threading import Thread
from pyhttpd.certs import CertificateSpec
from pyhttpd.env import HttpdTestEnv, HttpdTestSetup
log = logging.getLogger(__name__)
class TCPFaker:
# tcp backend for custom responses
def __init__(self, host, port):
self._thread = None
self._socket = None
self._host = host
self._port = port
self._done = False
self._request = None
def start(self):
def process():
self._socket.listen(1)
self._socket.settimeout(0.5)
self._process()
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind((self._host, self._port))
self._thread = Thread(target=process, daemon=True)
self._thread.start()
def stop(self):
self._done = True
self._thread.join(timeout=5)
self._socket.close()
def _make_response(self, data):
return """HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 5
Hello""".encode()
def _process(self):
_read_buffer = 8192 if sys.platform == "win32" else 4096
while not self._done:
try:
c, client_address = self._socket.accept()
try:
data = c.recv(_read_buffer)
# capture request to backend
self._request = data
c.sendall(self._make_response(data))
# Half-close for an orderly FIN instead of letting the
# OS tear the socket down under us. An abrupt close()
# right after sendall() can, depending on the platform's
# TCP stack and buffering, surface to the peer as a
# reset rather than a clean end of the response, which
# httpd's proxy and cache code treat as an aborted
# connection and a reason to discard the cache entry.
try:
c.shutdown(socket.SHUT_WR)
except OSError:
pass
finally:
c.close()
except socket.timeout:
pass
except ConnectionAbortedError:
self._done = True
class ProxyTestSetup(HttpdTestSetup):
def __init__(self, env: 'HttpdTestEnv'):
super().__init__(env=env)
self.add_source_dir(os.path.dirname(inspect.getfile(ProxyTestSetup)))
self.add_modules(["proxy", "proxy_http", "proxy_ajp", "proxy_balancer",
"proxy_connect", "proxy_uwsgi", "lbmethod_byrequests",
"remoteip"])
class ProxyTestEnv(HttpdTestEnv):
def __init__(self, pytestconfig=None):
super().__init__(pytestconfig=pytestconfig)
self.add_httpd_conf([
])
self._d_reverse = f"reverse.{self.http_tld}"
self._d_forward = f"forward.{self.http_tld}"
self._d_mixed = f"mixed.{self.http_tld}"
self.add_httpd_log_modules(
["proxy", "proxy_http", "proxy_balancer", "lbmethod_byrequests",
"ssl"])
self.add_cert_specs([
CertificateSpec(domains=[
self._d_forward, self._d_reverse, self._d_mixed
]),
CertificateSpec(domains=[f"noh2.{self.http_tld}"],
key_type='rsa2048'),
])
def setup_httpd(self, setup: HttpdTestSetup = None):
super().setup_httpd(setup=ProxyTestSetup(env=self))
@property
def d_forward(self):
return self._d_forward
@property
def d_reverse(self):
return self._d_reverse
@property
def d_mixed(self):
return self._d_mixed