コード例 #1
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_dnsResolve_propagation(self):
     """
     dnsResolve must return an empty string now we use dukpy, otherwise
     None value causes dukpy error as it propagates
     """
     parser = PACFile(dummy_js % 'isInNet(dnsResolve(host), "10.1.1.0", "255.255.255.0")')
     assert parser.find_proxy_for_url('$%$', '$%$') == 'PROXY 0.0.0.0:80'
コード例 #2
0
def get_pac(url=None, js=None, from_os_settings=True, from_dns=True, timeout=2,
            allowed_content_types=None, session=None, **kwargs):
    """
    Convenience function for finding and getting a parsed PAC file (if any) that's ready to use.

    :param str url: Download PAC from a URL.
        If provided, `from_os_settings` and `from_dns` are ignored.
    :param str js: Parse the given string as a PAC file.
        If provided, `from_os_settings` and `from_dns` are ignored.
    :param bool from_os_settings: Look for a PAC URL or filesystem path from the OS settings, and use it if present.
        Doesn't do anything on non-Windows or non-macOS/OSX platforms.
    :param bool from_dns: Look for a PAC file using the WPAD protocol.
    :param timeout: Time to wait for host resolution and response for each URL.
    :param allowed_content_types: If the response has a ``Content-Type`` header,
        then consider the response to be a PAC file only if the header is one of these values.
        If not specified, the allowed types are
        ``application/x-ns-proxy-autoconfig`` and ``application/x-javascript-config``.
    :return: The first valid parsed PAC file according to the criteria, or `None` if nothing was found.
    :rtype: PACFile|None
    :raises MalformedPacError: If something that claims to be a PAC file was obtained but could not be parsed.
    """
    if url:
        downloaded_pac = download_pac([url], timeout=timeout,
                                      allowed_content_types=allowed_content_types,
                                      session=session)
        if not downloaded_pac:
            return
        return PACFile(downloaded_pac, **kwargs)
    if js:
        return PACFile(js, **kwargs)

    # Deprecated in 0.8.2
    from_registry = kwargs.get('from_registry')
    if from_registry is not None:
        import warnings
        warnings.warn('from_registry is deprecated, use from_os_settings instead.')
        from_os_settings = from_registry

    if from_os_settings:
        if ON_WINDOWS:
            path = autoconfig_url_from_registry()
        elif ON_DARWIN:
            path = autoconfig_url_from_preferences()
        else:
            path = None

        if path and path.lower().startswith('file://'):
            path = file_url_to_local_path(path)

        if path and os.path.isfile(path):
            with open(path) as f:
                return PACFile(f.read(), **kwargs)

    pac_candidate_urls = collect_pac_urls(from_os_settings=True, from_dns=from_dns)
    downloaded_pac = download_pac(pac_candidate_urls, timeout=timeout, allowed_content_types=allowed_content_types, session=session)
    if not downloaded_pac:
        return
    return PACFile(downloaded_pac, **kwargs)
コード例 #3
0
ファイル: test_parser.py プロジェクト: zanachka/pypac
 def test_dnsResolve_propagation(self):
     """
     dnsResolve must return an empty string now we use dukpy, otherwise
     None value causes dukpy error as it propagates
     """
     parser = PACFile(
         dummy_js %
         'isInNet(dnsResolve(host), "10.1.1.0", "255.255.255.0")')
     assert parser.find_proxy_for_url("$%$", "$%$") == "PROXY 0.0.0.0:80"
