requests sessions this module provides a session object to manage and persist settings across requests cookies auth proxies formerly defined here reexposed here for backward compatibility preferred clock based on which one is more accurate on a given system determines appropriate setting for a given request taking into account the explicit setting on that request and the setting in the session if a setting is a dictionary they will be merged together using dictclass bypass if not a dictionary e g verify remove keys that are set to none extract keys first to avoid altering the dictionary during iteration properly merges both requests and session hooks this is necessary because when requesthooks response the merge breaks session hooks entirely receives a response returns a redirect uri or none due to the nature of how requests processes redirects this method will be called at least once upon the original response and at least twice on each subsequent redirect response if any if a custom mixin is used to handle this logic it may be advantageous to cache the redirect location onto the response object as a private attribute if resp isredirect location resp headerslocation currently the underlying http module on py3 decode headers in latin1 but empirical evidence suggests that latin1 is very rarely used with nonascii characters in http headers it is more likely to get utf8 header rather than latin1 this causes incorrect handling of utf8 encoded location headers to solve this we reencode the location in latin1 location location encodelatin1 return tonativestringlocation utf8 return none def shouldstripauthself oldurl newurl special case allow http https redirect when using the standard ports this isn t specified by rfc 7235 but is kept to avoid breaking backwards compatibility with older versions of requests that allowed any redirects on the same host handle default port usage corresponding to scheme standard case root uri must match receives a response returns a generator of responses or requests hist keep track of history url self getredirecttargetresp previousfragment urlparsereq url fragment while url preparedrequest req copy update history and keep track of redirects resp history must ignore the original request in this loop hist appendresp resp history hist1 try resp content consume socket so it can be released except chunkedencodingerror contentdecodingerror runtimeerror resp raw readdecodecontentfalse if lenresp history self maxredirects raise toomanyredirects fexceeded self maxredirects redirects responseresp release the connection back into the pool resp close handle redirection without scheme see rfc 1808 section 4 if url startswith parsedrurl urlparseresp url url jointonativestringparsedrurl scheme url normalize url case and attach previous fragment if needed rfc 7231 7 1 2 parsed urlparseurl if parsed fragment and previousfragment parsed parsed replacefragmentpreviousfragment elif parsed fragment previousfragment parsed fragment url parsed geturl facilitate relative location headers as allowed by rfc 7231 e g pathtoresource instead of http domain tldpathtoresource compliant with rfc3986 we percent encode the url if not parsed netloc url urljoinresp url requoteuriurl else url requoteuriurl preparedrequest url tonativestringurl self rebuildmethodpreparedrequest resp https github compsfrequestsissues1084 if resp statuscode not in codes temporaryredirect codes permanentredirect https github compsfrequestsissues3490 purgedheaders contentlength contenttype transferencoding for header in purgedheaders preparedrequest headers popheader none preparedrequest body none headers preparedrequest headers headers popcookie none extract any cookies sent on the response to the cookiejar in the new request because we ve mutated our copied prepared request use the old one that we haven t yet touched extractcookiestojarpreparedrequest cookies req resp raw mergecookiespreparedrequest cookies self cookies preparedrequest preparecookiespreparedrequest cookies rebuild auth and proxy information proxies self rebuildproxiespreparedrequest proxies self rebuildauthpreparedrequest resp a failed tell sets bodyposition to object this nonnone value ensures rewindable will be true allowing us to raise an unrewindablebodyerror instead of hanging the connection rewindable preparedrequest bodyposition is not none and contentlength in headers or transferencoding in headers attempt to rewind consumed filelike object if rewindable rewindbodypreparedrequest override the original request req preparedrequest if yieldrequests yield req else resp self send req streamstream timeouttimeout verifyverify certcert proxiesproxies allowredirectsfalse adapterkwargs extractcookiestojarself cookies preparedrequest resp raw extract redirect url if any for the next loop url self getredirecttargetresp yield resp def rebuildauthself preparedrequest response headers preparedrequest headers url preparedrequest url if ization in headers and self shouldstripauth response request url url if we get redirected to a new host we should strip out any authentication headers del headersization netrc might have more auth for us on our new host newauth getnetrcauthurl if self trustenv else none if newauth is not none preparedrequest prepareauthnewauth def rebuildproxiesself preparedrequest proxies headers preparedrequest headers scheme urlparsepreparedrequest url scheme newproxies resolveproxiespreparedrequest proxies self trustenv if proxyization in headers del headersproxyization try username password getauthfromurlnewproxiesscheme except keyerror username password none none urllib3 handles proxy ization for us in the standard adapter avoid appending this to tls tunneled requests where it may be leaked if not scheme startswithhttps and username and password headersproxyization basicauthstrusername password return newproxies def rebuildmethodself preparedrequest response method preparedrequest method https tools ietf orghtmlrfc7231section6 4 4 if response statuscode codes seeother and method head method get do what the browsers do despite standards first turn 302s into gets if response statuscode codes found and method head method get second if a post is responded to with a 301 turn it into a get this bizarre behaviour is explained in issue 1704 if response statuscode codes moved and method post method get preparedrequest method method class sessionsessionredirectmixin attrs headers cookies auth proxies hooks params verify cert adapters stream trustenv maxredirects def initself a caseinsensitive dictionary of headers to be sent on each class request request sent from this class session session self headers defaultheaders default authentication tuple or object to attach to class request request self auth none dictionary mapping protocol or protocol and host to the url of the proxy e g http foo bar 3128 http host name foo bar 4012 to be used on each class request request self proxies eventhandling hooks self hooks defaulthooks dictionary of querystring data to attach to each class request request the dictionary values may be lists for representing multivalued query parameters self params stream response content default self stream false ssl verification default defaults to true requiring requests to verify the tls certificate at the remote end if verify is set to false requests will accept any tls certificate presented by the server and will ignore hostname mismatches andor expired certificates which will make your application vulnerable to maninthemiddle mitm attacks only set this to false for testing self verify true ssl client certificate default if string path to ssl client cert file pem if tuple cert key pair self cert none maximum number of redirects allowed if the request exceeds this limit a class toomanyredirects exception is raised this defaults to requests models defaultredirectlimit which is 30 self maxredirects defaultredirectlimit trust environment settings for proxy configuration default authentication and similar self trustenv true a cookiejar containing all currently outstanding cookies set on this session by default it is a class requestscookiejar requests cookies requestscookiejar but may be any other cookielib cookiejar compatible object self cookies cookiejarfromdict default connection adapters self adapters ordereddict self mounthttps httpadapter self mounthttp httpadapter def enterself return self def exitself args self close def preparerequestself request cookies request cookies or bootstrap cookiejar if not isinstancecookies cookielib cookiejar cookies cookiejarfromdictcookies merge with session cookies mergedcookies mergecookies mergecookiesrequestscookiejar self cookies cookies set environment s basic authentication if not explicitly set auth request auth if self trustenv and not auth and not self auth auth getnetrcauthrequest url p preparedrequest p prepare methodrequest method upper urlrequest url filesrequest files datarequest data jsonrequest json headersmergesetting request headers self headers dictclasscaseinsensitivedict paramsmergesettingrequest params self params authmergesettingauth self auth cookiesmergedcookies hooksmergehooksrequest hooks self hooks return p def request self method url paramsnone datanone headersnone cookiesnone filesnone authnone timeoutnone allowredirectstrue proxiesnone hooksnone streamnone verifynone certnone jsonnone create the request req request methodmethod upper urlurl headersheaders filesfiles datadata or jsonjson paramsparams or authauth cookiescookies hookshooks prep self preparerequestreq proxies proxies or settings self mergeenvironmentsettings prep url proxies stream verify cert send the request sendkwargs timeout timeout allowredirects allowredirects sendkwargs updatesettings resp self sendprep sendkwargs return resp def getself url kwargs rsends a get request returns class response object param url url for the new class request object param kwargs optional arguments that request takes rtype requests response kwargs setdefaultallowredirects true return self requestoptions url kwargs def headself url kwargs rsends a head request returns class response object param url url for the new class request object param kwargs optional arguments that request takes rtype requests response return self requestpost url datadata jsonjson kwargs def putself url datanone kwargs rsends a put request returns class response object param url url for the new class request object param data optional dictionary list of tuples bytes or filelike object to send in the body of the class request param kwargs optional arguments that request takes rtype requests response return self requestpatch url datadata kwargs def deleteself url kwargs rsends a delete request returns class response object param url url for the new class request object param kwargs optional arguments that request takes rtype requests response send a given preparedrequest rtype requests response set defaults that the hooks can utilize to ensure they always have the correct parameters to reproduce the previous request it s possible that users might accidentally send a request object guard against that specific failure case set up variables needed for resolveredirects and dispatching of hooks get the appropriate adapter to use start time approximately of the request send the request total elapsed time of the request approximately response manipulation hooks persist cookies if the hooks create history then we want those cookies too resolve redirects if allowed redirect resolving generator shuffle things around if there s history insert the first original request at the start get the last request made if redirects aren t being followed store the response on the request for response next check the environment and merge it with some settings rtype dict gather clues from the surrounding environment set environment s proxies look for requests environment configuration and be compatible with curl merge all the kwargs returns the appropriate connection adapter for the given url rtype requests adapters baseadapter nothing matches closes all adapters and as such the session for v in self adapters values v close def mountself prefix adapter self adaptersprefix adapter keystomove k for k in self adapters if lenk lenprefix for key in keystomove self adapterskey self adapters popkey def getstateself state attr getattrself attr none for attr in self attrs return state def setstateself state for attr value in state items setattrself attr value def session return session formerly defined here reexposed here for backward compatibility noqa f401 noqa f401 preferred clock based on which one is more accurate on a given system determines appropriate setting for a given request taking into account the explicit setting on that request and the setting in the session if a setting is a dictionary they will be merged together using dict_class bypass if not a dictionary e g verify remove keys that are set to none extract keys first to avoid altering the dictionary during iteration properly merges both requests and session hooks this is necessary because when request_hooks response the merge breaks session hooks entirely receives a response returns a redirect uri or none due to the nature of how requests processes redirects this method will be called at least once upon the original response and at least twice on each subsequent redirect response if any if a custom mixin is used to handle this logic it may be advantageous to cache the redirect location onto the response object as a private attribute currently the underlying http module on py3 decode headers in latin1 but empirical evidence suggests that latin1 is very rarely used with non ascii characters in http headers it is more likely to get utf8 header rather than latin1 this causes incorrect handling of utf8 encoded location headers to solve this we re encode the location in latin1 decide whether ization header should be removed when redirecting special case allow http https redirect when using the standard ports this isn t specified by rfc 7235 but is kept to avoid breaking backwards compatibility with older versions of requests that allowed any redirects on the same host handle default port usage corresponding to scheme standard case root uri must match receives a response returns a generator of responses or requests keep track of history update history and keep track of redirects resp history must ignore the original request in this loop consume socket so it can be released release the connection back into the pool handle redirection without scheme see rfc 1808 section 4 normalize url case and attach previous fragment if needed rfc 7231 7 1 2 facilitate relative location headers as allowed by rfc 7231 e g path to resource instead of http domain tld path to resource compliant with rfc3986 we percent encode the url https github com psf requests issues 1084 https github com psf requests issues 3490 extract any cookies sent on the response to the cookiejar in the new request because we ve mutated our copied prepared request use the old one that we haven t yet touched rebuild auth and proxy information a failed tell sets _body_position to object this non none value ensures rewindable will be true allowing us to raise an unrewindablebodyerror instead of hanging the connection attempt to rewind consumed file like object override the original request extract redirect url if any for the next loop when being redirected we may want to strip authentication from the request to avoid leaking credentials this method intelligently removes and reapplies authentication where possible to avoid credential loss if we get redirected to a new host we should strip out any authentication headers netrc might have more auth for us on our new host this method re evaluates the proxy configuration by considering the environment variables if we are redirected to a url covered by no_proxy we strip the proxy configuration otherwise we set missing proxy keys for this url in case they were stripped by a previous redirect this method also replaces the proxy ization header where necessary rtype dict urllib3 handles proxy ization for us in the standard adapter avoid appending this to tls tunneled requests where it may be leaked when being redirected we may want to change the method of the request based on certain specs or browser behavior https tools ietf org html rfc7231 section 6 4 4 do what the browsers do despite standards first turn 302s into gets second if a post is responded to with a 301 turn it into a get this bizarre behaviour is explained in issue 1704 a requests session provides cookie persistence connection pooling and configuration basic usage import requests s requests session s get https httpbin org get response 200 or as a context manager with requests session as s s get https httpbin org get response 200 a case insensitive dictionary of headers to be sent on each class request request sent from this class session session default authentication tuple or object to attach to class request request dictionary mapping protocol or protocol and host to the url of the proxy e g http foo bar 3128 http host name foo bar 4012 to be used on each class request request event handling hooks dictionary of querystring data to attach to each class request request the dictionary values may be lists for representing multivalued query parameters stream response content default ssl verification default defaults to true requiring requests to verify the tls certificate at the remote end if verify is set to false requests will accept any tls certificate presented by the server and will ignore hostname mismatches and or expired certificates which will make your application vulnerable to man in the middle mitm attacks only set this to false for testing ssl client certificate default if string path to ssl client cert file pem if tuple cert key pair maximum number of redirects allowed if the request exceeds this limit a class toomanyredirects exception is raised this defaults to requests models default_redirect_limit which is 30 trust environment settings for proxy configuration default authentication and similar a cookiejar containing all currently outstanding cookies set on this session by default it is a class requestscookiejar requests cookies requestscookiejar but may be any other cookielib cookiejar compatible object default connection adapters constructs a class preparedrequest preparedrequest for transmission and returns it the class preparedrequest has settings merged from the class request request instance and those of the class session param request class request instance to prepare with this session s settings rtype requests preparedrequest bootstrap cookiejar merge with session cookies set environment s basic authentication if not explicitly set constructs a class request request prepares it and sends it returns class response response object param method method for the new class request object param url url for the new class request object param params optional dictionary or bytes to be sent in the query string for the class request param data optional dictionary list of tuples bytes or file like object to send in the body of the class request param json optional json to send in the body of the class request param headers optional dictionary of http headers to send with the class request param cookies optional dict or cookiejar object to send with the class request param files optional dictionary of filename file like objects for multipart encoding upload param auth optional auth tuple or callable to enable basic digest custom http auth param timeout optional how long to wait for the server to send data before giving up as a float or a ref connect timeout read timeout timeouts tuple type timeout float or tuple param allow_redirects optional set to true by default type allow_redirects bool param proxies optional dictionary mapping protocol or protocol and hostname to the url of the proxy param hooks optional dictionary mapping hook name to one event or list of events event must be callable param stream optional whether to immediately download the response content defaults to false param verify optional either a boolean in which case it controls whether we verify the server s tls certificate or a string in which case it must be a path to a ca bundle to use defaults to true when set to false requests will accept any tls certificate presented by the server and will ignore hostname mismatches and or expired certificates which will make your application vulnerable to man in the middle mitm attacks setting verify to false may be useful during local development or testing param cert optional if string path to ssl client cert file pem if tuple cert key pair rtype requests response create the request send the request sends a get request returns class response object param url url for the new class request object param kwargs optional arguments that request takes rtype requests response sends a options request returns class response object param url url for the new class request object param kwargs optional arguments that request takes rtype requests response sends a head request returns class response object param url url for the new class request object param kwargs optional arguments that request takes rtype requests response sends a post request returns class response object param url url for the new class request object param data optional dictionary list of tuples bytes or file like object to send in the body of the class request param json optional json to send in the body of the class request param kwargs optional arguments that request takes rtype requests response sends a put request returns class response object param url url for the new class request object param data optional dictionary list of tuples bytes or file like object to send in the body of the class request param kwargs optional arguments that request takes rtype requests response sends a patch request returns class response object param url url for the new class request object param data optional dictionary list of tuples bytes or file like object to send in the body of the class request param kwargs optional arguments that request takes rtype requests response sends a delete request returns class response object param url url for the new class request object param kwargs optional arguments that request takes rtype requests response send a given preparedrequest rtype requests response set defaults that the hooks can utilize to ensure they always have the correct parameters to reproduce the previous request it s possible that users might accidentally send a request object guard against that specific failure case set up variables needed for resolve_redirects and dispatching of hooks get the appropriate adapter to use start time approximately of the request send the request total elapsed time of the request approximately response manipulation hooks persist cookies if the hooks create history then we want those cookies too resolve redirects if allowed redirect resolving generator shuffle things around if there s history insert the first original request at the start get the last request made if redirects aren t being followed store the response on the request for response next check the environment and merge it with some settings rtype dict gather clues from the surrounding environment set environment s proxies look for requests environment configuration and be compatible with curl merge all the kwargs returns the appropriate connection adapter for the given url rtype requests adapters baseadapter nothing matches closes all adapters and as such the session registers a connection adapter to a prefix adapters are sorted in descending order by prefix length returns a class session for context management deprecated 1 0 0 this method has been deprecated since version 1 0 0 and is only kept for backwards compatibility new code should use class requests sessions session to create a session this may be removed at a future date rtype session
import os
import sys
import time
from collections import OrderedDict
from datetime import timedelta

