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