コード例 #4
0
def get_pac(url=None,
            js=None,
            from_registry=True,
            from_dns=True,
            timeout=2,
            allowed_content_types=None,
            **kwargs):
    """
    Convenience function for finding and getting a parsed PAC file (if any) that's ready to use.

    :param str url: Download PAC from a URL.
        If provided, `from_registry` and `from_dns` are ignored.
    :param str js: Parse the given string as a PAC file.
        If provided, `from_registry` and `from_dns` are ignored.
    :param bool from_registry: Look for a PAC URL or filesystem path from the Windows Registry, and use it if present.
        Doesn't do anything on non-Windows platforms.
    :param bool from_dns: Look for a PAC file using the WPAD protocol.
    :param timeout: Time to wait for host resolution and response for each URL.
    :param allowed_content_types: Consider PAC file response to be valid only
        if the server responds with one of these content types.
        If not specified, the allowed types are
        ``application/x-ns-proxy-autoconfig`` and ``application/x-javascript-config``.
    :return: The first valid parsed PAC file according to the criteria, or `None` if nothing was found.
    :rtype: PACFile|None
    :raises MalformedPacError: If something that claims to be a PAC file was obtained but could not be parsed.
    """
    if url:
        downloaded_pac = download_pac(
            [url],
            timeout=timeout,
            allowed_content_types=allowed_content_types)
        if not downloaded_pac:
            return
        return PACFile(downloaded_pac, **kwargs)
    if js:
        return PACFile(js, **kwargs)

    if from_registry and ON_WINDOWS:
        path = autoconfig_url_from_registry()
        if path and os.path.isfile(path):
            with open(path) as f:
                return PACFile(f.read(), **kwargs)

    pac_candidate_urls = collect_pac_urls(from_registry=True,
                                          from_dns=from_dns)
    downloaded_pac = download_pac(pac_candidate_urls,
                                  timeout=timeout,
                                  allowed_content_types=allowed_content_types)
    if not downloaded_pac:
        return
    return PACFile(downloaded_pac, **kwargs)
コード例 #5
0
ファイル: test_api.py プロジェクト: SeyfSV/pypac
 def test_pac(self, monkeypatch):
     monkeypatch.setenv('HTTP_PROXY', 'http://env')
     with _patch_get_pac(PACFile(proxy_pac_js)):
         with pac_context_for_url(arbitrary_url):
             assert os.environ['HTTP_PROXY'] == fake_proxy_url
             assert os.environ['HTTPS_PROXY'] == fake_proxy_url
     assert os.environ['HTTP_PROXY'] == 'http://env'
コード例 #6
0
ファイル: test_api.py プロジェクト: SeyfSV/pypac
 def test_pac_direct(self, monkeypatch):
     monkeypatch.setenv('HTTP_PROXY', 'http://env')
     with _patch_get_pac(PACFile(proxy_pac_js_tpl % 'DIRECT')):
         with pac_context_for_url(arbitrary_url):
             assert os.environ['HTTP_PROXY'] == ''
             assert os.environ['HTTPS_PROXY'] == ''
     assert os.environ['HTTP_PROXY'] == 'http://env'
コード例 #7
0
def test_url_host_port_excluded():
    res = ProxyResolver(
        PACFile(
            'function FindProxyForURL(url, host) { return host.indexOf(" ") == -1 ? "PROXY PASS:80" : "PROXY FAIL:80"; }'
        ))
    for url in ('http://foo/bar', 'http://foo:80/bar'):
        assert res.get_proxy(url) == 'http://PASS:80'
コード例 #8
0
ファイル: test_api.py プロジェクト: zanachka/pypac
 def test_pac_direct(self, monkeypatch):
     monkeypatch.setenv("HTTP_PROXY", "http://env")
     with _patch_get_pac(PACFile(proxy_pac_js_tpl % "DIRECT")):
         with pac_context_for_url(arbitrary_url):
             assert os.environ["HTTP_PROXY"] == ""
             assert os.environ["HTTPS_PROXY"] == ""
     assert os.environ["HTTP_PROXY"] == "http://env"
コード例 #9
0
 def _load_pac(self, force_download=False):
     if not os.path.isfile("m100.pac") or force_download:
         pac_content = self._download_pac()
         with open("m100.pac", "w") as f:
             f.write(pac_content.decode("utf8"))
     with open("m100.pac", "r") as f:
         pac = PACFile(f.read())
     return pac
コード例 #10
0
ファイル: test_parser.py プロジェクト: zanachka/pypac
 def test_pac_callstack_limit(self):
     """
     Try to load a PAC file that hits the Duktape call stack limit.
     """
     pac_js = 'function FindProxyForURL(url, host) {function b() {a();} function a() {b();}; a(); return "DIRECT";}'
     with pytest.raises(MalformedPacError) as e:
         PACFile(pac_js)
     assert "callstack limit" in str(e.value)
