~andrewjbeach/juju-ci-tools/make-local-patcher

« back to all changes in this revision

Viewing changes to azure-sdk-for-python-master/azure/http/httpclient.py

  • Committer: Curtis Hovey
  • Date: 2015-06-11 19:35:22 UTC
  • mto: This revision was merged to the branch mainline in revision 983.
  • Revision ID: curtis@canonical.com-20150611193522-o2nqkqb04o2i75wv
Remove euca_dump_logs because it has not been used this year.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#-------------------------------------------------------------------------
 
2
# Copyright (c) Microsoft.  All rights reserved.
 
3
#
 
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
 
8
#
 
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
#--------------------------------------------------------------------------
 
15
import base64
 
16
import os
 
17
import sys
 
18
 
 
19
if sys.version_info < (3,):
 
20
    from httplib import (
 
21
        HTTPSConnection,
 
22
        HTTPConnection,
 
23
        HTTP_PORT,
 
24
        HTTPS_PORT,
 
25
        )
 
26
    from urlparse import urlparse
 
27
else:
 
28
    from http.client import (
 
29
        HTTPSConnection,
 
30
        HTTPConnection,
 
31
        HTTP_PORT,
 
32
        HTTPS_PORT,
 
33
        )
 
34
    from urllib.parse import urlparse
 
35
 
 
36
from azure.http import HTTPError, HTTPResponse
 
37
from azure import _USER_AGENT_STRING, _update_request_uri_query
 
38
 
 
39
 
 
40
class _HTTPClient(object):
 
41
 
 
42
    '''
 
43
    Takes the request and sends it to cloud service and returns the response.
 
44
    '''
 
45
 
 
46
    def __init__(self, service_instance, cert_file=None, account_name=None,
 
47
                 account_key=None, service_namespace=None, issuer=None,
 
48
                 protocol='https'):
 
49
        '''
 
50
        service_instance: service client instance.
 
51
        cert_file:
 
52
            certificate file name/location. This is only used in hosted
 
53
            service management.
 
54
        account_name: the storage account.
 
55
        account_key:
 
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.
 
60
        '''
 
61
        self.service_instance = service_instance
 
62
        self.status = None
 
63
        self.respheader = None
 
64
        self.message = 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
 
69
        self.issuer = issuer
 
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()
 
76
 
 
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).
 
81
            #
 
82
            # We used to only support certificates installed in the Windows
 
83
            # Certificate Store.
 
84
            #   cert_file example: CURRENT_USER\my\CertificateName
 
85
            #
 
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
 
89
            #
 
90
            # When using OpenSSL .pem certificate file on Windows, make sure
 
91
            # you are on CPython 2.7.4 or later.
 
92
 
 
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):
 
96
                return False
 
97
 
 
98
        return True
 
99
 
 
100
    def set_proxy(self, host, port, user, password):
 
101
        '''
 
102
        Sets the proxy server host and port for the HTTP CONNECT Tunnelling.
 
103
 
 
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.
 
108
        '''
 
109
        self.proxy_host = host
 
110
        self.proxy_port = port
 
111
        self.proxy_user = user
 
112
        self.proxy_password = password
 
113
 
 
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
 
120
 
 
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
 
127
        else:
 
128
            if ':' in target_host:
 
129
                target_host, _, target_port = target_host.rpartition(':')
 
130
            if self.proxy_host:
 
131
                proxy_host = target_host
 
132
                proxy_port = target_port
 
133
                host = self.proxy_host
 
134
                port = self.proxy_port
 
135
            else:
 
136
                host = target_host
 
137
                port = target_port
 
138
 
 
139
            if protocol == 'http':
 
140
                connection = HTTPConnection(host, int(port))
 
141
            else:
 
142
                connection = HTTPSConnection(
 
143
                    host, int(port), cert_file=self.cert_file)
 
144
 
 
145
        if self.proxy_host:
 
146
            headers = None
 
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)
 
152
 
 
153
        return connection
 
154
 
 
155
    def send_request_headers(self, connection, request_headers):
 
156
        if self.use_httplib:
 
157
            if self.proxy_host:
 
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))
 
164
 
 
165
        for name, value in request_headers:
 
166
            if value:
 
167
                connection.putheader(name, value)
 
168
 
 
169
        connection.putheader('User-Agent', _USER_AGENT_STRING)
 
170
        connection.endheaders()
 
171
 
 
172
    def send_request_body(self, connection, request_body):
 
173
        if 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)
 
179
 
 
180
    def perform_request(self, request):
 
181
        ''' Sends request to cloud service server and return the response. '''
 
182
        connection = self.get_connection(request)
 
183
        try:
 
184
            connection.putrequest(request.method, request.path)
 
185
 
 
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)
 
190
 
 
191
            self.send_request_headers(connection, request.headers)
 
192
            self.send_request_body(connection, request.body)
 
193
 
 
194
            resp = connection.getresponse()
 
195
            self.status = int(resp.status)
 
196
            self.message = resp.reason
 
197
            self.respheader = headers = resp.getheaders()
 
198
 
 
199
            # for consistency across platforms, make header names lowercase
 
200
            for i, value in enumerate(headers):
 
201
                headers[i] = (value[0].lower(), value[1])
 
202
 
 
203
            respbody = None
 
204
            if resp.length is None:
 
205
                respbody = resp.read()
 
206
            elif resp.length > 0:
 
207
                respbody = resp.read(resp.length)
 
208
 
 
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)
 
220
 
 
221
            return response
 
222
        finally:
 
223
            connection.close()