mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 06:46:15 +00:00
135 lines
3.9 KiB
Python
135 lines
3.9 KiB
Python
import os
|
|
import threading
|
|
import ssl
|
|
from wsgiref.simple_server import WSGIServer, make_server, WSGIRequestHandler
|
|
from wsgiref.handlers import SimpleHandler
|
|
from six.moves.urllib.parse import urljoin
|
|
|
|
|
|
CERT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'certs')
|
|
|
|
|
|
class ServerHandler(SimpleHandler):
|
|
|
|
server_software = 'Pytest-HTTPBIN/0.1.0'
|
|
http_version = '1.1'
|
|
|
|
def cleanup_headers(self):
|
|
SimpleHandler.cleanup_headers(self)
|
|
self.headers['Connection'] = 'Close'
|
|
|
|
def close(self):
|
|
try:
|
|
self.request_handler.log_request(
|
|
self.status.split(' ', 1)[0], self.bytes_sent
|
|
)
|
|
finally:
|
|
SimpleHandler.close(self)
|
|
|
|
|
|
class Handler(WSGIRequestHandler):
|
|
|
|
def handle(self):
|
|
"""Handle a single HTTP request"""
|
|
|
|
self.raw_requestline = self.rfile.readline()
|
|
if not self.parse_request(): # An error code has been sent, just exit
|
|
return
|
|
|
|
handler = ServerHandler(
|
|
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
|
|
)
|
|
handler.request_handler = self # backpointer for logging
|
|
handler.run(self.server.get_app())
|
|
|
|
def get_environ(self):
|
|
"""
|
|
wsgiref simple server adds content-type text/plain to everything, this
|
|
removes it if it's not actually in the headers.
|
|
"""
|
|
# Note: Can't use super since this is an oldstyle class in python 2.x
|
|
environ = WSGIRequestHandler.get_environ(self).copy()
|
|
if self.headers.get('content-type') is None:
|
|
del environ['CONTENT_TYPE']
|
|
return environ
|
|
|
|
|
|
class SecureWSGIServer(WSGIServer):
|
|
|
|
def finish_request(self, request, client_address):
|
|
"""
|
|
Negotiates SSL and then mimics BaseServer behavior.
|
|
"""
|
|
request.settimeout(1.0)
|
|
try:
|
|
ssock = ssl.wrap_socket(
|
|
request,
|
|
keyfile=os.path.join(CERT_DIR, 'key.pem'),
|
|
certfile=os.path.join(CERT_DIR, 'cert.pem'),
|
|
server_side=True,
|
|
suppress_ragged_eofs=False,
|
|
)
|
|
self.RequestHandlerClass(ssock, client_address, self)
|
|
except Exception as e:
|
|
print("pytest-httpbin server hit an exception serving request: %s" % e)
|
|
print("attempting to ignore so the rest of the tests can run")
|
|
# WSGIRequestHandler seems to close the socket for us.
|
|
# Thanks, WSGIRequestHandler!!
|
|
|
|
|
|
class Server:
|
|
"""
|
|
HTTP server running a WSGI application in its own thread.
|
|
"""
|
|
|
|
port_envvar = 'HTTPBIN_HTTP_PORT'
|
|
|
|
def __init__(self, host='127.0.0.1', port=0, application=None, **kwargs):
|
|
self.app = application
|
|
if self.port_envvar in os.environ:
|
|
port = int(os.environ[self.port_envvar])
|
|
self._server = make_server(
|
|
host,
|
|
port,
|
|
self.app,
|
|
handler_class=Handler,
|
|
**kwargs
|
|
)
|
|
self.host = self._server.server_address[0]
|
|
self.port = self._server.server_address[1]
|
|
self.protocol = 'http'
|
|
|
|
self._thread = threading.Thread(
|
|
name=self.__class__,
|
|
target=self._server.serve_forever,
|
|
)
|
|
|
|
def __del__(self):
|
|
if hasattr(self, '_server'):
|
|
self.stop()
|
|
|
|
def start(self):
|
|
self._thread.start()
|
|
|
|
def __add__(self, other):
|
|
return self.url + other
|
|
|
|
def stop(self):
|
|
self._server.shutdown()
|
|
|
|
@property
|
|
def url(self):
|
|
return f'{self.protocol}://{self.host}:{self.port}'
|
|
|
|
def join(self, url, allow_fragments=True):
|
|
return urljoin(self.url, url, allow_fragments=allow_fragments)
|
|
|
|
|
|
class SecureServer(Server):
|
|
port_envvar = 'HTTPBIN_HTTPS_PORT'
|
|
|
|
def __init__(self, host='127.0.0.1', port=0, application=None, **kwargs):
|
|
kwargs['server_class'] = SecureWSGIServer
|
|
super().__init__(host, port, application, **kwargs)
|
|
self.protocol = 'https'
|