| """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 |