from ._internal_utils import to_native_string
from .adapters import HTTPAdapter
from .auth import _basic_auth_str
from .compat import Mapping, cookielib, urljoin, urlparse
from .cookies import (
    RequestsCookieJar,
    cookiejar_from_dict,
    extract_cookies_to_jar,
    merge_cookies,
)
from .exceptions import (
    ChunkedEncodingError,
    ContentDecodingError,
    InvalidSchema,
    TooManyRedirects,
)
from .hooks import default_hooks, dispatch_hook


from .models import (  
    DEFAULT_REDIRECT_LIMIT,
    REDIRECT_STATI,
    PreparedRequest,
    Request,
)
from .status_codes import codes
from .structures import CaseInsensitiveDict
from .utils import (  
    DEFAULT_PORTS,
    default_headers,
    get_auth_from_url,
    get_environ_proxies,
    get_netrc_auth,
    requote_uri,
    resolve_proxies,
    rewind_body,
    should_bypass_proxies,
    to_key_val_list,
)


if sys.platform == "win32":
    preferred_clock = time.perf_counter
else:
    preferred_clock = time.time


def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
    

    if session_setting is None:
        return request_setting

    if request_setting is None:
        return session_setting

    
    if not (
        isinstance(session_setting, Mapping) and isinstance(request_setting, Mapping)
    ):
        return request_setting

    merged_setting = dict_class(to_key_val_list(session_setting))
    merged_setting.update(to_key_val_list(request_setting))

    
    
    none_keys = [k for (k, v) in merged_setting.items() if v is None]
    for key in none_keys:
        del merged_setting[key]

    return merged_setting


