Сразу оговоримся, что речь идет о Python 2.X.
Задача: заставить xmlrpclib в Python работать через прокси-сервер с авторизацией Basic и NTLM, а также с хостом, требующим авторизацию и Cookies.
Мне это было нужно для системы багрепортов в нашем приложении, где при отправки сообщения об ошибке в TRAC должен создаваться тикет с описанием, логами, и прочим. Общение с TRAC'ом идет как раз через xmlRPC (используя XmlRpcPlugin). Пользователи приложения в основном работают за прокси-сервером внутри корпоративной сети.
Реализуется это через создание транспорта на основе urllib, который перенаправляет XML-запросы через прокси-сервер.
В интернете можно найти пару примеров для поддержки прокси без авторизации, написанных на первом urllib. Сначала я попытался взять такой пример и добавить к нему авторизацию, но в итоге стало понятно, что лучше переписать его под urllib2, где это сделать гораздо проще.
Данный вариант транспорта поддерживает также работу без прокси-сервера (если прямое соединение доступно, а указанный прокси-сервер — нет, то соединение произойдет напрямую — это особенность urllib2).
Для поддержки NTLM-авторизации используется python-ntlm.
На всякий случай предупреждаю, что код представлен только в качестве примера и требует обязательного тестирования и модификации под ваши нужды.
Пример использования:
Сам скрипт транспорта:
P.S.
Для всех, кто интересуется urllib2, рекомендую посмотреть urllib2 — The Missing Manual — отличный документ, где подробно описаны особенности работы с ним, в частности, обработка ошибок и исключений.
Задача: заставить xmlrpclib в Python работать через прокси-сервер с авторизацией Basic и NTLM, а также с хостом, требующим авторизацию и Cookies.
Мне это было нужно для системы багрепортов в нашем приложении, где при отправки сообщения об ошибке в TRAC должен создаваться тикет с описанием, логами, и прочим. Общение с TRAC'ом идет как раз через xmlRPC (используя XmlRpcPlugin). Пользователи приложения в основном работают за прокси-сервером внутри корпоративной сети.
Реализуется это через создание транспорта на основе urllib, который перенаправляет XML-запросы через прокси-сервер.
В интернете можно найти пару примеров для поддержки прокси без авторизации, написанных на первом urllib. Сначала я попытался взять такой пример и добавить к нему авторизацию, но в итоге стало понятно, что лучше переписать его под urllib2, где это сделать гораздо проще.
Данный вариант транспорта поддерживает также работу без прокси-сервера (если прямое соединение доступно, а указанный прокси-сервер — нет, то соединение произойдет напрямую — это особенность urllib2).
Для поддержки NTLM-авторизации используется python-ntlm.
На всякий случай предупреждаю, что код представлен только в качестве примера и требует обязательного тестирования и модификации под ваши нужды.
Пример использования:
Copy Source | Copy HTML
- serverURL = "http://some.server.com/xmlrpc"
-
- xmlTransport= UrllibTransport()
- server = xmlrpclib.ServerProxy(serverURL, transport = xmlTransport)
Сам скрипт транспорта:
Copy Source | Copy HTML
- # -*- coding: utf8 -*-
-
- # Requires python-ntlm (http://code.google.com/p/python-ntlm/) package
- from ntlm import HTTPNtlmAuthHandler
-
- import sys, os, tempfile, pickle
- import xmlrpclib, getpass, string
- import base64, urllib2, cookielib
- from urllib import unquote, splittype, splithost, getproxies
- import urllib2
-
- #################################
-
- useProxy = True
- useAuthOnProxy = True
-
- proxyUser = "username"
- proxyPassword = "password"
- proxyServer = "http://proxy.org:3128"
-
- httpAuthName = "user"
- httpAuthPassword = "password"
- serverTopLevelURL = "http://my.server.com"
-
- #################################
-
- class UrllibTransport(xmlrpclib.Transport):
- def request(self, host, handler, request_body, verbose= 0):
- self.verbose = verbose
-
- if useProxy:
- if useAuthOnProxy:
- self.proxyurl = "http://" + proxyUser + ":" \
- + proxyPassword + "@" \
- + proxyServer[7:]
- else:
- self.proxyurl = proxyServer
- else:
- self.proxyurl = None
-
- puser_pass = None
-
- if self.proxyurl is not None:
- type, r_type = splittype(self.proxyurl)
- phost, XXX = splithost(r_type)
-
- if '@' in phost:
- user_pass, phost = phost.split('@', 1)
- if ':' in user_pass:
- user, password = user_pass.split(':', 1)
- puser_pass = base64.encodestring(
- '%s:%s' % (unquote(user),unquote(password))).strip()
-
- proxies = {'http':'http://%s' % phost}
-
- host = unquote(host)
- address = "http://%s%s" % (host, handler)
-
- request = urllib2.Request(address)
- request.add_data(request_body)
- request.add_header('User-agent', self.user_agent)
- request.add_header("Content-Type", "text/xml")
-
- # HTTP Auth
- password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
- top_level_url = serverTopLevelURL
- password_mgr.add_password(None,
- top_level_url,
- httpAuthName,
- httpAuthPassword)
- handler = urllib2.HTTPBasicAuthHandler(password_mgr)
-
- # Cookies
- cj = cookielib.CookieJar()
-
- if puser_pass:
- # NTLM
- passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
- passman.add_password(None, serverTopLevelURL, user, password)
-
- authNTLM = HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman)
- request.add_header('Proxy-authorization', 'Basic ' + puser_pass)
-
- proxy_support = urllib2.ProxyHandler(proxies)
-
- opener = urllib2.build_opener(handler, proxy_support,
- urllib2.HTTPCookieProcessor(cj),
- authNTLM)
- elif self.proxyurl:
- # Proxy without auth
- proxy_support = urllib2.ProxyHandler(proxies)
- opener = urllib2.build_opener(proxy_support,
- handler,
- urllib2.HTTPCookieProcessor(cj))
- else:
- # Direct connection
- proxy_support = urllib2.ProxyHandler({})
- opener = urllib2.build_opener(proxy_support,
- handler,
- urllib2.HTTPCookieProcessor(cj))
-
- urllib2.install_opener(opener)
- response = urllib2.urlopen(request)
-
- return self.parse_response(response)
P.S.
Для всех, кто интересуется urllib2, рекомендую посмотреть urllib2 — The Missing Manual — отличный документ, где подробно описаны особенности работы с ним, в частности, обработка ошибок и исключений.