XML-RPCクライアントヘルパー
ややこしげなXML-RPCサーバーに接続するには
tags: | python, web, tips |
---|---|
created: | 2008-04-15T04:18:44 |
XML-RPCクライアントライブラリを作成してみました。
XML-RPCクライアントライブラリを作成してみました。
概要
標準のxmlrpclibがシンプル過ぎて繋げないサーバーがあるので、 もう少しがんばって繋ぎに行くXML-RPCクライアントラッパーを作成しました。
仕様
環境変数「HTTP_PROXY」に設定があれば、そのプロキシ経由で繋ぎに行きます。 (XmlRpcServer(local=True)という引数を加えるとプロキシは使わずに繋ぎます。)
認証が必要な場合にあらかじめセットしておいた ユーザー名とパスワードを使って認証にチャレンジします。 サポートしている認証は「ベーシック認証」と「ダイジェスト認証」の2種類です。
ソースコード
- xml_rpc.py
#!/usr/local/bin/python # -*- encoding: utf-8 -*- import os import xmlrpclib from urllib import splituser, splitpasswd from urllib2 import urlparse import socket import md5 import random """ import urllib2 toplevelurl='x68000.q-e-d.net' theurl='x68000.q-e-d.net/~68user/net/sample/http-auth-digest/secret.html' protocol='http://' username='hoge' password='fuga' passman = urllib2.HTTPPasswordMgrWithDefaultRealm() passman.add_password(None, toplevelurl, username, password) authhandler = urllib2.HTTPDigestAuthHandler(passman) opener = urllib2.build_opener(authhandler) pagehandle = opener.open(protocol + theurl) """ class CustomTransport(xmlrpclib.Transport): proxy_keys = dict(HTTP_PROXY='http',HTTPS_PROXY='https') #_use_datetime = True def __init__(self, proxies={}, local=False): xmlrpclib.Transport.__init__(self) self.proxies = dict((\ (self.proxy_keys[k],v)\ for k,v in os.environ.items()\ if k in self.proxy_keys\ )) self.proxies.update(proxies) self.local = local self.auth = '' self.nc = 0 def make_connection(self, host): self.user_pass, self.realhost = splituser(host) import httplib proto, proxy, p1,p2,p3,p4 = urlparse.urlparse(self.proxies.get('http', '')) if proxy and not self.local: return httplib.HTTP(proxy) else: return httplib.HTTP(self.realhost) def send_request(self, connection, handler, request_body): #connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler)) connection.putrequest("POST", handler) def request(self, host, handler, request_body, verbose=0): for count in range(3): try: return xmlrpclib.Transport.request(self, host, handler, request_body, verbose) except xmlrpclib.ProtocolError, ex: if ex.errcode==401: auth, params = ex.headers['WWW-Authenticate'].split(' ', 1) self.uri = handler self.auth = auth.lower() self.params = dict([ [n.strip() for n in i.split('=',1)]\ for i in params.split(',')]) raise ex def send_host(self, connection, host): connection.putheader('Host', self.realhost) if self.auth=='basic': if self.user_pass: import base64 user_pass = base64.encodestring(self.user_pass).strip() connection.putheader('Authorization', 'Basic %s' % user_pass) elif self.auth=='digest': if self.user_pass: self.nc += 1 username, password = self.user_pass.split(':') uri = self.uri realm = self.params['realm'].strip('"') nonce = self.params['nonce'].strip('"') qop = self.params['qop'].strip('"') a1 = md5.new('%(username)s:%(realm)s:%(password)s' % locals()).hexdigest() a2 = md5.new('POST:%(uri)s' % locals()).hexdigest() nc = '%08d' % self.nc chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' cnonce = ''.join([random.choice(chars) for i in range(16)]) response = md5.new('%(a1)s:%(nonce)s:%(nc)s:%(cnonce)s:%(qop)s:%(a2)s' % locals()).hexdigest() print >>open('log.txt','a'), locals() params = [] params.append('username=%s' % username) params.append('realm="%s"' % realm) params.append('nonce="%s"' % nonce) params.append('uri=%s' % uri) params.append('algorithm=%s' % self.params['algorithm']) params.append('qop=%s' % qop) params.append('nc=%s' % nc) params.append('cnonce="%s"' % cnonce) params.append('response="%s"' % response) for i in params: print >>open('log.txt','a'), i connection.putheader('Authorization', 'Digest %s' % ', '.join(params)) class XmlRpcServer(xmlrpclib.ServerProxy): def __init__(self, url, user='', password='', local=False): protocol,domain,path, d1,params,d3 = urlparse.urlparse(url) if params: params = '?'+params user_pass = '' if user: user_pass = ':'.join([user,password]) + '@' href = '%(protocol)s://%(user_pass)s%(domain)s%(path)s%(params)s' % locals() xmlrpclib.ServerProxy.__init__( self, href, transport=CustomTransport(local=local), allow_none=True) if __name__=='__main__': server = XmlRpcServer('http://example.org/RPC2','hoge','fuga') print server.system.listMethods()
使い方
import xml_rpc
url = 'http://example.org/RPC2'
user, password = 'hoge', 'password'
server = xml_rpc.XmlRpcServer(url, user, password)
print server.system.listMethods()