1
#-------------------------------------------------------------------------
2
# Copyright (c) Microsoft. All rights reserved.
4
# Licensed under the Apache License, Version 2.0 (the "License");
5
# you may not use this file except in compliance with the License.
6
# You may obtain a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14
#--------------------------------------------------------------------------
19
if sys.version_info < (3,):
26
from urlparse import urlparse
28
from http.client import (
34
from urllib.parse import urlparse
36
from azure.http import HTTPError, HTTPResponse
37
from azure import _USER_AGENT_STRING, _update_request_uri_query
40
class _HTTPClient(object):
43
Takes the request and sends it to cloud service and returns the response.
46
def __init__(self, service_instance, cert_file=None, account_name=None,
47
account_key=None, service_namespace=None, issuer=None,
50
service_instance: service client instance.
52
certificate file name/location. This is only used in hosted
54
account_name: the storage account.
56
the storage account access key for storage services or servicebus
57
access key for service bus service.
58
service_namespace: the service namespace for service bus.
59
issuer: the issuer for service bus service.
61
self.service_instance = service_instance
63
self.respheader = None
65
self.cert_file = cert_file
66
self.account_name = account_name
67
self.account_key = account_key
68
self.service_namespace = service_namespace
70
self.protocol = protocol
71
self.proxy_host = None
72
self.proxy_port = None
73
self.proxy_user = None
74
self.proxy_password = None
75
self.use_httplib = self.should_use_httplib()
77
def should_use_httplib(self):
78
if sys.platform.lower().startswith('win') and self.cert_file:
79
# On Windows, auto-detect between Windows Store Certificate
80
# (winhttp) and OpenSSL .pem certificate file (httplib).
82
# We used to only support certificates installed in the Windows
84
# cert_file example: CURRENT_USER\my\CertificateName
86
# We now support using an OpenSSL .pem certificate file,
87
# for a consistent experience across all platforms.
88
# cert_file example: account\certificate.pem
90
# When using OpenSSL .pem certificate file on Windows, make sure
91
# you are on CPython 2.7.4 or later.
93
# If it's not an existing file on disk, then treat it as a path in
94
# the Windows Certificate Store, which means we can't use httplib.
95
if not os.path.isfile(self.cert_file):
100
def set_proxy(self, host, port, user, password):
102
Sets the proxy server host and port for the HTTP CONNECT Tunnelling.
104
host: Address of the proxy. Ex: '192.168.0.100'
105
port: Port of the proxy. Ex: 6000
106
user: User for proxy authorization.
107
password: Password for proxy authorization.
109
self.proxy_host = host
110
self.proxy_port = port
111
self.proxy_user = user
112
self.proxy_password = password
114
def get_connection(self, request):
115
''' Create connection for the request. '''
116
protocol = request.protocol_override \
117
if request.protocol_override else self.protocol
118
target_host = request.host
119
target_port = HTTP_PORT if protocol == 'http' else HTTPS_PORT
121
if not self.use_httplib:
122
import azure.http.winhttp
123
connection = azure.http.winhttp._HTTPConnection(
124
target_host, cert_file=self.cert_file, protocol=protocol)
125
proxy_host = self.proxy_host
126
proxy_port = self.proxy_port
128
if ':' in target_host:
129
target_host, _, target_port = target_host.rpartition(':')
131
proxy_host = target_host
132
proxy_port = target_port
133
host = self.proxy_host
134
port = self.proxy_port
139
if protocol == 'http':
140
connection = HTTPConnection(host, int(port))
142
connection = HTTPSConnection(
143
host, int(port), cert_file=self.cert_file)
147
if self.proxy_user and self.proxy_password:
148
auth = base64.encodestring(
149
"{0}:{1}".format(self.proxy_user, self.proxy_password))
150
headers = {'Proxy-Authorization': 'Basic {0}'.format(auth)}
151
connection.set_tunnel(proxy_host, int(proxy_port), headers)
155
def send_request_headers(self, connection, request_headers):
158
for i in connection._buffer:
159
if i.startswith("Host: "):
160
connection._buffer.remove(i)
161
connection.putheader(
162
'Host', "{0}:{1}".format(connection._tunnel_host,
163
connection._tunnel_port))
165
for name, value in request_headers:
167
connection.putheader(name, value)
169
connection.putheader('User-Agent', _USER_AGENT_STRING)
170
connection.endheaders()
172
def send_request_body(self, connection, request_body):
174
assert isinstance(request_body, bytes)
175
connection.send(request_body)
176
elif (not isinstance(connection, HTTPSConnection) and
177
not isinstance(connection, HTTPConnection)):
178
connection.send(None)
180
def perform_request(self, request):
181
''' Sends request to cloud service server and return the response. '''
182
connection = self.get_connection(request)
184
connection.putrequest(request.method, request.path)
186
if not self.use_httplib:
187
if self.proxy_host and self.proxy_user:
188
connection.set_proxy_credentials(
189
self.proxy_user, self.proxy_password)
191
self.send_request_headers(connection, request.headers)
192
self.send_request_body(connection, request.body)
194
resp = connection.getresponse()
195
self.status = int(resp.status)
196
self.message = resp.reason
197
self.respheader = headers = resp.getheaders()
199
# for consistency across platforms, make header names lowercase
200
for i, value in enumerate(headers):
201
headers[i] = (value[0].lower(), value[1])
204
if resp.length is None:
205
respbody = resp.read()
206
elif resp.length > 0:
207
respbody = resp.read(resp.length)
209
response = HTTPResponse(
210
int(resp.status), resp.reason, headers, respbody)
211
if self.status == 307:
212
new_url = urlparse(dict(headers)['location'])
213
request.host = new_url.hostname
214
request.path = new_url.path
215
request.path, request.query = _update_request_uri_query(request)
216
return self.perform_request(request)
217
if self.status >= 300:
218
raise HTTPError(self.status, self.message,
219
self.respheader, respbody)