Python の xmlrpclib で proxy + Basic 認証

xmlrpclib を proxy 経由で使わなければいけなかったのだが、 xmlrpclib は httplib で通信をしているようで、環境変数の http_proxy を見てくれない。
色々とググってみても、 httplib をそのまま使って proxy を使う方法しか出てこなかった。
今回は proxy だけでなく Basic 認証も行わなければいけないので、なるべくなら urllib2 を使ってリクエストを送りたかった。
なので Transport クラスを継承して urllib2 を使ったリクエストを送るように書き換えてみた。

結果

で、できたのが以下のコード。
xmlrpclib.Transport を継承し、 Transport::request をオーバライドして urllib2 を使ってリクエストを送っている。

urllib2 のハンドラを使って

  • xmlrpc
  • proxy 経由のアクセス
  • Basic 認証

ができるようになった。

必要あるのかどうなのかわからないけれど、 cookie も保存するようにしてみた。

#-*- coding:utf-8 -*-
import cookielib
import urllib2
import xmlrpclib

class ProxiedTransport(xmlrpclib.Transport):

    SCHEME = 'https'

    def __init__(self, passwds, proxies=None, *args, **argd):
        '''
        初期化
        '''

        xmlrpclib.Transport.__init__(self, *args, **argd)

        handlers = []

        # proxy handler を作る
        if proxies is not None:
            proxy = urllib2.ProxyHandler(proxies)
            handlers.append(proxy)

        # cookie processor も作る
        cj = cookielib.CookieJar()
        cjhdr = urllib2.HTTPCookieProcessor(cj)

        handlers.append(cjhdr)

        mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()

        for url, (usr, passwd) in passwds.iteritems():
            mgr.add_password(None, url, usr, passwd)

        # Basic 認証 handler を作る
        basic = urllib2.HTTPBasicAuthHandler(mgr)

        handlers.append(basic)

        # opener を作る
        self.opener = urllib2.build_opener(*handlers)



    def request(self, host, handler, request_body, verbose=0):
        '''
        opener を使って url を開く
        '''

        self.verbose = 0

        scheme = self.SCHEME

        url = '%(scheme)s://%(host)s%(handler)s' % locals()

        req = urllib2.Request(url, data=request_body,
                              headers={'Content-Type':'text/xml'})

        fp = self.opener.open(req)

        return self._parse_response(fp, None)



def test():

    url = 'https://xmlrpc.exsample.com/XML-RPC'

    usr = 'guest'
    passwd = 'guest'

    trans = ProxiedTransport({url:[usr, passwd]},
                             {'https':'http://proxy.example.com:8080/'})

    proxy = xmlrpclib.ServerProxy(url, trans)

    arg1 = 10
    arg2 = 'aaaa'
    
    print proxy.rpcCall(arg1, arg2)
    
    

if __name__ == '__main__':
    test()