コード例 #11
0
 def test_pac_override_using_request_proxies_parameter(self):
     sess = PACSession()
     mock_ok = Mock(spec=requests.Response, status_code=204)
     with _patch_get_pac(PACFile(proxy_pac_js)), \
          _patch_request_base(mock_ok) as request:
         for proxies_arg in ({}, proxy_parameter_for_requests('http://manual:80')):
             sess.get(arbitrary_url, proxies=proxies_arg)
             request.assert_called_with('GET', arbitrary_url, proxies=proxies_arg, allow_redirects=ANY)
コード例 #12
0
 def test_default_behaviour_pac_found(self):
     sess = PACSession()
     mock_ok = Mock(spec=requests.Response, status_code=204)
     with _patch_get_pac(PACFile(proxy_pac_js)), \
          _patch_request_base(mock_ok) as request:
         assert sess.get(arbitrary_url).status_code == 204
         request.assert_called_with('GET', arbitrary_url,
                                    proxies=fake_proxies_requests_arg,
                                    allow_redirects=ANY)
コード例 #13
0
 def test_pac_no_failover_available_exc_case(self):
     """Special case where proxy fails but there's no DIRECT fallback. Error should bubble up,
     and all applicable proxies should be tried again in the next request. Proxy failure from exception."""
     sess = PACSession(pac=PACFile(proxy_pac_js_tpl % 'PROXY a:80; PROXY b:80'))
     for _ in range(2):
         with _patch_request_base(side_effect=ProxyError()) as request, \
                 pytest.raises(ProxyError):
             sess.get(arbitrary_url)
         request.assert_has_calls([
             get_call(arbitrary_url, 'http://a:80'),
             get_call(arbitrary_url, 'http://b:80'),
         ])
コード例 #14
0
    def test_large_pac_handling(self):
        """
        Try to load a large PAC file that triggers Js2Py hitting the Python recursion limit.
        Ensure it raises a more useful message.

        Note that unrecoverable stack overflows are possible, where this message won't be raised.
        See https://github.com/carsonyl/pypac/issues/8.
        """
        pac_js = 'function FindProxyForURL(url, host) { if(%s) { return "DIRECT"; } }' % \
                 ' || '.join(200 * ['shExpMatch(host, "*.example.com")'])
        with pytest.raises(PacComplexityError):
            PACFile(pac_js, recursion_limit=1000)
コード例 #15
0
 def test_pac_disabled(self):
     sess = PACSession(pac_enabled=False)
     mock_ok = Mock(spec=requests.Response, status_code=204)
     with _patch_get_pac(PACFile(proxy_pac_js)) as gp, \
             _patch_request_base(mock_ok) as request:
         assert sess.get(arbitrary_url).status_code == 204
         gp.assert_not_called()
         request.assert_called_with('GET', arbitrary_url, proxies=None, allow_redirects=ANY)
         # When re-enabled, PAC discovery should proceed and be honoured.
         sess.pac_enabled = True
         assert sess.get(arbitrary_url).status_code == 204
         gp.assert_called_with(recursion_limit=ARBITRARY_HIGH_RECURSION_LIMIT)
         request.assert_called_with('GET', arbitrary_url, proxies=fake_proxies_requests_arg, allow_redirects=ANY)
コード例 #16
0
ファイル: test_api.py プロジェクト: SeyfSV/pypac
 def test_pac_failover_to_direct_also_fails(self):
     """Proxy fails. Next in line is DIRECT keyword, but direct connection also fails. Error should bubble up.
     Subsequent requests go straight to DIRECT, despite DIRECT failing."""
     sess = PACSession(pac=PACFile(proxy_pac_js))
     with _patch_request_base(side_effect=ProxyError()) as request:
         for _ in range(2):
             with pytest.raises(ProxyError):
                 sess.get(arbitrary_url)
     request.assert_has_calls([
         get_call(arbitrary_url, fake_proxy_url),
         get_call(arbitrary_url, 'DIRECT'),
         get_call(arbitrary_url, 'DIRECT'),
     ])
