class Wiki(object): def __init__(self, url, ssl_verify_cert=True, ssl_ca_certs=None): self.ssl_verify_cert = ssl_verify_cert self.ssl_ca_certs = ssl_ca_certs scheme, host, path, _, _, _ = urlparse.urlparse(url) if isinstance(host, unicode): host = idna.ToASCII(host) self.host = host if isinstance(path, unicode): path = path.encode("utf-8") self.path = urllib.quote(path) + "?action=xmlrpc2" self.headers = dict(Connection="Keep-Alive") self.creds = None if scheme.strip().lower() == "http": self.connection = HTTPConnection(self.host) else: self.connection = HTTPSConnection(self.host, verify_cert=self.ssl_verify_cert, ca_certs=self.ssl_ca_certs) self.connection.connect() def _wiki_auth(self, username, password): self.creds = None token = self._request("getAuthToken", username, password) if not token: raise WikiAuthenticationFailed("wiki authentication failed") self.creds = token, username, password def _authenticate(self, username, password): auth = base64.b64encode(username + ":" + password) self.headers["Authorization"] = "Basic " + auth self.creds = None try: self._wiki_auth(username, password) except: self.headers.pop("Authorization", None) self.creds = None raise def _dumps(self, name, args): if self.creds is None: return xmlrpclib.dumps(args, name, allow_none=True) token, _, _ = self.creds mc_list = list() mc_list.append(dict(methodName="applyAuthToken", params=(token,))) mc_list.append(dict(methodName=name, params=args)) return xmlrpclib.dumps((mc_list,), "system.multicall", allow_none=True) def _loads(self, data): result, _ = xmlrpclib.loads(data) if self.creds is None: return result[0] auth, other = result[0] if isinstance(auth, dict): code = auth.get("faultCode", None) string = auth.get("faultString", "<unknown fault>") if code == "INVALID": raise WikiAuthenticationFailed(string) raise xmlrpclib.Fault(code, string) if isinstance(other, dict): code = other.get("faultCode", None) string = other.get("faultString", "<unknown fault>") raise xmlrpclib.Fault(code, string) return other[0] def _read_response(self, response): data = response.read() if response.status == 401: raise HttpAuthenticationFailed(response.reason) elif response.status != 200: raise WikiFailure(response.reason) return self._loads(data) def _request(self, name, *args): body = self._dumps(name, args) try: self.connection.request("POST", self.path, body, self.headers) response = self.connection.getresponse() except socket.error as error: if error.args[0] != errno.EPIPE: raise except httplib.BadStatusLine: pass else: return self._read_response(response) self.connection.close() self.connection.connect() self.connection.request("POST", self.path, body, self.headers) response = self.connection.getresponse() return self._read_response(response) def request(self, name, *args): try: try: return self._request(name, *args) except WikiAuthenticationFailed: _, username, password = self.creds self._wiki_auth(username, password) return self._request(name, *args) except xmlrpclib.Fault, fault: raise WikiFault(fault)
class Wiki(object): def __init__(self, url, ssl_verify_cert=True, ssl_ca_certs=None): self.ssl_verify_cert = ssl_verify_cert self.ssl_ca_certs = ssl_ca_certs scheme, host, path, _, _, _ = urlparse.urlparse(url) if isinstance(host, unicode): host = idna.ToASCII(host) self.host = host if isinstance(path, unicode): path = path.encode("utf-8") self.path = urllib.quote(path) + "?action=xmlrpc2" self.headers = dict(Connection="Keep-Alive") self.creds = None if scheme.strip().lower() == "http": self.connection = HTTPConnection(self.host) else: self.connection = HTTPSConnection(self.host, verify_cert=self.ssl_verify_cert, ca_certs=self.ssl_ca_certs) self.connection.connect() def _wiki_auth(self, username, password): self.creds = None token = self._request("getAuthToken", username, password) if not token: raise WikiAuthenticationFailed("wiki authentication failed") self.creds = token, username, password def _authenticate(self, username, password): auth = base64.b64encode(username + ":" + password) self.headers["Authorization"] = "Basic " + auth self.creds = None try: self._wiki_auth(username, password) except: self.headers.pop("Authorization", None) self.creds = None raise def _dumps(self, name, args): if self.creds is None: return xmlrpclib.dumps(args, name, allow_none=True) token, _, _ = self.creds mc_list = list() mc_list.append(dict(methodName="applyAuthToken", params=(token, ))) mc_list.append(dict(methodName=name, params=args)) return xmlrpclib.dumps((mc_list, ), "system.multicall", allow_none=True) def _loads(self, data): result, _ = xmlrpclib.loads(data) if self.creds is None: return result[0] auth, other = result[0] if isinstance(auth, dict): code = auth.get("faultCode", None) string = auth.get("faultString", "<unknown fault>") if code == "INVALID": raise WikiAuthenticationFailed(string) raise xmlrpclib.Fault(code, string) if isinstance(other, dict): code = other.get("faultCode", None) string = other.get("faultString", "<unknown fault>") raise xmlrpclib.Fault(code, string) return other[0] def _read_response(self, response): data = response.read() if response.status == 401: raise HttpAuthenticationFailed(response.reason) elif response.status != 200: raise WikiFailure(response.reason) return self._loads(data) def _request(self, name, *args): body = self._dumps(name, args) try: self.connection.request("POST", self.path, body, self.headers) response = self.connection.getresponse() except socket.error as error: if error.args[0] != errno.EPIPE: raise except httplib.BadStatusLine: pass else: return self._read_response(response) self.connection.close() self.connection.connect() self.connection.request("POST", self.path, body, self.headers) response = self.connection.getresponse() return self._read_response(response) def request(self, name, *args): try: try: return self._request(name, *args) except WikiAuthenticationFailed: _, username, password = self.creds self._wiki_auth(username, password) return self._request(name, *args) except xmlrpclib.Fault, fault: raise WikiFault(fault)