Merge pull request #35 from cdent/issue-30

Guard against http_proxy and https_proxy
This commit is contained in:
Chris Dent 2016-01-22 14:33:27 +00:00
commit 05b6772a0a
8 changed files with 74 additions and 3 deletions

View File

@ -1,9 +1,10 @@
import os
import wsgi_intercept import wsgi_intercept
class BaseInstalledApp(object): class BaseInstalledApp(object):
def __init__(self, app, host, port=80, script_name='', def __init__(self, app, host, port=80, script_name='',
install=None, uninstall=None): install=None, uninstall=None, proxy=None):
self.app = app self.app = app
self.host = host self.host = host
self.port = port self.port = port
@ -12,6 +13,7 @@ class BaseInstalledApp(object):
self._uninstall = uninstall or (lambda: None) self._uninstall = uninstall or (lambda: None)
self._hits = 0 self._hits = 0
self._internals = {} self._internals = {}
self._proxy = proxy
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
self._hits += 1 self._hits += 1
@ -32,10 +34,14 @@ class BaseInstalledApp(object):
wsgi_intercept.remove_wsgi_intercept(self.host, self.port) wsgi_intercept.remove_wsgi_intercept(self.host, self.port)
def install(self): def install(self):
if self._proxy:
os.environ['http_proxy'] = self._proxy
self._install() self._install()
self.install_wsgi_intercept() self.install_wsgi_intercept()
def uninstall(self): def uninstall(self):
if self._proxy:
del os.environ['http_proxy']
self.uninstall_wsgi_intercept() self.uninstall_wsgi_intercept()
self._uninstall() self._uninstall()
@ -56,9 +62,9 @@ def installer_class(module=None, install=None, uninstall=None):
uninstall = uninstall or getattr(module, 'uninstall', None) uninstall = uninstall or getattr(module, 'uninstall', None)
class InstalledApp(BaseInstalledApp): class InstalledApp(BaseInstalledApp):
def __init__(self, app, host, port=80, script_name=''): def __init__(self, app, host, port=80, script_name='', proxy=None):
BaseInstalledApp.__init__( BaseInstalledApp.__init__(
self, app=app, host=host, port=port, script_name=script_name, self, app=app, host=host, port=port, script_name=script_name,
install=install, uninstall=uninstall) install=install, uninstall=uninstall, proxy=proxy)
return InstalledApp return InstalledApp

View File

@ -42,6 +42,18 @@ def test_other():
assert app.success() assert app.success()
def test_proxy_handling():
"""Proxy variable no impact."""
with InstalledApp(wsgi_app.simple_app, host=HOST, port=80,
proxy='some.host:1234') as app:
http_client = http_lib.HTTPConnection(HOST)
http_client.request('GET', '/')
content = http_client.getresponse().read()
http_client.close()
assert content == b'WSGI intercept successful!\n'
assert app.success()
def test_app_error(): def test_app_error():
with InstalledApp(wsgi_app.raises_app, host=HOST, port=80): with InstalledApp(wsgi_app.raises_app, host=HOST, port=80):
http_client = http_lib.HTTPConnection(HOST) http_client = http_lib.HTTPConnection(HOST)

View File

@ -47,6 +47,17 @@ def test_bogus_domain():
'httplib2_intercept.HTTP_WSGIInterceptorWithTimeout("_nonexistant_domain_").connect()') 'httplib2_intercept.HTTP_WSGIInterceptorWithTimeout("_nonexistant_domain_").connect()')
def test_proxy_handling():
"""Proxy has no impact."""
with InstalledApp(wsgi_app.simple_app, host=HOST, port=80,
proxy='some_proxy.com:1234') as app:
http = httplib2.Http()
resp, content = http.request(
'http://some_hopefully_nonexistant_domain:80/')
assert content == b'WSGI intercept successful!\n'
assert app.success()
def test_https(): def test_https():
with InstalledApp(wsgi_app.simple_app, host=HOST, port=443) as app: with InstalledApp(wsgi_app.simple_app, host=HOST, port=443) as app:
http = httplib2.Http() http = httplib2.Http()

View File