コード例 #17
0
    def test_pac_failover_to_direct(self):
        """Proxy fails. Next in line is DIRECT keyword."""
        sess = PACSession(pac=PACFile(proxy_pac_js))

        def fake_request_reject_proxy(method, url, proxies=None, **kwargs):
            if proxies and proxies['http'] is not None:
                raise ProxyError()

        with _patch_request_base(side_effect=fake_request_reject_proxy) as request:
            sess.get(arbitrary_url)
            request.assert_has_calls([
                get_call(arbitrary_url, fake_proxy_url),
                get_call(arbitrary_url, 'DIRECT'),
            ])
コード例 #18
0
    def test_pac_failover(self):
        """First proxy raises error. Transparently fail over to second proxy."""
        sess = PACSession(pac=PACFile(proxy_pac_js_tpl % 'PROXY a:80; PROXY b:80; DIRECT'))

        def fake_request(method, url, proxies=None, **kwargs):
            if proxies and proxies['http'] == 'http://a:80':
                raise ProxyError()

        with _patch_request_base(side_effect=fake_request) as request:
            sess.get(arbitrary_url)
            request.assert_has_calls([
                get_call(arbitrary_url, 'http://a:80'),
                get_call(arbitrary_url, 'http://b:80'),
            ])
コード例 #19
0
ファイル: test_api.py プロジェクト: SeyfSV/pypac
    def test_post_init_proxy_auth(self):
        """Set proxy auth info after constructing PACSession, and ensure that PAC proxy URLs then reflect it."""
        sess = PACSession(pac=PACFile(proxy_pac_js_tpl % 'PROXY a:80;'))
        with _patch_request_base() as request:
            sess.get(arbitrary_url)  # Prime proxy resolver state.
            request.assert_has_calls([
                get_call(arbitrary_url, 'http://*****:*****@a:80'),
            ])
コード例 #20
0
    def test_failover_using_custom_response_filter(self):
        """Use a custom response filter to say that HTTP 407 responses are considered a proxy failure,
        in order to trigger proxy failover."""

        def custom_response_filter(response): return response.status_code == 407

        proxy_fail_resp = Mock(spec=requests.Response, status_code=407)
        sess = PACSession(pac=PACFile(proxy_pac_js_tpl % 'PROXY a:80; PROXY b:80'),
                          response_proxy_fail_filter=custom_response_filter)
        with _patch_request_base(proxy_fail_resp) as request:
            # Both proxies failed due to 407 response, so return value is the same 407.
            assert sess.get(arbitrary_url).status_code == 407
            request.assert_has_calls([
                get_call(arbitrary_url, 'http://a:80'),
                get_call(arbitrary_url, 'http://b:80'),
            ])
コード例 #21
0
    def test_failover_using_custom_exception_criteria(self):
        """Use a custom request exception filter to say that some arbitrary exception is considered a proxy failure,
        in order to trigger proxy failover."""

        def custom_exc_filter(exc): return isinstance(exc, NotImplementedError)

        def fake_request(method, url, proxies=None, **kwargs):
            if proxies and proxies['http'] == 'http://a:80':
                raise NotImplementedError()

        sess = PACSession(pac=PACFile(proxy_pac_js_tpl % 'PROXY a:80; PROXY b:80'),
                          exception_proxy_fail_filter=custom_exc_filter)

        with _patch_request_base(side_effect=fake_request) as request:
            sess.get(arbitrary_url)
            request.assert_has_calls([
                get_call(arbitrary_url, 'http://a:80'),
                get_call(arbitrary_url, 'http://b:80'),
            ])
コード例 #22
0
 def test_pyimport(self, pac_js):
     with pytest.raises(PyimportError):
         PACFile(pac_js)
コード例 #23
0
 def test_malformed_pac_files(self, value):
     with pytest.raises(MalformedPacError):
         PACFile(value)
コード例 #24
0
 def test_valid_js_function_signatures(self, pac_js):
     pac = PACFile(pac_js)
     assert pac.find_proxy_for_url('/', 'example.com') == 'DIRECT'
コード例 #25
0
 def test_shExpMatch(self):
     parser = PACFile(dummy_js % 'shExpMatch(host, "*.example.com")')
     assert parser.find_proxy_for_url('/', 'www.example.com') == 'DIRECT'
     assert parser.find_proxy_for_url('/', 'www.example.org') == 'PROXY 0.0.0.0:80'
