1# Copyright 2016 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 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"""Transport adapter for http.client, for internal use only.""" 16 17import logging 18import socket 19 20import six 21from six.moves import http_client 22from six.moves import urllib 23 24from google.auth import exceptions 25from google.auth import transport 26 27_LOGGER = logging.getLogger(__name__) 28 29 30class Response(transport.Response): 31 """http.client transport response adapter. 32 33 Args: 34 response (http.client.HTTPResponse): The raw http client response. 35 """ 36 37 def __init__(self, response): 38 self._status = response.status 39 self._headers = {key.lower(): value for key, value in response.getheaders()} 40 self._data = response.read() 41 42 @property 43 def status(self): 44 return self._status 45 46 @property 47 def headers(self): 48 return self._headers 49 50 @property 51 def data(self): 52 return self._data 53 54 55class Request(transport.Request): 56 """http.client transport request adapter.""" 57 58 def __call__( 59 self, url, method="GET", body=None, headers=None, timeout=None, **kwargs 60 ): 61 """Make an HTTP request using http.client. 62 63 Args: 64 url (str): The URI to be requested. 65 method (str): The HTTP method to use for the request. Defaults 66 to 'GET'. 67 body (bytes): The payload / body in HTTP request. 68 headers (Mapping): Request headers. 69 timeout (Optional(int)): The number of seconds to wait for a 70 response from the server. If not specified or if None, the 71 socket global default timeout will be used. 72 kwargs: Additional arguments passed throught to the underlying 73 :meth:`~http.client.HTTPConnection.request` method. 74 75 Returns: 76 Response: The HTTP response. 77 78 Raises: 79 google.auth.exceptions.TransportError: If any exception occurred. 80 """ 81 # socket._GLOBAL_DEFAULT_TIMEOUT is the default in http.client. 82 if timeout is None: 83 timeout = socket._GLOBAL_DEFAULT_TIMEOUT 84 85 # http.client doesn't allow None as the headers argument. 86 if headers is None: 87 headers = {} 88 89 # http.client needs the host and path parts specified separately. 90 parts = urllib.parse.urlsplit(url) 91 path = urllib.parse.urlunsplit( 92 ("", "", parts.path, parts.query, parts.fragment) 93 ) 94 95 if parts.scheme != "http": 96 raise exceptions.TransportError( 97 "http.client transport only supports the http scheme, {}" 98 "was specified".format(parts.scheme) 99 ) 100 101 connection = http_client.HTTPConnection(parts.netloc, timeout=timeout) 102 103 try: 104 _LOGGER.debug("Making request: %s %s", method, url) 105 106 connection.request(method, path, body=body, headers=headers, **kwargs) 107 response = connection.getresponse() 108 return Response(response) 109 110 except (http_client.HTTPException, socket.error) as caught_exc: 111 new_exc = exceptions.TransportError(caught_exc) 112 six.raise_from(new_exc, caught_exc) 113 114 finally: 115 connection.close() 116