File: httpclient.py

package info (click to toggle)
azure-multiapi-storage-python 0.5.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 23,652 kB
  • sloc: python: 222,802; sh: 61; makefile: 3
file content (125 lines) | stat: -rw-r--r-- 4,773 bytes parent folder | download
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
115
116
117
118
119
120
121
122
123
124
125
#-------------------------------------------------------------------------
# Copyright (c) Microsoft.  All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#--------------------------------------------------------------------------
import base64
import sys

if sys.version_info < (3,):
    from httplib import (
        HTTP_PORT,
        HTTPS_PORT,
    )
    from urllib2 import quote as url_quote
else:
    from http.client import (
        HTTP_PORT,
        HTTPS_PORT,
    )
    from urllib.parse import quote as url_quote

from . import HTTPError, HTTPResponse
from .._serialization import _get_data_bytes_or_stream_only

class _HTTPClient(object):
    '''
    Takes the request and sends it to cloud service and returns the response.
    '''

    def __init__(self, protocol=None, session=None, timeout=None):
        '''
        :param str protocol:
            http or https.
        :param requests.Session request_session:
            session object created with requests library (or compatible).
        :param int timeout:
            timeout for the http request, in seconds.
        '''
        self.protocol = protocol
        self.session = session
        self.timeout = timeout

        # By default, requests adds an Accept:*/* and Accept-Encoding to the session, 
        # which causes issues with some Azure REST APIs. Removing these here gives us 
        # the flexibility to add it back on a case by case basis.
        if 'Accept' in self.session.headers:
            del self.session.headers['Accept']

        if 'Accept-Encoding' in self.session.headers:
            del self.session.headers['Accept-Encoding']

        self.proxies = None

    def set_proxy(self, host, port, user, password):
        '''
        Sets the proxy server host and port for the HTTP CONNECT Tunnelling.

        Note that we set the proxies directly on the request later on rather than
        using the session object as requests has a bug where session proxy is ignored
        in favor of environment proxy. So, auth will not work unless it is passed
        directly when making the request as this overrides both.

        :param str host:
            Address of the proxy. Ex: '192.168.0.100'
        :param int port:
            Port of the proxy. Ex: 6000
        :param str user:
            User for proxy authorization.
        :param str password:
            Password for proxy authorization.
        '''
        if user and password:
            proxy_string = '{}:{}@{}:{}'.format(user, password, host, port) 
        else:
            proxy_string = '{}:{}'.format(host, port) 

        self.proxies = {}
        self.proxies['http'] = 'http://{}'.format(proxy_string)
        self.proxies['https'] = 'https://{}'.format(proxy_string)

    def perform_request(self, request):
        '''
        Sends an HTTPRequest to Azure Storage and returns an HTTPResponse. If 
        the response code indicates an error, raise an HTTPError.    
        
        :param HTTPRequest request:
            The request to serialize and send.
        :return: An HTTPResponse containing the parsed HTTP response.
        :rtype: :class:`~azure.storage._http.HTTPResponse`
        '''
        # Verify the body is in bytes or either a file-like/stream object
        if request.body:
            request.body = _get_data_bytes_or_stream_only('request.body', request.body)

        # Construct the URI
        uri = self.protocol.lower() + '://' + request.host + request.path

        # Send the request
        response = self.session.request(request.method, 
                                        uri,
                                        params=request.query,
                                        headers=request.headers, 
                                        data=request.body or None,
                                        timeout=self.timeout,
                                        proxies=self.proxies)

        # Parse the response
        status = int(response.status_code)
        respheaders = {}
        for key, name in response.headers.items():
            respheaders[key.lower()] = name

        wrap = HTTPResponse(status, response.reason, respheaders, response.content)
        response.close()

        return wrap