def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict):
    
    if session_hooks is None or session_hooks.get("response") == []:
        return request_hooks

    if request_hooks is None or request_hooks.get("response") == []:
        return session_hooks

    return merge_setting(request_hooks, session_hooks, dict_class)


class SessionRedirectMixin:
    def get_redirect_target(self, resp):
        
        
        
        
        
        
        
        if resp.is_redirect:
            location = resp.headers["location"]
            
            
            
            
            
            
            location = location.encode("latin1")
            return to_native_string(location, "utf8")
        return None

    def should_strip_auth(self, old_url, new_url):
        
        old_parsed = urlparse(old_url)
        new_parsed = urlparse(new_url)
        if old_parsed.hostname != new_parsed.hostname:
            return True
        
        
        
        
        if (
            old_parsed.scheme == "http"
            and old_parsed.port in (80, None)
            and new_parsed.scheme == "https"
            and new_parsed.port in (443, None)
        ):
            return False

        
        changed_port = old_parsed.port != new_parsed.port
        changed_scheme = old_parsed.scheme != new_parsed.scheme
        default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None)
        if (
            not changed_scheme
            and old_parsed.port in default_port
            and new_parsed.port in default_port
        ):
            return False

        
        return changed_port or changed_scheme

    def resolve_redirects(
        self,
        resp,
        req,
        stream=False,
        timeout=None,
        verify=True,
        cert=None,
        proxies=None,
        yield_requests=False,
        **adapter_kwargs,
    ):
        

        hist = []  

        url = self.get_redirect_target(resp)
        previous_fragment = urlparse(req.url).fragment
        while url:
            prepared_request = req.copy()

            
            
            hist.append(resp)
            resp.history = hist[1:]

            try:
                resp.content  
            except (ChunkedEncodingError, ContentDecodingError, RuntimeError):
                resp.raw.read(decode_content=False)

            if len(resp.history) >= self.max_redirects:
                raise TooManyRedirects(
                    f"Exceeded {self.max_redirects} redirects.", response=resp
                )

            
            resp.close()

            
            if url.startswith("//"):
                parsed_rurl = urlparse(resp.url)
                url = ":".join([to_native_string(parsed_rurl.scheme), url])

            
            parsed = urlparse(url)
            if parsed.fragment == "" and previous_fragment:
                parsed = parsed._replace(fragment=previous_fragment)
            elif parsed.fragment:
                previous_fragment = parsed.fragment
            url = parsed.geturl()

            
            
            
            if not parsed.netloc:
                url = urljoin(resp.url, requote_uri(url))
            else:
                url = requote_uri(url)

            prepared_request.url = to_native_string(url)

            self.rebuild_method(prepared_request, resp)

            
            if resp.status_code not in (
                codes.temporary_redirect,
                codes.permanent_redirect,
            ):
                
                purged_headers = ("Content-Length", "Content-Type", "Transfer-Encoding")
                for header in purged_headers:
                    prepared_request.headers.pop(header, None)
                prepared_request.body = None

            headers = prepared_request.headers
            headers.pop("Cookie", None)

            
            
            
            extract_cookies_to_jar(prepared_request._cookies, req, resp.raw)
            merge_cookies(prepared_request._cookies, self.cookies)
            prepared_request.prepare_cookies(prepared_request._cookies)

            
            proxies = self.rebuild_proxies(prepared_request, proxies)
            self.rebuild_auth(prepared_request, resp)

            
            
            
            rewindable = prepared_request._body_position is not None and (
                "Content-Length" in headers or "Transfer-Encoding" in headers
            )

            
            if rewindable:
                rewind_body(prepared_request)

            
            req = prepared_request

            if yield_requests:
                yield req
            else:
                resp = self.send(
                    req,
                    stream=stream,
                    timeout=timeout,
                    verify=verify,
                    cert=cert,
                    proxies=proxies,
                    allow_redirects=False,
                    **adapter_kwargs,
                )

                extract_cookies_to_jar(self.cookies, prepared_request, resp.raw)

                
                url = self.get_redirect_target(resp)
                yield resp

    def rebuild_auth(self, prepared_request, response):
        
        headers = prepared_request.headers
        url = prepared_request.url

        if "Authorization" in headers and self.should_strip_auth(
            response.request.url, url
        ):
            
            
            del headers["Authorization"]

        
        new_auth = get_netrc_auth(url) if self.trust_env else None
        if new_auth is not None:
            prepared_request.prepare_auth(new_auth)

    def rebuild_proxies(self, prepared_request, proxies):
        
        headers = prepared_request.headers
        scheme = urlparse(prepared_request.url).scheme
        new_proxies = resolve_proxies(prepared_request, proxies, self.trust_env)

        if "Proxy-Authorization" in headers:
            del headers["Proxy-Authorization"]

        try:
            username, password = get_auth_from_url(new_proxies[scheme])
        except KeyError:
            username, password = None, None

        
        
        if not scheme.startswith("https") and username and password:
            headers["Proxy-Authorization"] = _basic_auth_str(username, password)

        return new_proxies

    def rebuild_method(self, prepared_request, response):
        
        method = prepared_request.method

        
        if response.status_code == codes.see_other and method != "HEAD":
            method = "GET"

        
        
        if response.status_code == codes.found and method != "HEAD":
            method = "GET"

        
        
        if response.status_code == codes.moved and method == "POST":
            method = "GET"

        prepared_request.method = method