コード例 #26
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_dnsDomainIs(self):
     parser = PACFile(dummy_js % 'dnsDomainIs(host, "*.example.com")')
     assert parser.find_proxy_for_url('/', 'www.example.com') == 'DIRECT'
コード例 #27
0
 def test_localHostOrDomainIs(self):
     parser = PACFile(dummy_js % 'localHostOrDomainIs(host, "www.netscape.com")')
     assert parser.find_proxy_for_url('/', 'www') == 'DIRECT'
コード例 #28
0
 def test_isResolvable(self):
     parser = PACFile(dummy_js % 'isResolvable(host)')
     assert parser.find_proxy_for_url('/', 'www.google.com') == 'DIRECT'
     assert parser.find_proxy_for_url('/', 'bogus.domain.local') != 'DIRECT'
コード例 #29
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_isPlainHostName(self):
     parser = PACFile(dummy_js % 'isPlainHostName(host)')
     assert parser.find_proxy_for_url('/', 'google.com') != 'DIRECT'
     assert parser.find_proxy_for_url('/', 'foobar') == 'DIRECT'
コード例 #30
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_shExpMatch(self):
     parser = PACFile(dummy_js % 'shExpMatch(host, "*.example.com")')
     assert parser.find_proxy_for_url('/', 'www.example.com') == 'DIRECT'
     assert parser.find_proxy_for_url('/', 'www.example.org') == 'PROXY 0.0.0.0:80'
コード例 #31
0
 def test_builtins_undefined(self, pac_js):
     with pytest.raises(MalformedPacError):
         PACFile(pac_js)
コード例 #32
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_dnsDomainLevels(self):
     parser = PACFile(dummy_js % 'dnsDomainLevels(host)')
     assert parser.find_proxy_for_url('/', 'google.com') == 'DIRECT'
     assert parser.find_proxy_for_url('/', 'foobar') != 'DIRECT'
コード例 #33
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_dnsResolve(self):
     js = 'function FindProxyForURL(url, host) {return "PROXY " + dnsResolve(host) + ":80"; }'
     parser = PACFile(js)
     assert parser.find_proxy_for_url('/', 'www.google.com') is not None
コード例 #34
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_isResolvable(self):
     parser = PACFile(dummy_js % 'isResolvable(host)')
     assert parser.find_proxy_for_url('/', 'www.google.com') == 'DIRECT'
     assert parser.find_proxy_for_url('/', 'bogus.domain.local') != 'DIRECT'
コード例 #35
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_valid_js_function_signatures(self, pac_js):
     pac = PACFile(pac_js)
     assert pac.find_proxy_for_url('/', 'example.com') == 'DIRECT'
コード例 #36
0
 def test_dnsDomainIs(self):
     parser = PACFile(dummy_js % 'dnsDomainIs(host, "*.example.com")')
     assert parser.find_proxy_for_url('/', 'www.example.com') == 'DIRECT'
コード例 #37
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_isInNet(self):
     parser = PACFile(dummy_js % 'isInNet(host, "0.0.0.0", "0.0.0.0")')
     assert parser.find_proxy_for_url('/', 'www.google.com') == 'DIRECT'
コード例 #38
0
 def test_isInNet(self):
     parser = PACFile(dummy_js % 'isInNet(host, "0.0.0.0", "0.0.0.0")')
     assert parser.find_proxy_for_url('/', 'www.google.com') == 'DIRECT'
コード例 #39
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_localHostOrDomainIs(self):
     parser = PACFile(dummy_js % 'localHostOrDomainIs(host, "www.netscape.com")')
     assert parser.find_proxy_for_url('/', 'www') == 'DIRECT'
コード例 #40
0
 def test_myIpAddress(self):
     js = 'function FindProxyForURL(url, host) {return "PROXY " + myIpAddress() + ":80"; }'
     parser = PACFile(js)
     assert parser.find_proxy_for_url('/', 'www.example.com') is not None
コード例 #41
0
ファイル: test_parser.py プロジェクト: rbcarson/pypac
 def test_myIpAddress(self):
     js = 'function FindProxyForURL(url, host) {return "PROXY " + myIpAddress() + ":80"; }'
     parser = PACFile(js)
     assert parser.find_proxy_for_url('/', 'www.example.com') is not None