@ -1,3 +1,4 @@
import os
import py.test import py.test
from wsgi_intercept import requests_intercept, WSGIAppError from wsgi_intercept import requests_intercept, WSGIAppError
from test import wsgi_app from test import wsgi_app
@ -40,6 +41,18 @@ def test_bogus_domain():
'requests.get("http://_nonexistant_domain_")') 'requests.get("http://_nonexistant_domain_")')
def test_proxy_handling():
with py.test.raises(RuntimeError) as exc:
with InstalledApp(wsgi_app.simple_app, host=HOST, port=80,
proxy='some_proxy.com:1234'):
requests.get('http://some_hopefully_nonexistant_domain:80/')
assert 'http_proxy or https_proxy set in environment' in str(exc.value)
# We need to do this by hand because the exception was raised
# during the entry of the context manager, so the exit handler
# wasn't reached.
del os.environ['http_proxy']
def test_https(): def test_https():
with InstalledApp(wsgi_app.simple_app, host=HOST, port=443) as app: with InstalledApp(wsgi_app.simple_app, host=HOST, port=443) as app:
resp = requests.get('https://some_hopefully_nonexistant_domain:443/') resp = requests.get('https://some_hopefully_nonexistant_domain:443/')

View File

@ -1,3 +1,4 @@
import os
import py.test import py.test
from wsgi_intercept import urllib_intercept, WSGIAppError from wsgi_intercept import urllib_intercept, WSGIAppError
from test import wsgi_app from test import wsgi_app
@ -32,6 +33,19 @@ def test_http_other_port():
assert environ['wsgi.url_scheme'] == 'http' assert environ['wsgi.url_scheme'] == 'http'
def test_proxy_handling():
"""Like requests, urllib gets confused about proxy early on."""
with py.test.raises(RuntimeError) as exc:
with InstalledApp(wsgi_app.simple_app, host=HOST, port=80,
proxy='some.host:1234'):
url_lib.urlopen('http://some_hopefully_nonexistant_domain:80/')
assert 'http_proxy or https_proxy set in environment' in str(exc.value)
# We need to do this by hand because the exception was raised
# during the entry of the context manager, so the exit handler
# wasn't reached.
del os.environ['http_proxy']
def test_https(): def test_https():
with InstalledApp(wsgi_app.simple_app, host=HOST, port=443) as app: with InstalledApp(wsgi_app.simple_app, host=HOST, port=443) as app:
url_lib.urlopen('https://some_hopefully_nonexistant_domain:443/') url_lib.urlopen('https://some_hopefully_nonexistant_domain:443/')

View File

@ -50,6 +50,11 @@ Note especially that ``app_create_fn`` is a *function object* returning a WSGI
application; ``script_name`` becomes ``SCRIPT_NAME`` in the WSGI app's application; ``script_name`` becomes ``SCRIPT_NAME`` in the WSGI app's
environment, if set. environment, if set.
Note also that if ``http_proxy`` or ``https_proxy`` is set in the environment
this can cause difficulties with some of the intercepted libraries. If
requests or urllib is being used, these will raise an exception if one of
those variables is set.
Install Install
======= =======

View File

@ -1,6 +1,7 @@
"""Intercept HTTP connections that use `requests <http://docs.python-requests.org/en/latest/>`_. """Intercept HTTP connections that use `requests <http://docs.python-requests.org/en/latest/>`_.
""" """
import os
import sys import sys
from . import WSGI_HTTPConnection, WSGI_HTTPSConnection, wsgi_fake_socket from . import WSGI_HTTPConnection, WSGI_HTTPSConnection, wsgi_fake_socket
@ -32,6 +33,9 @@ class HTTPS_WSGIInterceptor(WSGI_HTTPSConnection, HTTPSConnection):
def install(): def install():
if 'http_proxy' in os.environ or 'https_proxy' in os.environ:
raise RuntimeError(
'http_proxy or https_proxy set in environment, please unset')
HTTPConnectionPool.ConnectionCls = HTTP_WSGIInterceptor HTTPConnectionPool.ConnectionCls = HTTP_WSGIInterceptor
HTTPSConnectionPool.ConnectionCls = HTTPS_WSGIInterceptor HTTPSConnectionPool.ConnectionCls = HTTPS_WSGIInterceptor

View File

@ -1,5 +1,8 @@
"""Intercept HTTP connections that use urllib.request (Py3) aka urllib2 (Python 2). """Intercept HTTP connections that use urllib.request (Py3) aka urllib2 (Python 2).
""" """
import os
try: try:
import urllib.request as url_lib import urllib.request as url_lib
except ImportError: except ImportError:
@ -27,6 +30,9 @@ class WSGI_HTTPSHandler(url_lib.HTTPSHandler):
def install_opener(): def install_opener():
if 'http_proxy' in os.environ or 'https_proxy' in os.environ:
raise RuntimeError(
'http_proxy or https_proxy set in environment, please unset')
handlers = [WSGI_HTTPHandler()] handlers = [WSGI_HTTPHandler()]
if WSGI_HTTPSHandler is not None: if WSGI_HTTPSHandler is not None:
handlers.append(WSGI_HTTPSHandler()) handlers.append(WSGI_HTTPSHandler())