Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(2109)

Side by Side Diff: Lib/SimpleXMLRPCServer.py

Issue 73041: Performance improvements to XMLRPC Base URL: http://svn.python.org/view/*checkout*/python/trunk/
Patch Set: Fix unittest. Move 'disable_nagle_algorithm' to StreamRequestHandler, where it is more appropriate. Created 15 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 """Simple XML-RPC Server. 1 """Simple XML-RPC Server.
2 2
3 This module can be used to create simple XML-RPC servers 3 This module can be used to create simple XML-RPC servers
4 by creating a server and either installing functions, a 4 by creating a server and either installing functions, a
5 class instance, or by extending the SimpleXMLRPCServer 5 class instance, or by extending the SimpleXMLRPCServer
6 class. 6 class.
7 7
8 It can also be used to handle XML-RPC requests in a CGI 8 It can also be used to handle XML-RPC requests in a CGI
9 environment using CGIXMLRPCRequestHandler. 9 environment using CGIXMLRPCRequestHandler.
10 10
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 # Written by Brian Quinlan (brian@sweetapp.com). 99 # Written by Brian Quinlan (brian@sweetapp.com).
100 # Based on code written by Fredrik Lundh. 100 # Based on code written by Fredrik Lundh.
101 101
102 import xmlrpclib 102 import xmlrpclib
103 from xmlrpclib import Fault 103 from xmlrpclib import Fault
104 import SocketServer 104 import SocketServer
105 import BaseHTTPServer 105 import BaseHTTPServer
106 import sys 106 import sys
107 import os 107 import os
108 import traceback 108 import traceback
109 import re
109 try: 110 try:
110 import fcntl 111 import fcntl
111 except ImportError: 112 except ImportError:
112 fcntl = None 113 fcntl = None
113 114
114 def resolve_dotted_attribute(obj, attr, allow_dotted_names=True): 115 def resolve_dotted_attribute(obj, attr, allow_dotted_names=True):
115 """resolve_dotted_attribute(a, 'b.c.d') => a.b.c.d 116 """resolve_dotted_attribute(a, 'b.c.d') => a.b.c.d
116 117
117 Resolves a dotted attribute name to an object. Raises 118 Resolves a dotted attribute name to an object. Raises
118 an AttributeError if any attribute in the chain starts with a '_'. 119 an AttributeError if any attribute in the chain starts with a '_'.
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 """Simple XML-RPC request handler class. 424 """Simple XML-RPC request handler class.
424 425
425 Handles all HTTP POST requests and attempts to decode them as 426 Handles all HTTP POST requests and attempts to decode them as
426 XML-RPC requests. 427 XML-RPC requests.
427 """ 428 """
428 429
429 # Class attribute listing the accessible path components; 430 # Class attribute listing the accessible path components;
430 # paths not on this list will result in a 404 error. 431 # paths not on this list will result in a 404 error.
431 rpc_paths = ('/', '/RPC2') 432 rpc_paths = ('/', '/RPC2')
432 433
434 #if not None, encode responses larger than this, if possible
435 encode_threshold = 1400 #a common MTU
436
437 #Override form StreamRequestHandler: full buffering of output
438 #and no Nagle.
439 wbufsize = -1
krisvale 2009/06/14 21:43:45 Make the default server high-performing
440 disable_nagle_algorithm = True
441
442 # a re to match a gzip Accept-Encoding
443 aepattern = re.compile(r"""
444 \s* ([^\s;]+) \s* #content-coding
445 (;\s* q \s*=\s* ([0-9\.]+))? #q
446 """, re.VERBOSE | re.IGNORECASE)
447
448 def accept_encodings(self):
449 r = {}
450 ae = self.headers.get("Accept-Encoding", "")
451 for e in ae.split(","):
452 match = self.aepattern.match(e)
453 if match:
454 v = match.group(3)
455 v = float(v) if v else 1.0
456 r[match.group(1)] = v
457 return r
458
433 def is_rpc_path_valid(self): 459 def is_rpc_path_valid(self):
434 if self.rpc_paths: 460 if self.rpc_paths:
435 return self.path in self.rpc_paths 461 return self.path in self.rpc_paths
436 else: 462 else:
437 # If .rpc_paths is empty, just assume all paths are legal 463 # If .rpc_paths is empty, just assume all paths are legal
438 return True 464 return True
439 465
440 def do_POST(self): 466 def do_POST(self):
441 """Handles the HTTP POST request. 467 """Handles the HTTP POST request.
442 468
(...skipping 13 matching lines...) Expand all
456 # begin to have problems (bug #792570). 482 # begin to have problems (bug #792570).
457 max_chunk_size = 10*1024*1024 483 max_chunk_size = 10*1024*1024
458 size_remaining = int(self.headers["content-length"]) 484 size_remaining = int(self.headers["content-length"])
459 L = [] 485 L = []
460 while size_remaining: 486 while size_remaining:
461 chunk_size = min(size_remaining, max_chunk_size) 487 chunk_size = min(size_remaining, max_chunk_size)
462 L.append(self.rfile.read(chunk_size)) 488 L.append(self.rfile.read(chunk_size))
463 size_remaining -= len(L[-1]) 489 size_remaining -= len(L[-1])
464 data = ''.join(L) 490 data = ''.join(L)
465 491
492 data = self.decode_request_content(data)
493 if data is None:
494 return #response has been sent
495
466 # In previous versions of SimpleXMLRPCServer, _dispatch 496 # In previous versions of SimpleXMLRPCServer, _dispatch
467 # could be overridden in this class, instead of in 497 # could be overridden in this class, instead of in
468 # SimpleXMLRPCDispatcher. To maintain backwards compatibility, 498 # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
469 # check to see if a subclass implements _dispatch and dispatch 499 # check to see if a subclass implements _dispatch and dispatch
470 # using that method if present. 500 # using that method if present.
471 response = self.server._marshaled_dispatch( 501 response = self.server._marshaled_dispatch(
472 data, getattr(self, '_dispatch', None) 502 data, getattr(self, '_dispatch', None)
473 ) 503 )
474 except Exception, e: # This should only happen if the module is buggy 504 except Exception, e: # This should only happen if the module is buggy
475 # internal error, report as HTTP server error 505 # internal error, report as HTTP server error
476 self.send_response(500) 506 self.send_response(500)
477 507
478 # Send information about the exception if requested 508 # Send information about the exception if requested
479 if hasattr(self.server, '_send_traceback_header') and \ 509 if hasattr(self.server, '_send_traceback_header') and \
480 self.server._send_traceback_header: 510 self.server._send_traceback_header:
481 self.send_header("X-exception", str(e)) 511 self.send_header("X-exception", str(e))
482 self.send_header("X-traceback", traceback.format_exc()) 512 self.send_header("X-traceback", traceback.format_exc())
483 513
514 self.send_header("Content-length", "0")
484 self.end_headers() 515 self.end_headers()
485 else: 516 else:
486 # got a valid XML RPC response 517 # got a valid XML RPC response
487 self.send_response(200) 518 self.send_response(200)
488 self.send_header("Content-type", "text/xml") 519 self.send_header("Content-type", "text/xml")
520 if self.encode_threshold is not None:
521 if len(response) > self.encode_threshold:
522 q = self.accept_encodings().get("gzip", 0)
523 if q:
524 response = xmlrpclib.gzip_encode(response)
525 self.send_header("Content-Encoding", "gzip")
489 self.send_header("Content-length", str(len(response))) 526 self.send_header("Content-length", str(len(response)))
490 self.end_headers() 527 self.end_headers()
491 self.wfile.write(response) 528 self.wfile.write(response)
492 529
493 # shut down the connection 530 def decode_request_content(self, data):
494 self.wfile.flush() 531 #support gzip encoding of request
495 self.connection.shutdown(1) 532 encoding = self.headers.get("content-encoding", "identity").lower()
533 if encoding == "identity":
534 return data
535 if encoding == "gzip":
536 try:
537 return xmlrpclib.gzip_decode(data)
538 except ValueError:
539 self.send_response(400, "error decoding gzip content")
540 else:
541 self.send_response(501, "encoding %r not supported" % encoding)
542 self.send_header("Content-length", "0")
543 self.end_headers()
496 544
497 def report_404 (self): 545 def report_404 (self):
498 # Report a 404 error 546 # Report a 404 error
499 self.send_response(404) 547 self.send_response(404)
500 response = 'No such page' 548 response = 'No such page'
501 self.send_header("Content-type", "text/plain") 549 self.send_header("Content-type", "text/plain")
502 self.send_header("Content-length", str(len(response))) 550 self.send_header("Content-length", str(len(response)))
503 self.end_headers() 551 self.end_headers()
504 self.wfile.write(response) 552 self.wfile.write(response)
505 # shut down the connection
506 self.wfile.flush()
507 self.connection.shutdown(1)
508 553
509 def log_request(self, code='-', size='-'): 554 def log_request(self, code='-', size='-'):
510 """Selectively log an accepted request.""" 555 """Selectively log an accepted request."""
511 556
512 if self.server.logRequests: 557 if self.server.logRequests:
513 BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size) 558 BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size)
514 559
515 class SimpleXMLRPCServer(SocketServer.TCPServer, 560 class SimpleXMLRPCServer(SocketServer.TCPServer,
516 SimpleXMLRPCDispatcher): 561 SimpleXMLRPCDispatcher):
517 """Simple XML-RPC server. 562 """Simple XML-RPC server.
518 563
519 Simple XML-RPC server that allows functions and a single instance 564 Simple XML-RPC server that allows functions and a single instance
520 to be installed to handle requests. The default implementation 565 to be installed to handle requests. The default implementation
521 attempts to dispatch XML-RPC calls to the functions or instance 566 attempts to dispatch XML-RPC calls to the functions or instance
522 installed in the server. Override the _dispatch method inhereted 567 installed in the server. Override the _dispatch method inhereted
523 from SimpleXMLRPCDispatcher to change this behavior. 568 from SimpleXMLRPCDispatcher to change this behavior.
524 """ 569 """
525 570
526 allow_reuse_address = True 571 allow_reuse_address = True
527 572
573
528 # Warning: this is for debugging purposes only! Never set this to True in 574 # Warning: this is for debugging purposes only! Never set this to True in
529 # production code, as will be sending out sensitive information (exception 575 # production code, as will be sending out sensitive information (exception
530 # and stack trace details) when exceptions are raised inside 576 # and stack trace details) when exceptions are raised inside
531 # SimpleXMLRPCRequestHandler.do_POST 577 # SimpleXMLRPCRequestHandler.do_POST
532 _send_traceback_header = False 578 _send_traceback_header = False
533 579
534 def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler, 580 def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
535 logRequests=True, allow_none=False, encoding=None, bind_and_act ivate=True): 581 logRequests=True, allow_none=False, encoding=None, bind_and_act ivate=True):
536 self.logRequests = logRequests 582 self.logRequests = logRequests
537 583
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 request_text = sys.stdin.read(length) 652 request_text = sys.stdin.read(length)
607 653
608 self.handle_xmlrpc(request_text) 654 self.handle_xmlrpc(request_text)
609 655
610 if __name__ == '__main__': 656 if __name__ == '__main__':
611 print 'Running XML-RPC server on port 8000' 657 print 'Running XML-RPC server on port 8000'
612 server = SimpleXMLRPCServer(("localhost", 8000)) 658 server = SimpleXMLRPCServer(("localhost", 8000))
613 server.register_function(pow) 659 server.register_function(pow)
614 server.register_function(lambda x,y: x+y, 'add') 660 server.register_function(lambda x,y: x+y, 'add')
615 server.serve_forever() 661 server.serve_forever()
OLDNEW
« no previous file with comments | « Lib/DocXMLRPCServer.py ('k') | Lib/SocketServer.py » ('j') | Lib/xmlrpclib.py » ('J')

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b