def test_tagging_key(): data = {} store = taggingcache.TaggingStore(data, writeable=True) server = taggingcache.taggingserver(store) resp = server_request(server, 'set testkey 0 0 4\r\n' 'blah\r\n') assert resp == 'STORED\r\n' resp = server_request(server, 'tag_add testtag testkey\r\n') assert resp == 'TAG_STORED\r\n'
def test_digest_next_nonce_nc(): # Test that if the server sets nextnonce that we reset # the nonce count back to 1 http = httplib2.Http() password = tests.gen_password() grenew_nonce = [None] handler = tests.http_reflect_with_auth( allow_scheme="digest", allow_credentials=(("joe", password),), out_renew_nonce=grenew_nonce, ) with tests.server_request(handler, request_count=5) as uri: http.add_credentials("joe", password) response1, _ = http.request(uri, "GET") info = httplib2.auth._parse_authentication_info(response1) print("debug: response1 authentication-info: {}\nparsed: {}".format(response1.get("authentication-info"), info)) assert response1.status == 200 assert info.get("nc") == "00000001", info assert not info.get("digest", {}).get("nextnonce"), info response2, _ = http.request(uri, "GET") info2 = httplib2.auth._parse_authentication_info(response2) assert info2.get("nc") == "00000002", info2 grenew_nonce[0]() response3, content = http.request(uri, "GET") info3 = httplib2.auth._parse_authentication_info(response3) assert response3.status == 200 assert info3.get("nc") == "00000001", info3
def test_digest_next_nonce_nc(): # Test that if the server sets nextnonce that we reset # the nonce count back to 1 http = httplib2.Http() password = tests.gen_password() grenew_nonce = [None] handler = tests.http_reflect_with_auth( allow_scheme="digest", allow_credentials=(("joe", password),), out_renew_nonce=grenew_nonce, ) with tests.server_request(handler, request_count=5) as uri: http.add_credentials("joe", password) response1, _ = http.request(uri, "GET") info = httplib2._parse_www_authenticate(response1, "authentication-info") assert response1.status == 200 assert info.get("digest", {}).get("nc") == "00000001", info assert not info.get("digest", {}).get("nextnonce"), info response2, _ = http.request(uri, "GET") info2 = httplib2._parse_www_authenticate(response2, "authentication-info") assert info2.get("digest", {}).get("nc") == "00000002", info2 grenew_nonce[0]() response3, content = http.request(uri, "GET") info3 = httplib2._parse_www_authenticate(response3, "authentication-info") assert response3.status == 200 assert info3.get("digest", {}).get("nc") == "00000001", info3
def test_adding_tag_to_nonexistant_key(): data = {} store = taggingcache.TaggingStore(data, writeable=True) server = taggingcache.taggingserver(store) resp = server_request(server, 'tag_add testtag testkey\r\n') assert resp == 'TAG_NOT_FOUND\r\n', resp
def test_deleting_nonexistent_tag(): data = {} store = taggingcache.TaggingStore(data, writeable=True) server = taggingcache.taggingserver(store) resp = server_request(server, 'tag_delete testtag\r\n') assert resp == 'TAG_NOT_FOUND\r\n', resp
def test_digest_auth_stale(): # Test that we can handle a nonce becoming stale http = httplib2.Http() password = tests.gen_password() grenew_nonce = [None] requests = [] handler = tests.http_reflect_with_auth( allow_scheme="digest", allow_credentials=(("joe", password),), out_renew_nonce=grenew_nonce, out_requests=requests, ) with tests.server_request(handler, request_count=4) as uri: http.add_credentials("joe", password) response, _ = http.request(uri, "GET") assert response.status == 200 info = httplib2._parse_www_authenticate( requests[0][1].headers, "www-authenticate" ) grenew_nonce[0]() response, _ = http.request(uri, "GET") assert response.status == 200 assert not response.fromcache assert getattr(response, "_stale_digest", False) info2 = httplib2._parse_www_authenticate( requests[2][1].headers, "www-authenticate" ) nonce1 = info.get("digest", {}).get("nonce", "") nonce2 = info2.get("digest", {}).get("nonce", "") assert nonce1 != "" assert nonce2 != "" assert nonce1 != nonce2, (nonce1, nonce2)
def test_digest_auth_stale(): # Test that we can handle a nonce becoming stale http = httplib2.Http() password = tests.gen_password() grenew_nonce = [None] requests = [] handler = tests.http_reflect_with_auth( allow_scheme='digest', allow_credentials=(('joe', password), ), out_renew_nonce=grenew_nonce, out_requests=requests, ) with tests.server_request(handler, request_count=4) as uri: http.add_credentials('joe', password) response, _ = http.request(uri, 'GET') assert response.status == 200 info = httplib2._parse_www_authenticate(requests[0][1].headers, 'www-authenticate') grenew_nonce[0]() response, _ = http.request(uri, 'GET') assert response.status == 200 assert not response.fromcache assert getattr(response, '_stale_digest', False) info2 = httplib2._parse_www_authenticate(requests[2][1].headers, 'www-authenticate') nonce1 = info.get('digest', {}).get('nonce', '') nonce2 = info2.get('digest', {}).get('nonce', '') assert nonce1 != '' assert nonce2 != '' assert nonce1 != nonce2, (nonce1, nonce2)
def test_digest_next_nonce_nc(): # Test that if the server sets nextnonce that we reset # the nonce count back to 1 http = httplib2.Http() password = tests.gen_password() grenew_nonce = [None] handler = tests.http_reflect_with_auth( allow_scheme='digest', allow_credentials=(('joe', password), ), out_renew_nonce=grenew_nonce, ) with tests.server_request(handler, request_count=5) as uri: http.add_credentials('joe', password) response1, _ = http.request(uri, 'GET') info = httplib2._parse_www_authenticate(response1, 'authentication-info') assert response1.status == 200 assert info.get('digest', {}).get('nc') == '00000001', info assert not info.get('digest', {}).get('nextnonce'), info response2, _ = http.request(uri, 'GET') info2 = httplib2._parse_www_authenticate(response2, 'authentication-info') assert info2.get('digest', {}).get('nc') == '00000002', info2 grenew_nonce[0]() response3, content = http.request(uri, 'GET') info3 = httplib2._parse_www_authenticate(response3, 'authentication-info') assert response3.status == 200 assert info3.get('digest', {}).get('nc') == '00000001', info3
def docheck(commands, storeclass=stores.Store, initialdata={}, storeargs={}): store = storeclass(initialdata.copy(), **storeargs) serverfunc = server.MemcacheServer(store) for request, response in commands: data = server_request(serverfunc, request) assert data == response, '%r != expected %r' % (data, response)
def test_deleting_key_with_associated_tag(): data = {} store = taggingcache.TaggingStore(data, writeable=True) server = taggingcache.taggingserver(store) resp = server_request(server, 'set testkey 0 0 4\r\n' 'blah\r\n') assert resp == 'STORED\r\n' resp = server_request(server, 'tag_add testtag testkey\r\n') assert resp == 'TAG_STORED\r\n' resp = server_request(server, 'delete testkey\r\n') assert resp == 'DELETED\r\n', resp assert 'testkey' not in store.key_tags assert 'testtag' not in store.tags
def test_deleting_tag_with_multiple_keys(): data = {} store = taggingcache.TaggingStore(data, writeable=True) server = taggingcache.taggingserver(store) resp = server_request(server, 'set testkey1 0 0 4\r\n' 'blah\r\n') assert resp == 'STORED\r\n' resp = server_request(server, 'set testkey2 0 0 4\r\n' 'blah\r\n') assert resp == 'STORED\r\n' resp = server_request(server, 'tag_add testtag testkey1\r\n') assert resp == 'TAG_STORED\r\n' resp = server_request(server, 'tag_add testtag testkey2\r\n') assert resp == 'TAG_STORED\r\n' resp = server_request(server, 'tag_delete testtag\r\n') assert resp == 'TAG_DELETED\r\n', resp resp = server_request(server, 'get testkey1\r\n') assert resp == 'END\r\n', resp resp = server_request(server, 'get testkey2\r\n') assert resp == 'END\r\n', resp
def test_etag_used(): # Test that we use ETags properly to validate our cache cache_path = tests.get_cache_path() http = httplib2.Http(cache=cache_path) response_kwargs = dict( add_date=True, add_etag=True, body=b'something', headers={ 'cache-control': 'public,max-age=300', }, ) def handler(request): if request.headers.get('range'): return tests.http_response_bytes(status=206, **response_kwargs) return tests.http_response_bytes(**response_kwargs) with tests.server_request(handler, request_count=2) as uri: response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity'}) assert response['etag'] == '"437b930db84b8079c2dd804a71936b5f"' http.request(uri, 'GET', headers={'accept-encoding': 'identity'}) response, _ = http.request( uri, 'GET', headers={ 'accept-encoding': 'identity', 'cache-control': 'must-revalidate' }, ) assert response.status == 200 assert response.fromcache # TODO: API to read cache item, at least internal to tests cache_file_name = os.path.join( cache_path, httplib2.safename(httplib2.urlnorm(uri)[-1])) with open(cache_file_name, 'r') as f: status_line = f.readline() assert status_line.startswith("status:") response, content = http.request( uri, 'HEAD', headers={'accept-encoding': 'identity'}) assert response.status == 200 assert response.fromcache response, content = http.request(uri, 'GET', headers={ 'accept-encoding': 'identity', 'range': 'bytes=0-0' }) assert response.status == 206 assert not response.fromcache
def test_digest(): # Test that we support Digest Authentication http = httplib2.Http() password = tests.gen_password() handler = tests.http_reflect_with_auth(allow_scheme="digest", allow_credentials=(("joe", password),)) with tests.server_request(handler, request_count=3) as uri: response, content = http.request(uri, "GET") assert response.status == 401 http.add_credentials("joe", password) response, content = http.request(uri, "GET") assert response.status == 200, content.decode()
def test_update_uses_cached_etag_overridden(): # Test that we natively support http://www.w3.org/1999/04/Editing/ http = httplib2.Http(cache=tests.get_cache_path()) with tests.server_request(handler_conditional_update, request_count=2) as uri: response, content = http.request(uri, 'GET') assert response.status == 200 assert not response.fromcache response, content = http.request(uri, 'GET') assert response.status == 200 assert response.fromcache response, content = http.request(uri, 'PUT', body=b'foo', headers={'if-match': 'fred'}) assert response.status == 412
def test_timeout_individual(): def handler(request): time.sleep(0.5) return tests.http_response_bytes() http = httplib2.Http(timeout=0.1) http.force_exception_to_status_code = True with tests.server_request(handler) as uri: response, content = http.request(uri) assert response.status == 408 assert response.reason.startswith("Request Timeout")
def test_basic(): # Test Basic Authentication http = httplib2.Http() password = tests.gen_password() handler = tests.http_reflect_with_auth(allow_scheme='basic', allow_credentials=(('joe', password), )) with tests.server_request(handler, request_count=3) as uri: response, content = http.request(uri, 'GET') assert response.status == 401 http.add_credentials('joe', password) response, content = http.request(uri, 'GET') assert response.status == 200
def test_update_uses_cached_etag_and_oc_method(): # Test that we natively support http://www.w3.org/1999/04/Editing/ http = httplib2.Http(cache=tests.get_cache_path()) with tests.server_request(handler_conditional_update, request_count=2) as uri: response, _ = http.request(uri, 'GET') assert response.status == 200 assert not response.fromcache response, _ = http.request(uri, 'GET') assert response.status == 200 assert response.fromcache http.optimistic_concurrency_methods.append('DELETE') response, _ = http.request(uri, 'DELETE') assert response.status == 200
def test_digest(): # Test that we support Digest Authentication http = httplib2.Http() password = tests.gen_password() handler = tests.http_reflect_with_auth( allow_scheme="digest", allow_credentials=(("joe", password),) ) with tests.server_request(handler, request_count=3) as uri: response, content = http.request(uri, "GET") assert response.status == 401 http.add_credentials("joe", password) response, content = http.request(uri, "GET") assert response.status == 200, content.decode()
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
def test_update_uses_cached_etag_and_oc_method(): # Test that we natively support http://www.w3.org/1999/04/Editing/ http = httplib2.Http(cache=tests.get_cache_path()) with tests.server_request(handler_conditional_update, request_count=2) as uri: response, _ = http.request(uri, "GET") assert response.status == 200 assert not response.fromcache response, _ = http.request(uri, "GET") assert response.status == 200 assert response.fromcache http.optimistic_concurrency_methods.append("DELETE") response, _ = http.request(uri, "DELETE") assert response.status == 200
def test_update_uses_cached_etag(method): # Test that we natively support http://www.w3.org/1999/04/Editing/ http = httplib2.Http(cache=tests.get_cache_path()) with tests.server_request(handler_conditional_update, request_count=3) as uri: response, _ = http.request(uri, 'GET') assert response.status == 200 assert not response.fromcache response, _ = http.request(uri, 'GET') assert response.status == 200 assert response.fromcache response, _ = http.request(uri, method, body=b'foo') assert response.status == 200 response, _ = http.request(uri, method, body=b'foo') assert response.status == 412
def test_basic_for_domain(): # Test Basic Authentication http = httplib2.Http() password = tests.gen_password() handler = tests.http_reflect_with_auth(allow_scheme="basic", allow_credentials=(("joe", password),)) with tests.server_request(handler, request_count=4) as uri: response, content = http.request(uri, "GET") assert response.status == 401 http.add_credentials("joe", password, "example.org") response, content = http.request(uri, "GET") assert response.status == 401 domain = urllib.parse.urlparse(uri)[1] http.add_credentials("joe", password, domain) response, content = http.request(uri, "GET") assert response.status == 200
def test_update_uses_cached_etag(method): # Test that we natively support http://www.w3.org/1999/04/Editing/ http = httplib2.Http(cache=tests.get_cache_path()) with tests.server_request(handler_conditional_update, request_count=3) as uri: response, _ = http.request(uri, "GET") assert response.status == 200 assert not response.fromcache response, _ = http.request(uri, "GET") assert response.status == 200 assert response.fromcache response, _ = http.request(uri, method, body=b"foo") assert response.status == 200 response, _ = http.request(uri, method, body=b"foo") assert response.status == 412
def test_etag_used(): # Test that we use ETags properly to validate our cache cache_path = tests.get_cache_path() http = httplib2.Http(cache=cache_path) response_kwargs = dict( add_date=True, add_etag=True, body=b"something", headers={"cache-control": "public,max-age=300"}, ) def handler(request): if request.headers.get("range"): return tests.http_response_bytes(status=206, **response_kwargs) return tests.http_response_bytes(**response_kwargs) with tests.server_request(handler, request_count=2) as uri: response, _ = http.request(uri, "GET", headers={"accept-encoding": "identity"}) assert response["etag"] == '"437b930db84b8079c2dd804a71936b5f"' http.request(uri, "GET", headers={"accept-encoding": "identity"}) response, _ = http.request( uri, "GET", headers={"accept-encoding": "identity", "cache-control": "must-revalidate"}, ) assert response.status == 200 assert response.fromcache # TODO: API to read cache item, at least internal to tests cache_file_name = os.path.join( cache_path, httplib2.safename(httplib2.urlnorm(uri)[-1]) ) with open(cache_file_name, "r") as f: status_line = f.readline() assert status_line.startswith("status:") response, content = http.request( uri, "HEAD", headers={"accept-encoding": "identity"} ) assert response.status == 200 assert response.fromcache response, content = http.request( uri, "GET", headers={"accept-encoding": "identity", "range": "bytes=0-0"} ) assert response.status == 206 assert not response.fromcache
def test_update_uses_cached_etag_overridden(): # Test that we natively support http://www.w3.org/1999/04/Editing/ http = httplib2.Http(cache=tests.get_cache_path()) with tests.server_request(handler_conditional_update, request_count=2) as uri: response, content = http.request(uri, "GET") assert response.status == 200 assert not response.fromcache response, content = http.request(uri, "GET") assert response.status == 200 assert response.fromcache response, content = http.request(uri, "PUT", body=b"foo", headers={"if-match": "fred"}) assert response.status == 412
def test_connection_close(): http = httplib2.Http() g = [] def handler(request): g.append(request.number) return tests.http_response_bytes(proto="HTTP/1.1") with tests.server_request(handler, request_count=3) as uri: http.request(uri, "GET") # conn1 req1 for c in http.connections.values(): assert c.sock is not None http.request(uri, "GET", headers={"connection": "close"}) time.sleep(0.7) http.request(uri, "GET") # conn2 req1 assert g == [1, 2, 1]
def test_get_301_via_https_spec_violation_on_location(): # Test that we follow redirects through HTTPS # even if they violate the spec by including # a relative Location: header instead of an absolute one. http = httplib2.Http(ca_certs=tests.CA_CERTS) def handler(request): if request.uri == "/final": return tests.http_response_bytes(body=b"final") return tests.http_response_bytes(status="301 goto", headers={"location": "/final"}) with tests.server_request(handler, request_count=2, tls=True) as uri: response, content = http.request(uri, "GET") assert response.status == 200 assert content == b"final" assert response.previous.status == 301
def test_get_301_via_https(): http = httplib2.Http(ca_certs=tests.CA_CERTS) glocation = [""] # nonlocal kind of trick, maybe redundant def handler(request): if request.uri == "/final": return tests.http_response_bytes(body=b"final") return tests.http_response_bytes(status="301 goto", headers={"location": glocation[0]}) with tests.server_request(handler, request_count=2, tls=True) as uri: glocation[0] = urllib.parse.urljoin(uri, "/final") response, content = http.request(uri, "GET") assert response.status == 200 assert content == b"final" assert response.previous.status == 301 assert response.previous["location"] == glocation[0]
def test_basic_two_credentials(): # Test Basic Authentication with multiple sets of credentials http = httplib2.Http() password1 = tests.gen_password() password2 = tests.gen_password() allowed = [("joe", password1)] # exploit shared mutable list handler = tests.http_reflect_with_auth(allow_scheme="basic", allow_credentials=allowed) with tests.server_request(handler, request_count=7) as uri: http.add_credentials("fred", password2) response, content = http.request(uri, "GET") assert response.status == 401 http.add_credentials("joe", password1) response, content = http.request(uri, "GET") assert response.status == 200 allowed[0] = ("fred", password2) response, content = http.request(uri, "GET") assert response.status == 200
def test_basic_for_domain(): # Test Basic Authentication http = httplib2.Http() password = tests.gen_password() handler = tests.http_reflect_with_auth( allow_scheme="basic", allow_credentials=(("joe", password),) ) with tests.server_request(handler, request_count=4) as uri: response, content = http.request(uri, "GET") assert response.status == 401 http.add_credentials("joe", password, "example.org") response, content = http.request(uri, "GET") assert response.status == 401 domain = urllib.parse.urlparse(uri)[1] http.add_credentials("joe", password, domain) response, content = http.request(uri, "GET") assert response.status == 200
def test_timeout_global(): def handler(request): time.sleep(0.5) return tests.http_response_bytes() try: socket.setdefaulttimeout(0.1) except Exception: pytest.skip("cannot set global socket timeout") try: http = httplib2.Http() http.force_exception_to_status_code = True with tests.server_request(handler) as uri: response, content = http.request(uri) assert response.status == 408 assert response.reason.startswith("Request Timeout") finally: socket.setdefaulttimeout(None)
def test_wsse_ok(): http = httplib2.Http() username = "******" password = tests.gen_password() grenew_nonce = [None] requests = [] handler = tests.http_reflect_with_auth( allow_scheme="wsse", allow_credentials=((username, password),), out_renew_nonce=grenew_nonce, out_requests=requests, ) http.add_credentials(username, password) with tests.server_request(handler, request_count=2) as uri: response, _ = http.request(uri) assert requests[0][1].status == 401 assert requests[1][0].headers["authorization"] == 'WSSE profile="UsernameToken"' assert response.status == 200
def test_basic_two_credentials(): # Test Basic Authentication with multiple sets of credentials http = httplib2.Http() password1 = tests.gen_password() password2 = tests.gen_password() allowed = [("joe", password1)] # exploit shared mutable list handler = tests.http_reflect_with_auth( allow_scheme="basic", allow_credentials=allowed ) with tests.server_request(handler, request_count=7) as uri: http.add_credentials("fred", password2) response, content = http.request(uri, "GET") assert response.status == 401 http.add_credentials("joe", password1) response, content = http.request(uri, "GET") assert response.status == 200 allowed[0] = ("fred", password2) response, content = http.request(uri, "GET") assert response.status == 200
def test_update_invalidates_cache(): # Test that calling PUT or DELETE on a # URI that is cache invalidates that cache. http = httplib2.Http(cache=tests.get_cache_path()) def handler(request): if request.method in ('PUT', 'PATCH', 'DELETE'): return tests.http_response_bytes(status=405) return tests.http_response_bytes( add_date=True, add_etag=True, headers={'cache-control': 'max-age=300'}) with tests.server_request(handler, request_count=3) as uri: response, _ = http.request(uri, 'GET') response, _ = http.request(uri, 'GET') assert response.fromcache response, _ = http.request(uri, 'DELETE') assert response.status == 405 assert not response.fromcache response, _ = http.request(uri, 'GET') assert not response.fromcache
def test_client_cert_verified(): cert_log = [] def setup_tls(context, server, skip_errors): context.load_verify_locations(cafile=tests.CA_CERTS) context.verify_mode = ssl.CERT_REQUIRED return context.wrap_socket(server, server_side=True) def handler(request): cert_log.append(request.client_sock.getpeercert()) return tests.http_response_bytes() http = httplib2.Http(ca_certs=tests.CA_CERTS) with tests.server_request(handler, tls=setup_tls) as uri: uri_parsed = urllib.parse.urlparse(uri) http.add_certificate(tests.CLIENT_PEM, tests.CLIENT_PEM, uri_parsed.netloc) http.request(uri) assert len(cert_log) == 1 # TODO extract serial from tests.CLIENT_PEM assert cert_log[0]["serialNumber"] == "E2AA6A96D1BF1AEC"
def test_update_invalidates_cache(): # Test that calling PUT or DELETE on a # URI that is cache invalidates that cache. http = httplib2.Http(cache=tests.get_cache_path()) def handler(request): if request.method in ("PUT", "PATCH", "DELETE"): return tests.http_response_bytes(status=405) return tests.http_response_bytes( add_date=True, add_etag=True, headers={"cache-control": "max-age=300"}) with tests.server_request(handler, request_count=3) as uri: response, _ = http.request(uri, "GET") response, _ = http.request(uri, "GET") assert response.fromcache response, _ = http.request(uri, "DELETE") assert response.status == 405 assert not response.fromcache response, _ = http.request(uri, "GET") assert not response.fromcache
def test_timeout_subsequent(): class Handler(object): number = 0 @classmethod def handle(cls, request): # request.number is always 1 because of # the new socket connection each time cls.number += 1 if cls.number % 2 != 0: time.sleep(0.6) return tests.http_response_bytes(status=500) return tests.http_response_bytes(status=200) http = httplib2.Http(timeout=0.5) http.force_exception_to_status_code = True with tests.server_request(Handler.handle, request_count=2) as uri: response, _ = http.request(uri) assert response.status == 408 assert response.reason.startswith("Request Timeout") response, _ = http.request(uri) assert response.status == 200