Changeset 391 for python/trunk/Lib/xmlrpclib.py
- Timestamp:
- Mar 19, 2014, 11:31:01 PM (11 years ago)
- Location:
- python/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
python/trunk
-
Property svn:mergeinfo
set to
/python/vendor/Python-2.7.6 merged eligible /python/vendor/current merged eligible
-
Property svn:mergeinfo
set to
-
python/trunk/Lib/xmlrpclib.py
r2 r391 1 1 # 2 2 # XML-RPC CLIENT LIBRARY 3 # $Id : xmlrpclib.py 65467 2008-08-04 00:50:11Z brett.cannon$3 # $Id$ 4 4 # 5 5 # an XML-RPC client interface for Python. … … 140 140 141 141 from types import * 142 import socket 143 import errno 144 import httplib 145 try: 146 import gzip 147 except ImportError: 148 gzip = None #python can be built without zlib/gzip support 142 149 143 150 # -------------------------------------------------------------------- … … 527 534 FastMarshaller = None 528 535 529 #530 # the SGMLOP parser is about 15x faster than Python's builtin531 # XML parser. SGMLOP sources can be downloaded from:532 #533 # http://www.pythonware.com/products/xml/sgmlop.htm534 #535 536 try:537 import sgmlop538 if not hasattr(sgmlop, "XMLParser"):539 raise ImportError540 except ImportError:541 SgmlopParser = None # sgmlop accelerator not available542 else:543 class SgmlopParser:544 def __init__(self, target):545 546 # setup callbacks547 self.finish_starttag = target.start548 self.finish_endtag = target.end549 self.handle_data = target.data550 self.handle_xml = target.xml551 552 # activate parser553 self.parser = sgmlop.XMLParser()554 self.parser.register(self)555 self.feed = self.parser.feed556 self.entity = {557 "amp": "&", "gt": ">", "lt": "<",558 "apos": "'", "quot": '"'559 }560 561 def close(self):562 try:563 self.parser.close()564 finally:565 self.parser = self.feed = None # nuke circular reference566 567 def handle_proc(self, tag, attr):568 m = re.search("encoding\s*=\s*['\"]([^\"']+)[\"']", attr)569 if m:570 self.handle_xml(m.group(1), 1)571 572 def handle_entityref(self, entity):573 # <string> entity574 try:575 self.handle_data(self.entity[entity])576 except KeyError:577 self.handle_data("&%s;" % entity)578 579 536 try: 580 537 from xml.parsers import expat … … 585 542 else: 586 543 class ExpatParser: 587 # fast expat parser for Python 2.0 and later. this is about 588 # 50% slower than sgmlop, on roundtrip testing 544 # fast expat parser for Python 2.0 and later. 589 545 def __init__(self, target): 590 546 self._parser = parser = expat.ParserCreate(None, None) … … 607 563 class SlowParser: 608 564 """Default XML parser (based on xmllib.XMLParser).""" 609 # this is about 10 times slower than sgmlop, on roundtrip 610 # testing. 565 # this is the slowest parser. 611 566 def __init__(self, target): 612 567 import xmllib # lazy subclassing (!) … … 991 946 class MultiCallIterator: 992 947 """Iterates over the results of a multicall. Exceptions are 993 thrownin response to xmlrpc faults."""948 raised in response to xmlrpc faults.""" 994 949 995 950 def __init__(self, results): … … 1070 1025 if FastParser: 1071 1026 parser = FastParser(target) 1072 elif SgmlopParser:1073 parser = SgmlopParser(target)1074 1027 elif ExpatParser: 1075 1028 parser = ExpatParser(target) … … 1184 1137 return u.close(), u.getmethodname() 1185 1138 1139 ## 1140 # Encode a string using the gzip content encoding such as specified by the 1141 # Content-Encoding: gzip 1142 # in the HTTP header, as described in RFC 1952 1143 # 1144 # @param data the unencoded data 1145 # @return the encoded data 1146 1147 def gzip_encode(data): 1148 """data -> gzip encoded data 1149 1150 Encode data using the gzip content encoding as described in RFC 1952 1151 """ 1152 if not gzip: 1153 raise NotImplementedError 1154 f = StringIO.StringIO() 1155 gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1) 1156 gzf.write(data) 1157 gzf.close() 1158 encoded = f.getvalue() 1159 f.close() 1160 return encoded 1161 1162 ## 1163 # Decode a string using the gzip content encoding such as specified by the 1164 # Content-Encoding: gzip 1165 # in the HTTP header, as described in RFC 1952 1166 # 1167 # @param data The encoded data 1168 # @return the unencoded data 1169 # @raises ValueError if data is not correctly coded. 1170 1171 def gzip_decode(data): 1172 """gzip encoded data -> unencoded data 1173 1174 Decode data using the gzip content encoding as described in RFC 1952 1175 """ 1176 if not gzip: 1177 raise NotImplementedError 1178 f = StringIO.StringIO(data) 1179 gzf = gzip.GzipFile(mode="rb", fileobj=f) 1180 try: 1181 decoded = gzf.read() 1182 except IOError: 1183 raise ValueError("invalid data") 1184 f.close() 1185 gzf.close() 1186 return decoded 1187 1188 ## 1189 # Return a decoded file-like object for the gzip encoding 1190 # as described in RFC 1952. 1191 # 1192 # @param response A stream supporting a read() method 1193 # @return a file-like object that the decoded data can be read() from 1194 1195 class GzipDecodedResponse(gzip.GzipFile if gzip else object): 1196 """a file-like object to decode a response encoded with the gzip 1197 method, as described in RFC 1952. 1198 """ 1199 def __init__(self, response): 1200 #response doesn't support tell() and read(), required by 1201 #GzipFile 1202 if not gzip: 1203 raise NotImplementedError 1204 self.stringio = StringIO.StringIO(response.read()) 1205 gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio) 1206 1207 def close(self): 1208 gzip.GzipFile.close(self) 1209 self.stringio.close() 1210 1186 1211 1187 1212 # -------------------------------------------------------------------- … … 1211 1236 user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__ 1212 1237 1238 #if true, we'll request gzip encoding 1239 accept_gzip_encoding = True 1240 1241 # if positive, encode request using gzip if it exceeds this threshold 1242 # note that many server will get confused, so only use it if you know 1243 # that they can decode such a request 1244 encode_threshold = None #None = don't encode 1245 1213 1246 def __init__(self, use_datetime=0): 1214 1247 self._use_datetime = use_datetime 1215 1248 self._connection = (None, None) 1249 self._extra_headers = [] 1216 1250 ## 1217 1251 # Send a complete request, and parse the response. 1252 # Retry request if a cached connection has disconnected. 1218 1253 # 1219 1254 # @param host Target host. … … 1224 1259 1225 1260 def request(self, host, handler, request_body, verbose=0): 1261 #retry request once if cached connection has gone cold 1262 for i in (0, 1): 1263 try: 1264 return self.single_request(host, handler, request_body, verbose) 1265 except socket.error, e: 1266 if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE): 1267 raise 1268 except httplib.BadStatusLine: #close after we sent request 1269 if i: 1270 raise 1271 1272 ## 1273 # Send a complete request, and parse the response. 1274 # 1275 # @param host Target host. 1276 # @param handler Target PRC handler. 1277 # @param request_body XML-RPC request body. 1278 # @param verbose Debugging flag. 1279 # @return Parsed response. 1280 1281 def single_request(self, host, handler, request_body, verbose=0): 1226 1282 # issue XML-RPC request 1227 1283 … … 1230 1286 h.set_debuglevel(1) 1231 1287 1232 self.send_request(h, handler, request_body)1233 self.send_host(h, host)1234 self.send_user_agent(h)1235 self.send_content(h, request_body)1236 1237 errcode, errmsg, headers = h.getreply()1238 1239 if errcode != 200:1240 raise ProtocolError(1241 host + handler,1242 errcode, errmsg,1243 headers1244 )1245 1246 self.verbose = verbose1247 1248 1288 try: 1249 sock = h._conn.sock 1250 except AttributeError: 1251 sock = None 1252 1253 return self._parse_response(h.getfile(), sock) 1289 self.send_request(h, handler, request_body) 1290 self.send_host(h, host) 1291 self.send_user_agent(h) 1292 self.send_content(h, request_body) 1293 1294 response = h.getresponse(buffering=True) 1295 if response.status == 200: 1296 self.verbose = verbose 1297 return self.parse_response(response) 1298 except Fault: 1299 raise 1300 except Exception: 1301 # All unexpected errors leave connection in 1302 # a strange state, so we clear it. 1303 self.close() 1304 raise 1305 1306 #discard any response data and raise exception 1307 if (response.getheader("content-length", 0)): 1308 response.read() 1309 raise ProtocolError( 1310 host + handler, 1311 response.status, response.reason, 1312 response.msg, 1313 ) 1254 1314 1255 1315 ## … … 1300 1360 1301 1361 def make_connection(self, host): 1362 #return an existing connection if possible. This allows 1363 #HTTP/1.1 keep-alive. 1364 if self._connection and host == self._connection[0]: 1365 return self._connection[1] 1366 1302 1367 # create a HTTP connection object from a host descriptor 1303 import httplib 1304 host, extra_headers, x509 = self.get_host_info(host) 1305 return httplib.HTTP(host) 1368 chost, self._extra_headers, x509 = self.get_host_info(host) 1369 #store the host argument along with the connection object 1370 self._connection = host, httplib.HTTPConnection(chost) 1371 return self._connection[1] 1372 1373 ## 1374 # Clear any cached connection object. 1375 # Used in the event of socket errors. 1376 # 1377 def close(self): 1378 if self._connection[1]: 1379 self._connection[1].close() 1380 self._connection = (None, None) 1306 1381 1307 1382 ## … … 1313 1388 1314 1389 def send_request(self, connection, handler, request_body): 1315 connection.putrequest("POST", handler) 1390 if (self.accept_gzip_encoding and gzip): 1391 connection.putrequest("POST", handler, skip_accept_encoding=True) 1392 connection.putheader("Accept-Encoding", "gzip") 1393 else: 1394 connection.putrequest("POST", handler) 1316 1395 1317 1396 ## … … 1320 1399 # @param connection Connection handle. 1321 1400 # @param host Host name. 1401 # 1402 # Note: This function doesn't actually add the "Host" 1403 # header anymore, it is done as part of the connection.putrequest() in 1404 # send_request() above. 1322 1405 1323 1406 def send_host(self, connection, host): 1324 host, extra_headers, x509 = self.get_host_info(host) 1325 connection.putheader("Host", host) 1407 extra_headers = self._extra_headers 1326 1408 if extra_headers: 1327 1409 if isinstance(extra_headers, DictType): … … 1346 1428 def send_content(self, connection, request_body): 1347 1429 connection.putheader("Content-Type", "text/xml") 1430 1431 #optionally encode the request 1432 if (self.encode_threshold is not None and 1433 self.encode_threshold < len(request_body) and 1434 gzip): 1435 connection.putheader("Content-Encoding", "gzip") 1436 request_body = gzip_encode(request_body) 1437 1348 1438 connection.putheader("Content-Length", str(len(request_body))) 1349 connection.endheaders() 1350 if request_body: 1351 connection.send(request_body) 1439 connection.endheaders(request_body) 1352 1440 1353 1441 ## … … 1357 1445 # @return Response tuple and target method. 1358 1446 1359 def parse_response(self, file): 1360 # compatibility interface 1361 return self._parse_response(file, None) 1362 1363 ## 1364 # Parse response (alternate interface). This is similar to the 1365 # parse_response method, but also provides direct access to the 1366 # underlying socket object (where available). 1367 # 1368 # @param file Stream. 1369 # @param sock Socket handle (or None, if the socket object 1370 # could not be accessed). 1371 # @return Response tuple and target method. 1372 1373 def _parse_response(self, file, sock): 1374 # read response from input file/socket, and parse it 1447 def parse_response(self, response): 1448 # read response data from httpresponse, and parse it 1449 1450 # Check for new http response object, else it is a file object 1451 if hasattr(response,'getheader'): 1452 if response.getheader("Content-Encoding", "") == "gzip": 1453 stream = GzipDecodedResponse(response) 1454 else: 1455 stream = response 1456 else: 1457 stream = response 1375 1458 1376 1459 p, u = self.getparser() 1377 1460 1378 1461 while 1: 1379 if sock: 1380 response = sock.recv(1024) 1381 else: 1382 response = file.read(1024) 1383 if not response: 1462 data = stream.read(1024) 1463 if not data: 1384 1464 break 1385 1465 if self.verbose: 1386 print "body:", repr(response) 1387 p.feed(response) 1388 1389 file.close() 1466 print "body:", repr(data) 1467 p.feed(data) 1468 1469 if stream is not response: 1470 stream.close() 1390 1471 p.close() 1391 1472 … … 1401 1482 1402 1483 def make_connection(self, host): 1484 if self._connection and host == self._connection[0]: 1485 return self._connection[1] 1403 1486 # create a HTTPS connection object from a host descriptor 1404 1487 # host may be a string, or a (host, x509-dict) tuple 1405 import httplib1406 host, extra_headers, x509 = self.get_host_info(host)1407 1488 try: 1408 HTTPS = httplib.HTTPS 1489 HTTPS = httplib.HTTPSConnection 1409 1490 except AttributeError: 1410 1491 raise NotImplementedError( … … 1412 1493 ) 1413 1494 else: 1414 return HTTPS(host, None, **(x509 or {})) 1495 chost, self._extra_headers, x509 = self.get_host_info(host) 1496 self._connection = host, HTTPS(chost, None, **(x509 or {})) 1497 return self._connection[1] 1415 1498 1416 1499 ## … … 1457 1540 # establish a "logical" server connection 1458 1541 1542 if isinstance(uri, unicode): 1543 uri = uri.encode('ISO-8859-1') 1544 1459 1545 # get the url 1460 1546 import urllib … … 1477 1563 self.__allow_none = allow_none 1478 1564 1565 def __close(self): 1566 self.__transport.close() 1567 1479 1568 def __request(self, methodname, params): 1480 1569 # call a method on the remote server … … 1509 1598 # note: to call a remote object with an non-standard name, use 1510 1599 # result getattr(server, "strange-python-name")(args) 1600 1601 def __call__(self, attr): 1602 """A workaround to get special attributes on the ServerProxy 1603 without interfering with the magic __getattr__ 1604 """ 1605 if attr == "close": 1606 return self.__close 1607 elif attr == "transport": 1608 return self.__transport 1609 raise AttributeError("Attribute %r not found" % (attr,)) 1511 1610 1512 1611 # compatibility
Note:
See TracChangeset
for help on using the changeset viewer.