1
2
3
4
5
6
7
8
9
10
11
12
13 import os
14 import sys
15 import time
16 from rhn import connections
17 from rhn.i18n import sstr, bstr
18 from rhn.SmartIO import SmartIO
19 from rhn.UserDictCase import UserDictCase
20
21 try:
22 import xmlrpclib
23 from types import IntType, StringType, ListType
24 except ImportError:
25 import xmlrpc.client as xmlrpclib
26 IntType = int
27 StringType = bytes
28 ListType = list
29
30 __version__ = "$Revision$"
31
32
33 COMPRESS_LEVEL = 6
34
35
38
40 user_agent = "rhn.rpclib.py/%s" % __version__
41
42 - def __init__(self, transfer=0, encoding=0, refreshCallback=None,
43 progressCallback=None, use_datetime=None, timeout=None):
44 self._use_builtin_types = False
45 self._transport_flags = {'transfer' : 0, 'encoding' : 0}
46 self.set_transport_flags(transfer=transfer, encoding=encoding)
47 self._headers = UserDictCase()
48 self.verbose = 0
49 self.connection = None
50 self.method = "POST"
51 self._lang = None
52 self.refreshCallback = refreshCallback
53 self.progressCallback = progressCallback
54 self.bufferSize = 16384
55 self.headers_in = None
56 self.response_status = None
57 self.response_reason = None
58 self._redirected = None
59 self._use_datetime = use_datetime
60 self.timeout = timeout
61
62
64 self.progressCallback = progressCallback
65 self.bufferSize = bufferSize
66
67
69 self.refreshCallback = refreshCallback
70
71
72
73
75 if bufferSize is None:
76
77 bufferSize = 16384
78
79 self.bufferSize = bufferSize
80
81
83 if method not in ("GET", "POST"):
84 raise IOError("Unknown request method %s" % method)
85 self.method = method
86
87
89
90
91
92 self._transport_flags.update(kwargs)
93 if transfer is not None:
94 self._transport_flags['transfer'] = transfer
95 if encoding is not None:
96 self._transport_flags['encoding'] = encoding
97 self.validate_transport_flags()
98
100 return self._transport_flags.copy()
101
103
104 transfer = self._transport_flags.get('transfer')
105 transfer = lookupTransfer(transfer, strict=1)
106 self._transport_flags['transfer'] = transfer
107
108 encoding = self._transport_flags.get('encoding')
109 encoding = lookupEncoding(encoding, strict=1)
110 self._transport_flags['encoding'] = encoding
111
112
114 if type(arg) in [ type([]), type(()) ]:
115
116 self._headers[name] = [str(a) for a in arg]
117 else:
118 self._headers[name] = str(arg)
119
121 if name in self._headers:
122 vlist = self._headers[name]
123 if not isinstance(vlist, ListType):
124 vlist = [ vlist ]
125 else:
126 vlist = self._headers[name] = []
127 vlist.append(str(arg))
128
130 self._headers.clear()
131
139
140 - def request(self, host, handler, request_body, verbose=0):
141
142
143
144
145
146 self.verbose = verbose
147
148
149 host, extra_headers, x509 = self.get_host_info(host)
150 if not extra_headers:
151 extra_headers = []
152
153 connection = self.get_connection(host)
154
155
156 connection.set_user_agent(self.user_agent)
157 if self.verbose:
158 connection.set_debuglevel(self.verbose - 1)
159
160 req = Output(connection=connection, method=self.method)
161 req.set_transport_flags(**self._transport_flags)
162
163
164 req.set_header('User-Agent', self.user_agent)
165 for header, value in list(self._headers.items()) + extra_headers:
166
167 req.set_header(header, value)
168
169
170 req.set_header("Content-Type", "text/xml")
171 req.process(request_body)
172
173
174 for h in ['Content-Length', 'Host']:
175 req.clear_header(h)
176
177 headers, fd = req.send_http(host, handler)
178
179 if self.verbose:
180 print("Incoming headers:")
181 for header, value in headers.items():
182 print("\t%s : %s" % (header, value))
183
184 if fd.status in (301, 302):
185 self._redirected = headers["Location"]
186 self.response_status = fd.status
187 return None
188
189
190 self.headers_in = headers
191 self.response_status = fd.status
192 self.response_reason = fd.reason
193
194 return self._process_response(fd, connection)
195
197
198 resp = Input(self.headers_in, progressCallback=self.progressCallback,
199 bufferSize=self.bufferSize)
200
201 fd = resp.decode(fd)
202
203 if isinstance(fd, InputStream):
204
205
206
207 f = File(fd.fd, fd.length, fd.name, bufferSize=self.bufferSize,
208 progressCallback=self.progressCallback)
209
210
211
212
213 f.close = connection.close
214 return f
215
216
217
218
219
220 connection.close()
221
222 return self.parse_response(fd)
223
224
226 return self._redirected
227
228
247
248
251
253 - def __init__(self, transfer=0, encoding=0, refreshCallback=None,
254 progressCallback=None, trusted_certs=None, timeout=None):
255 Transport.__init__(self, transfer, encoding,
256 refreshCallback=refreshCallback, progressCallback=progressCallback,
257 timeout=timeout)
258 self.trusted_certs = []
259 for certfile in (trusted_certs or []):
260 self.add_trusted_cert(certfile)
261
263 if not os.access(certfile, os.R_OK):
264 raise ValueError("Certificate file %s is not accessible" % certfile)
265 self.trusted_certs.append(certfile)
266
268
269 host, extra_headers, x509 = self.get_host_info(host)
270 if self.verbose:
271 print("Connecting via https to %s" % (host, ))
272 if self.timeout:
273 return connections.HTTPSConnection(host,
274 trusted_certs=self.trusted_certs, timeout=self.timeout)
275 else:
276 return connections.HTTPSConnection(host,
277 trusted_certs=self.trusted_certs)
278
279
281 - def __init__(self, proxy, proxyUsername=None, proxyPassword=None,
282 transfer=0, encoding=0, refreshCallback=None, progressCallback=None,
283 timeout=None):
284 Transport.__init__(self, transfer, encoding,
285 refreshCallback=refreshCallback, progressCallback=progressCallback,
286 timeout=timeout)
287 self._proxy = proxy
288 self._proxy_username = proxyUsername
289 self._proxy_password = proxyPassword
290
292 if self.verbose:
293 print("Connecting via http to %s proxy %s, username %s, pass %s" % (
294 host, self._proxy, self._proxy_username, self._proxy_password))
295 if self.timeout:
296 return connections.HTTPProxyConnection(self._proxy, host,
297 username=self._proxy_username, password=self._proxy_password,
298 timeout=self.timeout)
299 else:
300 return connections.HTTPProxyConnection(self._proxy, host,
301 username=self._proxy_username, password=self._proxy_password)
302
304 - def __init__(self, proxy, proxyUsername=None, proxyPassword=None,
305 transfer=0, encoding=0, refreshCallback=None,
306 progressCallback=None, trusted_certs=None, timeout=None):
307 ProxyTransport.__init__(self, proxy,
308 proxyUsername=proxyUsername, proxyPassword=proxyPassword,
309 transfer=transfer, encoding=encoding,
310 refreshCallback=refreshCallback,
311 progressCallback=progressCallback,
312 timeout=timeout)
313 self.trusted_certs = []
314 for certfile in (trusted_certs or []):
315 self.add_trusted_cert(certfile)
316
318 if not os.access(certfile, os.R_OK):
319 raise ValueError("Certificate file %s is not accessible" % certfile)
320 self.trusted_certs.append(certfile)
321
323 if self.verbose:
324 print("Connecting via https to %s proxy %s, username %s, pass %s" % (
325 host, self._proxy, self._proxy_username, self._proxy_password))
326 if self.timeout:
327 return connections.HTTPSProxyConnection(self._proxy, host,
328 username=self._proxy_username, password=self._proxy_password,
329 trusted_certs=self.trusted_certs, timeout=self.timeout)
330 else:
331 return connections.HTTPSProxyConnection(self._proxy, host,
332 username=self._proxy_username, password=self._proxy_password,
333 trusted_certs=self.trusted_certs)
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
492
493
494
496 """
497 Tries to read data from the supplied stream, and puts the results into a
498 StmartIO object. The data will be in memory or in a temporary file,
499 depending on how much it's been read
500 Returns a SmartIO object
501 """
502 io = SmartIO(max_mem_size=max_mem_size)
503 while 1:
504 chunk = fd.read(bufferSize)
505 if not chunk:
506
507 break
508 io.write(chunk)
509
510 return io
511
512 -def _smart_read(fd, amt, bufferSize=1024, progressCallback=None,
513 max_mem_size=16384):
514
515
516
517
518
519
520
521
522
523
524
525
526 startTime = time.time()
527 lastTime = startTime
528 buf = SmartIO(max_mem_size=max_mem_size)
529
530 origsize = amt
531 while amt > 0:
532 curTime = time.time()
533 l = min(bufferSize, amt)
534 chunk = fd.read(l)
535
536 l = len(chunk)
537 if not l:
538
539 break
540
541
542 amt = amt - l
543 buf.write(chunk)
544 if progressCallback is None:
545
546 continue
547
548
549
550 if curTime - lastTime >= 1 or amt == 0:
551 lastTime = curTime
552
553 bytesRead = float(origsize - amt)
554
555
556
557 speed = bytesRead / ((curTime - startTime) + .000001)
558 if origsize == 0:
559 secs = 0
560 else:
561
562
563
564
565 secs = amt / speed
566 progressCallback(bytesRead, origsize, speed, secs)
567
568
569 buf.seek(0, 0)
570 return buf
571
581
582
583
584
586
587
588 ENCODE_NONE = 0
589 ENCODE_GZIP = 1
590 ENCODE_ZLIB = 2
591 ENCODE_GPG = 3
592
593
594 TRANSFER_NONE = 0
595 TRANSFER_BINARY = 1
596 TRANSFER_BASE64 = 2
597
598
599 encodings = [
600 [None, "__plain"],
601 ["x-gzip", "gzip"],
602 ["x-zlib", "deflate"],
603 ["x-gpg"],
604 ]
605 transfers = [
606 None,
607 "binary",
608 "base64",
609 ]
610
611 - def __init__(self, transfer=0, encoding=0, connection=None, method="POST"):
612
613 if connection:
614 if not isinstance(connection, connections.HTTPConnection):
615 raise Exception("Expected an HTTPConnection type object")
616
617 self.method = method
618
619
620 self._connection = connection
621
622 self.data = None
623 self.headers = UserDictCase()
624 self.encoding = 0
625 self.transfer = 0
626 self.transport_flags = {}
627
628 self.username = None
629 self.password = None
630
631 self._host = None
632 self._handler = None
633 self._http_type = None
634 self._protocol = None
635
636 self.set_transport_flags(transfer=transfer, encoding=encoding)
637
638
639 self.__processed = 0
640
642 if type(arg) in [ type([]), type(()) ]:
643
644
645
646
647
648
649
650
651
652
653 self.headers[name] = ','.join(map(str, arg))
654 else:
655 self.headers[name] = str(arg)
656
658 if name in self.headers:
659 del self.headers[name]
660
662
663 self.data = data
664
665
666 if self.encoding == self.ENCODE_GZIP:
667 import gzip
668 encoding_name = self.encodings[self.ENCODE_GZIP][0]
669 self.set_header("Content-Encoding", encoding_name)
670 f = SmartIO(force_mem=1)
671 gz = gzip.GzipFile(mode="wb", compresslevel=COMPRESS_LEVEL,
672 fileobj = f)
673 if sys.version_info[0] == 3:
674 gz.write(bstr(data))
675 else:
676 gz.write(sstr(data))
677 gz.close()
678 self.data = f.getvalue()
679 f.close()
680 elif self.encoding == self.ENCODE_ZLIB:
681 import zlib
682 encoding_name = self.encodings[self.ENCODE_ZLIB][0]
683 self.set_header("Content-Encoding", encoding_name)
684 obj = zlib.compressobj(COMPRESS_LEVEL)
685 self.data = obj.compress(data) + obj.flush()
686 elif self.encoding == self.ENCODE_GPG:
687
688 raise NotImplementedError(self.transfer, self.encoding)
689
690
691 if self.transfer == self.TRANSFER_BINARY:
692 transfer_name = self.transfers[self.TRANSFER_BINARY]
693 self.set_header("Content-Transfer-Encoding", transfer_name)
694 self.set_header("Content-Type", "application/binary")
695 elif self.transfer == self.TRANSFER_BASE64:
696 import base64
697 transfer_name = self.transfers[self.TRANSFER_BASE64]
698 self.set_header("Content-Transfer-Encoding", transfer_name)
699 self.set_header("Content-Type", "text/base64")
700 self.data = base64.encodestring(self.data)
701
702 self.set_header("Content-Length", len(self.data))
703
704 rpc_version = __version__
705 if len(__version__.split()) > 1:
706 rpc_version = __version__.split()[1]
707
708
709 self.set_header("X-Transport-Info",
710 'Extended Capabilities Transport (C) Red Hat, Inc (version %s)' %
711 rpc_version)
712 self.__processed = 1
713
714
716 self.transfer = transfer
717 self.encoding = encoding
718 self.transport_flags.update(kwargs)
719
743
745 """Returns true if the response is acceptable"""
746 if response.status == 200:
747 return 1
748 if response.status in (301, 302):
749 return 1
750 if response.status != 206:
751 return 0
752
753 if not self.transport_flags.get('allow_partial_content'):
754 return 0
755 if response.msg['Content-Type'] != 'application/octet-stream':
756
757
758 return 0
759 return 1
760
762 if self._connection:
763 self._connection.close()
764 self._connection = None
765
767 """Given a string or numeric representation of a transfer, return the
768 transfer code"""
769 if transfer is None:
770
771 return 0
772 if isinstance(transfer, IntType) and 0 <= transfer < len(Output.transfers):
773 return transfer
774 if isinstance(transfer, StringType):
775 for i in range(len(Output.transfers)):
776 if Output.transfers[i] == transfer.lower():
777 return i
778 if strict:
779 raise ValueError("Unsupported transfer %s" % transfer)
780
781 return 0
782
784 """Given a string or numeric representation of an encoding, return the
785 encoding code"""
786 if encoding is None:
787
788 return 0
789 if isinstance(encoding, IntType) and 0 <= encoding < len(Output.encodings):
790 return encoding
791 if isinstance(encoding, StringType):
792 for i in range(len(Output.encodings)):
793 if encoding.lower() in Output.encodings[i]:
794 return i
795 if strict:
796 raise ValueError("Unsupported encoding %s" % encoding)
797
798 return 0
799
800 Output = BaseOutput
801
802
804 - def __init__(self, file_obj, length = 0, name = None,
805 progressCallback=None, bufferSize=16384):
806 self.length = length
807 self.file_obj = file_obj
808 self.close = file_obj.close
809 self.bufferSize=bufferSize
810 self.name = ""
811 if name:
812 self.name = name[name.rfind("/")+1:]
813 self.progressCallback = progressCallback
814
817
818 - def read(self, amt=None):
819
820 if amt is None:
821 fd = self._get_file()
822 return fd.read()
823
824 return self.file_obj.read(amt)
825
827 """Copies the contents of this File object into another file
828 object"""
829 fd = self._get_file()
830 while 1:
831 buf = fd.read(self.bufferSize)
832 if not buf:
833 break
834 if sys.version_info[0] == 3:
835 file.write(bstr(buf))
836 else:
837 file.write(sstr(buf))
838 return file
839
841 """Read everything into a temporary file and call the progress
842 callbacks if the file length is defined, or just reads till EOF"""
843 if self.length:
844 io = _smart_read(self.file_obj, self.length,
845 bufferSize=self.bufferSize,
846 progressCallback=self.progressCallback)
847 io.seek(0, 0)
848 else:
849
850 io = _smart_total_read(self.file_obj, bufferSize=self.bufferSize)
851 io.seek(0, 0)
852 return io
853
858