1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
import zlib
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
import logging
from timeout_transport import TimeoutTransport, TimeoutSafeTransport
# xmlrpc server side
class GzipXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
def do_POST(self):
if not(self.headers.has_key('accept-encoding') and self.headers['accept-encoding'] == 'gzip'):
return SimpleXMLRPCRequestHandler.do_POST(self)
else:
if not self.is_rpc_path_valid():
self.report_404()
return
try:
max_chunk_size = 10*1024*1024
size_remaining = int(self.headers["content-length"])
L = []
while size_remaining:
chunk_size = min(size_remaining, max_chunk_size)
L.append(self.rfile.read(chunk_size))
size_remaining -= len(L[-1])
data = ''.join(L)
data = zlib.decompress(data) # is_gzip
response = self.server._marshaled_dispatch(
data, getattr(self, '_dispatch', None)
)
except Exception, e:
self.send_response(500)
self.end_headers()
else:
response = zlib.compress(response, zlib.Z_BEST_COMPRESSION) # is_gzip
self.send_response(200)
self.send_header("Content-type", "text/xml")
self.send_header("Content-length", str(len(response)))
self.send_header("Accept-Encoding", "gzip") # is_gzip
self.end_headers()
self.wfile.write(response)
self.wfile.flush()
self.connection.shutdown(1)
# xmlrpc client side
class GzipTransport(TimeoutTransport):
def __init__(self, timeout=None, *args, **kwargs):
TimeoutTransport.__init__(self, timeout=timeout, *args, **kwargs)
self._logger = logging.getLogger('xmlrpc.transport')
def request(self, host, handler, request_body, verbose=0):
h = self.make_connection(host)
if verbose:
h.set_debuglevel(1)
self.send_request(h, handler, request_body)
self.send_host(h, host)
self.send_user_agent(h)
# is_gzip
h.putheader('Accept-Encoding', 'gzip')
raw_size = len(request_body)
request_body = zlib.compress(request_body, zlib.Z_BEST_COMPRESSION)
gzipped_size = len(request_body)
saving = 100*(float(raw_size-gzipped_size))/gzipped_size if gzipped_size else 0
self._logger.debug('payload size: raw %s, gzipped %s, saving %.2f%%',
raw_size, gzipped_size, saving)
self.send_content(h, request_body)
errcode, errmsg, headers = h.getreply()
if errcode != 200:
raise xmlrpclib.ProtocolError(
host + handler,
errcode, errmsg,
headers
)
self.verbose = verbose
try:
sock = h._conn.sock
except AttributeError:
sock = None
# is_gzip
if headers.has_key('accept-encoding') and headers['accept-encoding'] == 'gzip':
return self._parse_gzipped_response(h.getfile(), sock)
return self._parse_response(h.getfile(), sock)
def _parse_gzipped_response(self, file, sock):
p, u = self.getparser()
response_chunks = []
while 1:
if sock:
chunk = sock.recv(1024)
else:
chunk = file.read(1024)
if not chunk:
break
response_chunks.append(chunk)
response = zlib.decompress("".join(response_chunks))
if self.verbose:
print "body:", repr(response)
p.feed(response)
file.close()
p.close()
return u.close()
class GzipSafeTransport(TimeoutSafeTransport, GzipTransport):
def __init__(self, timeout=None, *args, **kwargs):
TimeoutSafeTransport.__init__(self, timeout=timeout, *args, **kwargs)
self._logger = logging.getLogger('xmlrpc.transport')
def request(self, host, handler, request_body, verbose=0):
return GzipTransport.request(self, host, handler, request_body, verbose)
|