]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/lib/py/src/transport/THttpClient.py
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / py / src / transport / THttpClient.py
1 #
2 # Licensed to the Apache Software Foundation (ASF) under one
3 # or more contributor license agreements. See the NOTICE file
4 # distributed with this work for additional information
5 # regarding copyright ownership. The ASF licenses this file
6 # to you under the Apache License, Version 2.0 (the
7 # "License"); you may not use this file except in compliance
8 # with the License. You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing,
13 # software distributed under the License is distributed on an
14 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 # KIND, either express or implied. See the License for the
16 # specific language governing permissions and limitations
17 # under the License.
18 #
19
20 from io import BytesIO
21 import os
22 import ssl
23 import sys
24 import warnings
25 import base64
26
27 from six.moves import urllib
28 from six.moves import http_client
29
30 from .TTransport import TTransportBase
31 import six
32
33
34 class THttpClient(TTransportBase):
35 """Http implementation of TTransport base."""
36
37 def __init__(self, uri_or_host, port=None, path=None, cafile=None, cert_file=None, key_file=None, ssl_context=None):
38 """THttpClient supports two different types of construction:
39
40 THttpClient(host, port, path) - deprecated
41 THttpClient(uri, [port=<n>, path=<s>, cafile=<filename>, cert_file=<filename>, key_file=<filename>, ssl_context=<context>])
42
43 Only the second supports https. To properly authenticate against the server,
44 provide the client's identity by specifying cert_file and key_file. To properly
45 authenticate the server, specify either cafile or ssl_context with a CA defined.
46 NOTE: if both cafile and ssl_context are defined, ssl_context will override cafile.
47 """
48 if port is not None:
49 warnings.warn(
50 "Please use the THttpClient('http{s}://host:port/path') constructor",
51 DeprecationWarning,
52 stacklevel=2)
53 self.host = uri_or_host
54 self.port = port
55 assert path
56 self.path = path
57 self.scheme = 'http'
58 else:
59 parsed = urllib.parse.urlparse(uri_or_host)
60 self.scheme = parsed.scheme
61 assert self.scheme in ('http', 'https')
62 if self.scheme == 'http':
63 self.port = parsed.port or http_client.HTTP_PORT
64 elif self.scheme == 'https':
65 self.port = parsed.port or http_client.HTTPS_PORT
66 self.certfile = cert_file
67 self.keyfile = key_file
68 self.context = ssl.create_default_context(cafile=cafile) if (cafile and not ssl_context) else ssl_context
69 self.host = parsed.hostname
70 self.path = parsed.path
71 if parsed.query:
72 self.path += '?%s' % parsed.query
73 try:
74 proxy = urllib.request.getproxies()[self.scheme]
75 except KeyError:
76 proxy = None
77 else:
78 if urllib.request.proxy_bypass(self.host):
79 proxy = None
80 if proxy:
81 parsed = urllib.parse.urlparse(proxy)
82 self.realhost = self.host
83 self.realport = self.port
84 self.host = parsed.hostname
85 self.port = parsed.port
86 self.proxy_auth = self.basic_proxy_auth_header(parsed)
87 else:
88 self.realhost = self.realport = self.proxy_auth = None
89 self.__wbuf = BytesIO()
90 self.__http = None
91 self.__http_response = None
92 self.__timeout = None
93 self.__custom_headers = None
94
95 @staticmethod
96 def basic_proxy_auth_header(proxy):
97 if proxy is None or not proxy.username:
98 return None
99 ap = "%s:%s" % (urllib.parse.unquote(proxy.username),
100 urllib.parse.unquote(proxy.password))
101 cr = base64.b64encode(ap).strip()
102 return "Basic " + cr
103
104 def using_proxy(self):
105 return self.realhost is not None
106
107 def open(self):
108 if self.scheme == 'http':
109 self.__http = http_client.HTTPConnection(self.host, self.port,
110 timeout=self.__timeout)
111 elif self.scheme == 'https':
112 self.__http = http_client.HTTPSConnection(self.host, self.port,
113 key_file=self.keyfile,
114 cert_file=self.certfile,
115 timeout=self.__timeout,
116 context=self.context)
117 if self.using_proxy():
118 self.__http.set_tunnel(self.realhost, self.realport,
119 {"Proxy-Authorization": self.proxy_auth})
120
121 def close(self):
122 self.__http.close()
123 self.__http = None
124 self.__http_response = None
125
126 def isOpen(self):
127 return self.__http is not None
128
129 def setTimeout(self, ms):
130 if ms is None:
131 self.__timeout = None
132 else:
133 self.__timeout = ms / 1000.0
134
135 def setCustomHeaders(self, headers):
136 self.__custom_headers = headers
137
138 def read(self, sz):
139 return self.__http_response.read(sz)
140
141 def write(self, buf):
142 self.__wbuf.write(buf)
143
144 def flush(self):
145 if self.isOpen():
146 self.close()
147 self.open()
148
149 # Pull data out of buffer
150 data = self.__wbuf.getvalue()
151 self.__wbuf = BytesIO()
152
153 # HTTP request
154 if self.using_proxy() and self.scheme == "http":
155 # need full URL of real host for HTTP proxy here (HTTPS uses CONNECT tunnel)
156 self.__http.putrequest('POST', "http://%s:%s%s" %
157 (self.realhost, self.realport, self.path))
158 else:
159 self.__http.putrequest('POST', self.path)
160
161 # Write headers
162 self.__http.putheader('Content-Type', 'application/x-thrift')
163 self.__http.putheader('Content-Length', str(len(data)))
164 if self.using_proxy() and self.scheme == "http" and self.proxy_auth is not None:
165 self.__http.putheader("Proxy-Authorization", self.proxy_auth)
166
167 if not self.__custom_headers or 'User-Agent' not in self.__custom_headers:
168 user_agent = 'Python/THttpClient'
169 script = os.path.basename(sys.argv[0])
170 if script:
171 user_agent = '%s (%s)' % (user_agent, urllib.parse.quote(script))
172 self.__http.putheader('User-Agent', user_agent)
173
174 if self.__custom_headers:
175 for key, val in six.iteritems(self.__custom_headers):
176 self.__http.putheader(key, val)
177
178 self.__http.endheaders()
179
180 # Write payload
181 self.__http.send(data)
182
183 # Get reply to flush the request
184 self.__http_response = self.__http.getresponse()
185 self.code = self.__http_response.status
186 self.message = self.__http_response.reason
187 self.headers = self.__http_response.msg