1"""Proxy tests. 2 3Tests do modify `os.environ` global states. Each test must be run in separate 4process. Must use `pytest --forked` or similar technique. 5""" 6 7from __future__ import absolute_import 8from __future__ import division 9from __future__ import print_function 10 11import httplib2 12import mock 13import os 14import pytest 15import socket 16import tests 17from six.moves import urllib 18 19 20def _raise_name_not_known_error(*args, **kwargs): 21 raise socket.gaierror(socket.EAI_NONAME, "Name or service not known") 22 23 24def test_from_url(): 25 pi = httplib2.proxy_info_from_url("http://myproxy.example.com") 26 assert pi.proxy_host == "myproxy.example.com" 27 assert pi.proxy_port == 80 28 assert pi.proxy_user is None 29 30 31def test_from_url_ident(): 32 pi = httplib2.proxy_info_from_url("http://zoidberg:fish@someproxy:99") 33 assert pi.proxy_host == "someproxy" 34 assert pi.proxy_port == 99 35 assert pi.proxy_user == "zoidberg" 36 assert pi.proxy_pass == "fish" 37 38 39def test_from_env(monkeypatch): 40 assert os.environ.get("http_proxy") is None 41 monkeypatch.setenv("http_proxy", "http://myproxy.example.com:8080") 42 pi = httplib2.proxy_info_from_environment() 43 assert pi.proxy_host == "myproxy.example.com" 44 assert pi.proxy_port == 8080 45 46 47def test_from_env_https(monkeypatch): 48 assert os.environ.get("http_proxy") is None 49 monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80") 50 monkeypatch.setenv("https_proxy", "http://myproxy.example.com:81") 51 pi = httplib2.proxy_info_from_environment("https") 52 assert pi.proxy_host == "myproxy.example.com" 53 assert pi.proxy_port == 81 54 55 56def test_from_env_none(): 57 os.environ.clear() 58 pi = httplib2.proxy_info_from_environment() 59 assert pi is None 60 61 62def test_applies_to(monkeypatch): 63 monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80") 64 monkeypatch.setenv("https_proxy", "http://myproxy.example.com:81") 65 monkeypatch.setenv("no_proxy", "localhost,example.com,.wildcard") 66 pi = httplib2.proxy_info_from_environment() 67 assert not pi.applies_to("localhost") 68 assert pi.applies_to("www.google.com") 69 assert pi.applies_to("prefixlocalhost") 70 assert pi.applies_to("www.example.com") 71 assert pi.applies_to("sub.example.com") 72 assert not pi.applies_to("sub.wildcard") 73 assert not pi.applies_to("pub.sub.wildcard") 74 75 76def test_noproxy_trailing_comma(monkeypatch): 77 monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80") 78 monkeypatch.setenv("no_proxy", "localhost,other.host,") 79 pi = httplib2.proxy_info_from_environment() 80 assert not pi.applies_to("localhost") 81 assert not pi.applies_to("other.host") 82 assert pi.applies_to("example.domain") 83 84 85def test_noproxy_star(monkeypatch): 86 monkeypatch.setenv("http_proxy", "http://myproxy.example.com:80") 87 monkeypatch.setenv("NO_PROXY", "*") 88 pi = httplib2.proxy_info_from_environment() 89 for host in ("localhost", "169.254.38.192", "www.google.com"): 90 assert not pi.applies_to(host) 91 92 93def test_headers(): 94 headers = {"key0": "val0", "key1": "val1"} 95 pi = httplib2.ProxyInfo( 96 httplib2.socks.PROXY_TYPE_HTTP, "localhost", 1234, proxy_headers=headers 97 ) 98 assert pi.proxy_headers == headers 99 100 101@pytest.mark.skipif( 102 os.environ.get("TRAVIS_PYTHON_VERSION") in ("2.7", "pypy"), 103 reason="Fails on Travis py27/pypy, works elsewhere. " 104 "See https://travis-ci.org/httplib2/httplib2/jobs/408769880.", 105) 106@mock.patch("socket.socket.connect", spec=True) 107def test_server_not_found_error_is_raised_for_invalid_hostname(mock_socket_connect): 108 """Invalidates https://github.com/httplib2/httplib2/pull/100.""" 109 mock_socket_connect.side_effect = _raise_name_not_known_error 110 http = httplib2.Http( 111 proxy_info=httplib2.ProxyInfo( 112 httplib2.socks.PROXY_TYPE_HTTP, "255.255.255.255", 8001 113 ) 114 ) 115 with tests.assert_raises(httplib2.ServerNotFoundError): 116 http.request("http://invalid.hostname.foo.bar/", "GET") 117 118 119def test_auth_str_bytes(): 120 # https://github.com/httplib2/httplib2/pull/115 121 # Proxy-Authorization b64encode() TypeError: a bytes-like object is required, not 'str' 122 with tests.server_const_http(request_count=2) as uri: 123 uri_parsed = urllib.parse.urlparse(uri) 124 http = httplib2.Http( 125 proxy_info=httplib2.ProxyInfo( 126 httplib2.socks.PROXY_TYPE_HTTP, 127 proxy_host=uri_parsed.hostname, 128 proxy_port=uri_parsed.port, 129 proxy_rdns=True, 130 proxy_user=u"user_str", 131 proxy_pass=u"pass_str", 132 ) 133 ) 134 response, _ = http.request(uri, "GET") 135 assert response.status == 200 136 137 with tests.server_const_http(request_count=2) as uri: 138 uri_parsed = urllib.parse.urlparse(uri) 139 http = httplib2.Http( 140 proxy_info=httplib2.ProxyInfo( 141 httplib2.socks.PROXY_TYPE_HTTP, 142 proxy_host=uri_parsed.hostname, 143 proxy_port=uri_parsed.port, 144 proxy_rdns=True, 145 proxy_user=b"user_bytes", 146 proxy_pass=b"pass_bytes", 147 ) 148 ) 149 response, _ = http.request(uri, "GET") 150 assert response.status == 200 151 152 153def test_socks5_auth(): 154 def proxy_conn(client, tick): 155 data = client.recv(64) 156 assert data == b"\x05\x02\x00\x02" 157 client.send(b"\x05\x02") # select username/password auth 158 data = client.recv(64) 159 assert data == b"\x01\x08user_str\x08pass_str" 160 client.send(b"\x01\x01") # deny 161 tick(None) 162 163 with tests.server_socket(proxy_conn) as uri: 164 uri_parsed = urllib.parse.urlparse(uri) 165 proxy_info = httplib2.ProxyInfo( 166 httplib2.socks.PROXY_TYPE_SOCKS5, 167 proxy_host=uri_parsed.hostname, 168 proxy_port=uri_parsed.port, 169 proxy_rdns=True, 170 proxy_user=u"user_str", 171 proxy_pass=u"pass_str", 172 ) 173 http = httplib2.Http(proxy_info=proxy_info) 174 with tests.assert_raises(httplib2.socks.Socks5AuthError): 175 http.request(uri, "GET") 176 177 178def test_functional_noproxy_star_http(monkeypatch): 179 def handler(request): 180 if request.method == "CONNECT": 181 return tests.http_response_bytes( 182 status="400 Expected direct", headers={"connection": "close"}, 183 ) 184 return tests.http_response_bytes() 185 186 with tests.server_request(handler) as uri: 187 monkeypatch.setenv("http_proxy", uri) 188 monkeypatch.setenv("no_proxy", "*") 189 http = httplib2.Http() 190 response, _ = http.request(uri, "GET") 191 assert response.status == 200 192 193 194def test_functional_noproxy_star_https(monkeypatch): 195 def handler(request): 196 if request.method == "CONNECT": 197 return tests.http_response_bytes( 198 status="400 Expected direct", headers={"connection": "close"}, 199 ) 200 return tests.http_response_bytes() 201 202 with tests.server_request(handler, tls=True) as uri: 203 monkeypatch.setenv("https_proxy", uri) 204 monkeypatch.setenv("no_proxy", "*") 205 http = httplib2.Http(ca_certs=tests.CA_CERTS) 206 response, _ = http.request(uri, "GET") 207 assert response.status == 200 208