class Session(SessionRedirectMixin):
    

    __attrs__ = [
        "headers",
        "cookies",
        "auth",
        "proxies",
        "hooks",
        "params",
        "verify",
        "cert",
        "adapters",
        "stream",
        "trust_env",
        "max_redirects",
    ]

    def __init__(self):
        
        
        
        self.headers = default_headers()

        
        
        self.auth = None

        
        
        
        self.proxies = {}

        
        self.hooks = default_hooks()

        
        
        
        self.params = {}

        
        self.stream = False

        
        
        
        
        
        
        
        
        self.verify = True

        
        
        self.cert = None

        
        
        
        
        self.max_redirects = DEFAULT_REDIRECT_LIMIT

        
        
        self.trust_env = True

        
        
        
        
        self.cookies = cookiejar_from_dict({})

        
        self.adapters = OrderedDict()
        self.mount("https://", HTTPAdapter())
        self.mount("http://", HTTPAdapter())

    def __enter__(self):
        return self

    def __exit__(self, *args):
        self.close()

    def prepare_request(self, request):
        
        cookies = request.cookies or {}

        
        if not isinstance(cookies, cookielib.CookieJar):
            cookies = cookiejar_from_dict(cookies)

        
        merged_cookies = merge_cookies(
            merge_cookies(RequestsCookieJar(), self.cookies), cookies
        )

        
        auth = request.auth
        if self.trust_env and not auth and not self.auth:
            auth = get_netrc_auth(request.url)

        p = PreparedRequest()
        p.prepare(
            method=request.method.upper(),
            url=request.url,
            files=request.files,
            data=request.data,
            json=request.json,
            headers=merge_setting(
                request.headers, self.headers, dict_class=CaseInsensitiveDict
            ),
            params=merge_setting(request.params, self.params),
            auth=merge_setting(auth, self.auth),
            cookies=merged_cookies,
            hooks=merge_hooks(request.hooks, self.hooks),
        )
        return p

    def request(
        self,
        method,
        url,
        params=None,
        data=None,
        headers=None,
        cookies=None,
        files=None,
        auth=None,
        timeout=None,
        allow_redirects=True,
        proxies=None,
        hooks=None,
        stream=None,
        verify=None,
        cert=None,
        json=None,
    ):
        
        
        req = Request(
            method=method.upper(),
            url=url,
            headers=headers,
            files=files,
            data=data or {},
            json=json,
            params=params or {},
            auth=auth,
            cookies=cookies,
            hooks=hooks,
        )
        prep = self.prepare_request(req)

        proxies = proxies or {}

        settings = self.merge_environment_settings(
            prep.url, proxies, stream, verify, cert
        )

        
        send_kwargs = {
            "timeout": timeout,
            "allow_redirects": allow_redirects,
        }
        send_kwargs.update(settings)
        resp = self.send(prep, **send_kwargs)

        return resp

    def get(self, url, **kwargs):
        r

        kwargs.setdefault("allow_redirects", True)
        return self.request("GET", url, **kwargs)

    def options(self, url, **kwargs):
        r

        kwargs.setdefault("allow_redirects", True)
        return self.request("OPTIONS", url, **kwargs)

    def head(self, url, **kwargs):
        r

        kwargs.setdefault("allow_redirects", False)
        return self.request("HEAD", url, **kwargs)

    def post(self, url, data=None, json=None, **kwargs):
        r

        return self.request("POST", url, data=data, json=json, **kwargs)

    def put(self, url, data=None, **kwargs):
        r

        return self.request("PUT", url, data=data, **kwargs)

    def patch(self, url, data=None, **kwargs):
        r

        return self.request("PATCH", url, data=data, **kwargs)

    def delete(self, url, **kwargs):
        r

        return self.request("DELETE", url, **kwargs)

    def send(self, request, **kwargs):
        
        
        
        kwargs.setdefault("stream", self.stream)
        kwargs.setdefault("verify", self.verify)
        kwargs.setdefault("cert", self.cert)
        if "proxies" not in kwargs:
            kwargs["proxies"] = resolve_proxies(request, self.proxies, self.trust_env)

        
        
        if isinstance(request, Request):
            raise ValueError("You can only send PreparedRequests.")

        
        allow_redirects = kwargs.pop("allow_redirects", True)
        stream = kwargs.get("stream")
        hooks = request.hooks

        
        adapter = self.get_adapter(url=request.url)

        
        start = preferred_clock()

        
        r = adapter.send(request, **kwargs)

        
        elapsed = preferred_clock() - start
        r.elapsed = timedelta(seconds=elapsed)

        
        r = dispatch_hook("response", hooks, r, **kwargs)

        
        if r.history:
            
            for resp in r.history:
                extract_cookies_to_jar(self.cookies, resp.request, resp.raw)

        extract_cookies_to_jar(self.cookies, request, r.raw)

        
        if allow_redirects:
            
            gen = self.resolve_redirects(r, request, **kwargs)
            history = [resp for resp in gen]
        else:
            history = []

        
        if history:
            
            history.insert(0, r)
            
            r = history.pop()
            r.history = history

        
        if not allow_redirects:
            try:
                r._next = next(
                    self.resolve_redirects(r, request, yield_requests=True, **kwargs)
                )
            except StopIteration:
                pass

        if not stream:
            r.content

        return r

    def merge_environment_settings(self, url, proxies, stream, verify, cert):
        
        
        if self.trust_env:
            
            no_proxy = proxies.get("no_proxy") if proxies is not None else None
            env_proxies = get_environ_proxies(url, no_proxy=no_proxy)
            for k, v in env_proxies.items():
                proxies.setdefault(k, v)

            
            
            if verify is True or verify is None:
                verify = (
                    os.environ.get("REQUESTS_CA_BUNDLE")
                    or os.environ.get("CURL_CA_BUNDLE")
                    or verify
                )

        
        proxies = merge_setting(proxies, self.proxies)
        stream = merge_setting(stream, self.stream)
        verify = merge_setting(verify, self.verify)
        cert = merge_setting(cert, self.cert)

        return {"proxies": proxies, "stream": stream, "verify": verify, "cert": cert}

    def get_adapter(self, url):
        
        for prefix, adapter in self.adapters.items():
            if url.lower().startswith(prefix.lower()):
                return adapter

        
        raise InvalidSchema(f"No connection adapters were found for {url!r}")

    def close(self):
        
        for v in self.adapters.values():
            v.close()

    def mount(self, prefix, adapter):
        
        self.adapters[prefix] = adapter
        keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]

        for key in keys_to_move:
            self.adapters[key] = self.adapters.pop(key)

    def __getstate__(self):
        state = {attr: getattr(self, attr, None) for attr in self.__attrs__}
        return state

    def __setstate__(self, state):
        for attr, value in state.items():
            setattr(self, attr, value)


def session():
    
    return Session()