Merge lp:~xnox/launchpadlib/proxy into lp:launchpadlib

Proposed by Dimitri John Ledkov
Status: Rejected
Rejected by: Dimitri John Ledkov
Proposed branch: lp:~xnox/launchpadlib/proxy
Merge into: lp:launchpadlib
Diff against target: 106 lines (+50/-0)
1 file modified
src/launchpadlib/launchpad.py (+50/-0)
To merge this branch: bzr merge lp:~xnox/launchpadlib/proxy
Reviewer Review Type Date Requested Status
Dimitri John Ledkov Needs Resubmitting
Barry Warsaw Needs Fixing
William Grant Pending
Colin Watson Pending
Review via email: mp+241176@code.launchpad.net

Description of the change

i hate proxies.

To post a comment you must log in.
lp:~xnox/launchpadlib/proxy updated
138. By Dimitri John Ledkov

Support proxy settings.

Revision history for this message
Barry Warsaw (barry) wrote :

Can you devise some tests for this change?

review: Needs Fixing
Revision history for this message
Dimitri John Ledkov (xnox) wrote :

So I went to look at writting tests for this. I wanted to do something simple - set environment, initialise Launchpad object and check the proxy that is used by underlying http technology.

This got me digging through all the objects involved all the way down to httplib2.Http class that is the ultimate consumer of the proxy_info variable.

At this point I have also discovered that we are overriding the proxy_info default to None - which in httplib2.Http speak has meaning "do not use proxy". The other option is to provide a static ProxyInfo definition (as done in this branch) which would make the proxy settings stick through the lifecycle on the initialised object.

The default for httplib2.Http however is to pass a callable as proxy_info which accepts method as a parameter and determines the proxy settings on the fly. The default implementation of such a callable is httplib2.Http.proxy_from_the_environment(method="http"). Thus I'm proposing to stop overriding proxy_info to value None (aka "No proxy") and instead switch the default value of proxy_info to httplib2.Http.proxy_from_the_environment, as that's what the default value of proxy_info is in the httplib2.Http class which we are subclassing across the stack.

review: Needs Resubmitting

Unmerged revisions

138. By Dimitri John Ledkov

Support proxy settings.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/launchpadlib/launchpad.py'
2--- src/launchpadlib/launchpad.py 2014-07-03 10:44:33 +0000
3+++ src/launchpadlib/launchpad.py 2014-11-08 12:04:34 +0000
4@@ -24,10 +24,20 @@
5 import os
6 try:
7 from urllib.parse import urlsplit
8+ from urllib.parse import urlparse
9 except:
10 from urlparse import urlsplit
11+ from urlparse import urlparse
12 import warnings
13
14+try:
15+ import socks
16+ import libproxy
17+ from httplib2 import ProxyInfo
18+ _proxy_support = True
19+except ImportError:
20+ _proxy_support = False
21+
22 from lazr.restfulclient.resource import (
23 CollectionWithKeyBasedLookup,
24 HostedFile, # Re-import for client convenience
25@@ -53,6 +63,34 @@
26 OAUTH_REALM = 'https://api.launchpad.net'
27
28
29+def _auto_detect_proxy(url):
30+ if not _proxy_support:
31+ return None
32+
33+ protocol_map = {
34+ 'http': socks.PROXY_TYPE_HTTP,
35+ 'socks': socks.PROXY_TYPE_SOCKS5,
36+ 'socks5': socks.PROXY_TYPE_SOCKS5,
37+ 'socks4': socks.PROXY_TYPE_SOCKS4,
38+ }
39+
40+ pf = libproxy.ProxyFactory()
41+ proxies = pf.getProxies(url)
42+ for proxy in proxies:
43+ proxy_components = urlparse(proxy)
44+ protocol = protocol_map.get(proxy_components.scheme, None)
45+ if protocol is None:
46+ return None
47+
48+ return ProxyInfo(
49+ protocol,
50+ proxy_components.hostname,
51+ proxy_components.port,
52+ proxy_user=proxy_components.username,
53+ proxy_pass=proxy_components.password,
54+ )
55+
56+
57 class PersonSet(CollectionWithKeyBasedLookup):
58 """A custom subclass capable of person lookup by username."""
59
60@@ -181,6 +219,8 @@
61 :type service_root: string
62 """
63 service_root = uris.lookup_service_root(service_root)
64+ if proxy_info is None:
65+ proxy_info = _auto_detect_proxy(service_root)
66 if (service_root.endswith(version)
67 or service_root.endswith(version + '/')):
68 error = ("It looks like you're using a service root that "
69@@ -201,6 +241,8 @@
70 credentials, service_root, cache, timeout, proxy_info, version)
71
72 def httpFactory(self, credentials, cache, timeout, proxy_info):
73+ if proxy_info is None:
74+ proxy_info = _auto_detect_proxy(str(self._root_uri))
75 return LaunchpadOAuthAwareHttp(
76 self, self.authorization_engine, credentials, cache, timeout,
77 proxy_info)
78@@ -358,6 +400,9 @@
79 credentials.consumer.application_name = (
80 authorization_engine.application_name)
81
82+ if proxy_info is None:
83+ proxy_info = _auto_detect_proxy(service_root)
84+
85 return cls(credentials, authorization_engine, credential_store,
86 service_root, cache, timeout, proxy_info, version)
87
88@@ -369,6 +414,8 @@
89 """Get access to Launchpad without providing any credentials."""
90 (service_root, launchpadlib_dir, cache_path,
91 service_root_dir) = cls._get_paths(service_root, launchpadlib_dir)
92+ if proxy_info is None:
93+ proxy_info = _auto_detect_proxy(service_root)
94 token = AnonymousAccessToken()
95 credentials = Credentials(consumer_name, access_token=token)
96 return cls(credentials, None, None, service_root=service_root,
97@@ -482,6 +529,9 @@
98 (service_root, launchpadlib_dir, cache_path,
99 service_root_dir) = cls._get_paths(service_root, launchpadlib_dir)
100
101+ if proxy_info is None:
102+ proxy_info = _auto_detect_proxy(service_root)
103+
104 if (application_name is None and consumer_name is None and
105 authorization_engine is None):
106 raise ValueError(

Subscribers

People subscribed via source and target branches