blob: edafe01c8b8a9b3d8af17c9ba217bcc30c622c0a [file] [log] [blame]
"""Proxy tests.
Tests do modify `os.environ` global states. Each test must be run in separate
process. Must use `pytest --forked` or similar technique.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import httplib2
import mock
import os
import pytest
import socket
import tests
from six.moves import urllib
def _raise_name_not_known_error(*args, **kwargs):
raise socket.gaierror(socket.EAI_NONAME, "Name or service not known")
def test_from_url():
pi = httplib2.proxy_info_from_url("http://myproxy.example.com")
assert pi.proxy_host == "myproxy.example.com"
assert pi.proxy_port == 80
assert pi.proxy_user is None
def test_from_url_ident():
pi = httplib2.proxy_info_from_url("http://zoidberg:fish@someproxy:99")
assert pi.proxy_host == "someproxy"
assert pi.proxy_port == 99
assert pi.proxy_user == "zoidberg"
assert pi.proxy_pass == "fish"
def test_from_env(monkeypatch):
assert os.environ.get("http_proxy") is None
monkeypatch.setenv("http_proxy", "http://myproxy.example.com:8080")
pi = httplib2.proxy_info_from_environment()
assert pi.proxy_host == "myproxy.example.com"
assert pi.proxy_port == 8080
def test_from_env_https(monkeypatch):
assert os.environ.get("http_proxy") is None
monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80")
monkeypatch.setenv("https_proxy", "http://myproxy.example.com:81")
pi = httplib2.proxy_info_from_environment("https")
assert pi.proxy_host == "myproxy.example.com"
assert pi.proxy_port == 81
def test_from_env_none():
os.environ.clear()
pi = httplib2.proxy_info_from_environment()
assert pi is None
def test_applies_to(monkeypatch):
monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80")
monkeypatch.setenv("https_proxy", "http://myproxy.example.com:81")
monkeypatch.setenv("no_proxy", "localhost,example.com,.wildcard")
pi = httplib2.proxy_info_from_environment()
assert not pi.applies_to("localhost")
assert pi.applies_to("www.google.com")
assert pi.applies_to("prefixlocalhost")
assert pi.applies_to("www.example.com")
assert pi.applies_to("sub.example.com")
assert not pi.applies_to("sub.wildcard")
assert not pi.applies_to("pub.sub.wildcard")
def test_noproxy_trailing_comma(monkeypatch):
monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80")
monkeypatch.setenv("no_proxy", "localhost,other.host,")
pi = httplib2.proxy_info_from_environment()
assert not pi.applies_to("localhost")
assert not pi.applies_to("other.host")
assert pi.applies_to("example.domain")
def test_noproxy_star(monkeypatch):
monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80")
monkeypatch.setenv("NO_PROXY", "*")
pi = httplib2.proxy_info_from_environment()
for host in ("localhost", "169.254.38.192", "www.google.com"):
assert not pi.applies_to(host)
def test_headers():
headers = {"key0": "val0", "key1": "val1"}
pi = httplib2.ProxyInfo(
httplib2.socks.PROXY_TYPE_HTTP, "localhost", 1234, proxy_headers=headers
)
assert pi.proxy_headers == headers
@pytest.mark.skipif(
os.environ.get("TRAVIS_PYTHON_VERSION") in ("2.7", "pypy"),
reason="Fails on Travis py27/pypy, works elsewhere. "
"See https://travis-ci.org/httplib2/httplib2/jobs/408769880.",
)
@mock.patch("socket.socket.connect", spec=True)
def test_server_not_found_error_is_raised_for_invalid_hostname(mock_socket_connect):
"""Invalidates https://github.com/httplib2/httplib2/pull/100."""
mock_socket_connect.side_effect = _raise_name_not_known_error
http = httplib2.Http(
proxy_info=httplib2.ProxyInfo(
httplib2.socks.PROXY_TYPE_HTTP, "255.255.255.255", 8001
)
)
with tests.assert_raises(httplib2.ServerNotFoundError):
http.request("http://invalid.hostname.foo.bar/", "GET")
def test_auth_str_bytes():
# https://github.com/httplib2/httplib2/pull/115
# Proxy-Authorization b64encode() TypeError: a bytes-like object is required, not 'str'
with tests.server_const_http(request_count=2) as uri:
uri_parsed = urllib.parse.urlparse(uri)
http = httplib2.Http(
proxy_info=httplib2.ProxyInfo(
httplib2.socks.PROXY_TYPE_HTTP,
proxy_host=uri_parsed.hostname,
proxy_port=uri_parsed.port,
proxy_rdns=True,
proxy_user=u"user_str",
proxy_pass=u"pass_str",
)
)
response, _ = http.request(uri, "GET")
assert response.status == 200
with tests.server_const_http(request_count=2) as uri:
uri_parsed = urllib.parse.urlparse(uri)
http = httplib2.Http(
proxy_info=httplib2.ProxyInfo(
httplib2.socks.PROXY_TYPE_HTTP,
proxy_host=uri_parsed.hostname,
proxy_port=uri_parsed.port,
proxy_rdns=True,
proxy_user=b"user_bytes",
proxy_pass=b"pass_bytes",
)
)
response, _ = http.request(uri, "GET")
assert response.status == 200
def test_socks5_auth():
def proxy_conn(client, tick):
data = client.recv(64)
assert data == b"\x05\x02\x00\x02"
client.send(b"\x05\x02") # select username/password auth
data = client.recv(64)
assert data == b"\x01\x08user_str\x08pass_str"
client.send(b"\x01\x01") # deny
tick(None)
with tests.server_socket(proxy_conn) as uri:
uri_parsed = urllib.parse.urlparse(uri)
proxy_info = httplib2.ProxyInfo(
httplib2.socks.PROXY_TYPE_SOCKS5,
proxy_host=uri_parsed.hostname,
proxy_port=uri_parsed.port,
proxy_rdns=True,
proxy_user=u"user_str",
proxy_pass=u"pass_str",
)
http = httplib2.Http(proxy_info=proxy_info)
with tests.assert_raises(httplib2.socks.Socks5AuthError):
http.request(uri, "GET")
def test_functional_noproxy_star_http(monkeypatch):
def handler(request):
if request.method == "CONNECT":
return tests.http_response_bytes(
status="400 Expected direct", headers={"connection": "close"},
)
return tests.http_response_bytes()
with tests.server_request(handler) as uri:
monkeypatch.setenv("http_proxy", uri)
monkeypatch.setenv("no_proxy", "*")
http = httplib2.Http()
response, _ = http.request(uri, "GET")
assert response.status == 200
def test_functional_noproxy_star_https(monkeypatch):
def handler(request):
if request.method == "CONNECT":
return tests.http_response_bytes(
status="400 Expected direct", headers={"connection": "close"},
)
return tests.http_response_bytes()
with tests.server_request(handler, tls=True) as uri:
monkeypatch.setenv("https_proxy", uri)
monkeypatch.setenv("no_proxy", "*")
http = httplib2.Http(ca_certs=tests.CA_CERTS)
response, _ = http.request(uri, "GET")
assert response.status == 200