18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2006-2012 Mitch Garnaat http://garnaat.org/
28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2012 Amazon.com, Inc. or its affiliates.
38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2010 Google
48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2008 rPath, Inc.
58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2009 The Echo Nest Corporation
68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2010, Eucalyptus Systems, Inc.
78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2011, Nexenta Systems Inc.
88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# All rights reserved.
98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Permission is hereby granted, free of charge, to any person obtaining a
118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# copy of this software and associated documentation files (the
128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# "Software"), to deal in the Software without restriction, including
138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# without limitation the rights to use, copy, modify, merge, publish, dis-
148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# tribute, sublicense, and/or sell copies of the Software, and to permit
158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# persons to whom the Software is furnished to do so, subject to the fol-
168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# lowing conditions:
178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# The above copyright notice and this permission notice shall be included
198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# in all copies or substantial portions of the Software.
208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# IN THE SOFTWARE.
288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Parts of this code were copied or derived from sample code supplied by AWS.
318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# The following notice applies to that code.
328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  This software code is made available "AS IS" without warranties of any
348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  kind.  You may copy, display, modify and redistribute the software
358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  code either by itself or as incorporated into your code; provided that
368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  you do not remove any proprietary notices.  Your use of this software
378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  code is at your own risk and you waive any claim against Amazon
388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  Digital Services, Inc. or its affiliates with respect to your use of
398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  this software code. (c) 2006 Amazon Digital Services, Inc. or its
408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#  affiliates.
418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiHandles basic connections to AWS
448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi"""
458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom datetime import datetime
468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport errno
478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport os
488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport random
498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport re
508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport socket
518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport sys
528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport time
538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport xml.sax
548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport copy
558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto import auth
578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto import auth_handler
588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport boto
598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport boto.utils
608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport boto.handler
618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport boto.cacerts
628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto import config, UserAgent
648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.compat import six, http_client, urlparse, quote, encodebytes
658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.exception import AWSConnectionError
668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.exception import BotoClientError
678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.exception import BotoServerError
688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.exception import PleaseRetryException
698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.provider import Provider
708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.resultset import ResultSet
718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiHAVE_HTTPS_CONNECTION = False
738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoitry:
748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    import ssl
758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    from boto import https_connection
768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # Google App Engine runs on Python 2.5 so doesn't have ssl.SSLError.
778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if hasattr(ssl, 'SSLError'):
788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        HAVE_HTTPS_CONNECTION = True
798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiexcept ImportError:
808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    pass
818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoitry:
838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    import threading
848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiexcept ImportError:
858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    import dummy_threading as threading
868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiON_APP_ENGINE = all(key in os.environ for key in (
888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    'USER_IS_ADMIN', 'CURRENT_VERSION_ID', 'APPLICATION_ID'))
898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiPORTS_BY_SECURITY = {True: 443,
918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                     False: 80}
928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi KandoiDEFAULT_CA_CERTS_FILE = os.path.join(os.path.dirname(os.path.abspath(boto.cacerts.__file__)), "cacerts.txt")
948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass HostConnectionPool(object):
978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    A pool of connections for one remote (host,port,is_secure).
1008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    When connections are added to the pool, they are put into a
1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    pending queue.  The _mexe method returns connections to the pool
1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    before the response body has been read, so they connections aren't
1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    ready to send another request yet.  They stay in the pending queue
1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    until they are ready for another request, at which point they are
1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    returned to the pool of ready connections.
1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    The pool of ready connections is an ordered list of
1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    (connection,time) pairs, where the time is the time the connection
1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    was returned from _mexe.  After a certain period of time,
1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    connections are considered stale, and discarded rather than being
1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    reused.  This saves having to wait for the connection to time out
1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    if AWS has decided to close it on the other end because of
1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    inactivity.
1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    Thread Safety:
1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        This class is used only from ConnectionPool while it's mutex
1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        is held.
1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self):
1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.queue = []
1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def size(self):
1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the number of connections in the pool for this host.
1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Some of the connections may still be in use, and may not be
1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        ready to be returned by get().
1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return len(self.queue)
1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def put(self, conn):
1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Adds a connection to the pool, along with the time it was
1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        added.
1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.queue.append((conn, time.time()))
1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get(self):
1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the next connection in this pool that is ready to be
1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        reused.  Returns None if there aren't any.
1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Discard ready connections that are too old.
1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.clean()
1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Return the first connection that is ready, and remove it
1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # from the queue.  Connections that aren't ready are returned
1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # to the end of the queue with an updated time, on the
1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # assumption that somebody is actively reading the response.
1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for _ in range(len(self.queue)):
1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            (conn, _) = self.queue.pop(0)
1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if self._conn_ready(conn):
1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                return conn
1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.put(conn)
1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return None
1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _conn_ready(self, conn):
1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        There is a nice state diagram at the top of http_client.py.  It
1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        indicates that once the response headers have been read (which
1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        _mexe does before adding the connection to the pool), a
1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        response is attached to the connection, and it stays there
1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        until it's done reading.  This isn't entirely true: even after
1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        the client is done reading, the response may be closed, but
1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        not removed from the connection yet.
1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        This is ugly, reading a private instance variable, but the
1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        state we care about isn't available in any public methods.
1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if ON_APP_ENGINE:
1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Google AppEngine implementation of HTTPConnection doesn't contain
1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # _HTTPConnection__response attribute. Moreover, it's not possible
1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # to determine if given connection is ready. Reusing connections
1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # simply doesn't make sense with App Engine urlfetch service.
1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return False
1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            response = getattr(conn, '_HTTPConnection__response', None)
1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return (response is None) or response.isclosed()
1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def clean(self):
1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Get rid of stale connections.
1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Note that we do not close the connection here -- somebody
1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # may still be reading from it.
1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        while len(self.queue) > 0 and self._pair_stale(self.queue[0]):
1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.queue.pop(0)
1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _pair_stale(self, pair):
1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns true of the (connection,time) pair is too old to be
1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        used.
1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        (_conn, return_time) = pair
1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        now = time.time()
1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return return_time + ConnectionPool.STALE_DURATION < now
2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass ConnectionPool(object):
2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    A connection pool that expires connections after a fixed period of
2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    time.  This saves time spent waiting for a connection that AWS has
2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    timed out on the other end.
2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    This class is thread-safe.
2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    """
2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    #
2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # The amout of time between calls to clean.
2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    #
2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    CLEAN_INTERVAL = 5.0
2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    #
2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # How long before a connection becomes "stale" and won't be reused
2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # again.  The intention is that this time is less that the timeout
2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # period that AWS uses, so we'll never try to reuse a connection
2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # and find that AWS is timing it out.
2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    #
2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # Experimentation in July 2011 shows that AWS starts timing things
2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # out after three minutes.  The 60 seconds here is conservative so
2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # we should never hit that 3-minute timout.
2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    #
2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    STALE_DURATION = 60.0
2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self):
2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Mapping from (host,port,is_secure) to HostConnectionPool.
2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # If a pool becomes empty, it is removed.
2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.host_to_pool = {}
2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # The last time the pool was cleaned.
2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.last_clean_time = 0.0
2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.mutex = threading.Lock()
2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        ConnectionPool.STALE_DURATION = \
2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            config.getfloat('Boto', 'connection_stale_duration',
2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                            ConnectionPool.STALE_DURATION)
2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __getstate__(self):
2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        pickled_dict = copy.copy(self.__dict__)
2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        pickled_dict['host_to_pool'] = {}
2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        del pickled_dict['mutex']
2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return pickled_dict
2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __setstate__(self, dct):
2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.__init__()
2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def size(self):
2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the number of connections in the pool.
2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return sum(pool.size() for pool in self.host_to_pool.values())
2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_http_connection(self, host, port, is_secure):
2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Gets a connection from the pool for the named host.  Returns
2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        None if there is no connection that can be reused. It's the caller's
2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        responsibility to call close() on the connection when it's no longer
2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        needed.
2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.clean()
2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with self.mutex:
2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            key = (host, port, is_secure)
2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if key not in self.host_to_pool:
2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                return None
2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return self.host_to_pool[key].get()
2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def put_http_connection(self, host, port, is_secure, conn):
2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Adds a connection to the pool of connections that can be
2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        reused for the named host.
2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with self.mutex:
2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            key = (host, port, is_secure)
2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if key not in self.host_to_pool:
2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.host_to_pool[key] = HostConnectionPool()
2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.host_to_pool[key].put(conn)
2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def clean(self):
2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Clean up the stale connections in all of the pools, and then
2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        get rid of empty pools.  Pools clean themselves every time a
2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        connection is fetched; this cleaning takes care of pools that
2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        aren't being used any more, so nothing is being gotten from
2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        them.
2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        with self.mutex:
2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            now = time.time()
2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if self.last_clean_time + self.CLEAN_INTERVAL < now:
2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                to_remove = []
2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                for (host, pool) in self.host_to_pool.items():
2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    pool.clean()
2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if pool.size() == 0:
2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        to_remove.append(host)
2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                for host in to_remove:
2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    del self.host_to_pool[host]
3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.last_clean_time = now
3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass HTTPRequest(object):
3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, method, protocol, host, port, path, auth_path,
3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 params, headers, body):
3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Represents an HTTP request.
3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type method: string
3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param method: The HTTP method name, 'GET', 'POST', 'PUT' etc.
3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type protocol: string
3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param protocol: The http protocol used, 'http' or 'https'.
3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type host: string
3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param host: Host to which the request is addressed. eg. abc.com
3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type port: int
3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param port: port on which the request is being sent. Zero means unset,
3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            in which case default port will be chosen.
3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type path: string
3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param path: URL path that is being accessed.
3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type auth_path: string
3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param path: The part of the URL path used when creating the
3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            authentication string.
3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type params: dict
3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param params: HTTP url query parameters, with key as name of
3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            the param, and value as value of param.
3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type headers: dict
3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param headers: HTTP headers, with key as name of the header and value
3358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            as value of header.
3368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type body: string
3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param body: Body of the HTTP request. If not present, will be None or
3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            empty string ('').
3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.method = method
3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.protocol = protocol
3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.host = host
3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.port = port
3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.path = path
3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if auth_path is None:
3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            auth_path = path
3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.auth_path = auth_path
3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.params = params
3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # chunked Transfer-Encoding should act only on PUT request.
3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if headers and 'Transfer-Encoding' in headers and \
3528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                headers['Transfer-Encoding'] == 'chunked' and \
3538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.method != 'PUT':
3548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.headers = headers.copy()
3558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            del self.headers['Transfer-Encoding']
3568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
3578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.headers = headers
3588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.body = body
3598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __str__(self):
3618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return (('method:(%s) protocol:(%s) host(%s) port(%s) path(%s) '
3628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 'params(%s) headers(%s) body(%s)') % (self.method,
3638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 self.protocol, self.host, self.port, self.path, self.params,
3648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 self.headers, self.body))
3658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def authorize(self, connection, **kwargs):
3678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not getattr(self, '_headers_quoted', False):
3688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            for key in self.headers:
3698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                val = self.headers[key]
3708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if isinstance(val, six.text_type):
3718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    safe = '!"#$%&\'()*+,/:;<=>?@[\\]^`{|}~'
3728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    self.headers[key] = quote(val.encode('utf-8'), safe)
3738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            setattr(self, '_headers_quoted', True)
3748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.headers['User-Agent'] = UserAgent
3768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        connection._auth_handler.add_auth(self, **kwargs)
3788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # I'm not sure if this is still needed, now that add_auth is
3808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # setting the content-length for POST requests.
3818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if 'Content-Length' not in self.headers:
3828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if 'Transfer-Encoding' not in self.headers or \
3838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    self.headers['Transfer-Encoding'] != 'chunked':
3848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.headers['Content-Length'] = str(len(self.body))
3858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass HTTPResponse(http_client.HTTPResponse):
3888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, *args, **kwargs):
3908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        http_client.HTTPResponse.__init__(self, *args, **kwargs)
3918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._cached_response = ''
3928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def read(self, amt=None):
3948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Read the response.
3958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        This method does not have the same behavior as
3978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        http_client.HTTPResponse.read.  Instead, if this method is called with
3988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        no ``amt`` arg, then the response body will be cached.  Subsequent
3998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        calls to ``read()`` with no args **will return the cached response**.
4008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
4028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if amt is None:
4038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # The reason for doing this is that many places in boto call
4048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # response.read() and except to get the response body that they
4058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # can then process.  To make sure this always works as they expect
4068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # we're caching the response so that multiple calls to read()
4078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # will return the full body.  Note that this behavior only
4088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # happens if the amt arg is not specified.
4098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if not self._cached_response:
4108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self._cached_response = http_client.HTTPResponse.read(self)
4118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return self._cached_response
4128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
4138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return http_client.HTTPResponse.read(self, amt)
4148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass AWSAuthConnection(object):
4178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, host, aws_access_key_id=None,
4188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 aws_secret_access_key=None,
4198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 is_secure=True, port=None, proxy=None, proxy_port=None,
4208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 proxy_user=None, proxy_pass=None, debug=0,
4218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 https_connection_factory=None, path='/',
4228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 provider='aws', security_token=None,
4238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 suppress_consec_slashes=True,
4248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 validate_certs=True, profile_name=None):
4258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
4268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type host: str
4278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param host: The host to make the connection to
4288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :keyword str aws_access_key_id: Your AWS Access Key ID (provided by
4308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            Amazon). If none is specified, the value in your
4318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ``AWS_ACCESS_KEY_ID`` environmental variable is used.
4328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :keyword str aws_secret_access_key: Your AWS Secret Access Key
4338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            (provided by Amazon). If none is specified, the value in your
4348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ``AWS_SECRET_ACCESS_KEY`` environmental variable is used.
4358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :keyword str security_token: The security token associated with
4368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            temporary credentials issued by STS.  Optional unless using
4378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            temporary credentials.  If none is specified, the environment
4388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            variable ``AWS_SECURITY_TOKEN`` is used if defined.
4398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type is_secure: boolean
4418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param is_secure: Whether the connection is over SSL
4428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type https_connection_factory: list or tuple
4448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param https_connection_factory: A pair of an HTTP connection
4458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            factory and the exceptions to catch.  The factory should have
4468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            a similar interface to L{http_client.HTTPSConnection}.
4478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param str proxy: Address/hostname for a proxy server
4498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type proxy_port: int
4518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param proxy_port: The port to use when connecting over a proxy
4528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type proxy_user: str
4548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param proxy_user: The username to connect with on the proxy
4558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type proxy_pass: str
4578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param proxy_pass: The password to use when connection over a proxy.
4588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type port: int
4608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param port: The port to use to connect
4618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type suppress_consec_slashes: bool
4638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param suppress_consec_slashes: If provided, controls whether
4648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            consecutive slashes will be suppressed in key paths.
4658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type validate_certs: bool
4678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param validate_certs: Controls whether SSL certificates
4688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            will be validated or not.  Defaults to True.
4698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
4708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type profile_name: str
4718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param profile_name: Override usual Credentials section in config
4728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            file to use a named set of keys instead.
4738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
4748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.suppress_consec_slashes = suppress_consec_slashes
4758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.num_retries = 6
4768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Override passed-in is_secure setting if value was defined in config.
4778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if config.has_option('Boto', 'is_secure'):
4788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            is_secure = config.getboolean('Boto', 'is_secure')
4798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.is_secure = is_secure
4808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Whether or not to validate server certificates.
4818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # The default is now to validate certificates.  This can be
4828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # overridden in the boto config file are by passing an
4838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # explicit validate_certs parameter to the class constructor.
4848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.https_validate_certificates = config.getbool(
4858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Boto', 'https_validate_certificates',
4868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            validate_certs)
4878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.https_validate_certificates and not HAVE_HTTPS_CONNECTION:
4888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise BotoClientError(
4898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                "SSL server certificate validation is enabled in boto "
4908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                "configuration, but Python dependencies required to "
4918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                "support this feature are not available. Certificate "
4928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                "validation is only supported when running under Python "
4938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                "2.6 or later.")
4948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        certs_file = config.get_value(
4958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'Boto', 'ca_certificates_file', DEFAULT_CA_CERTS_FILE)
4968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if certs_file == 'system':
4978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            certs_file = None
4988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.ca_certificates_file = certs_file
4998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if port:
5008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.port = port
5018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
5028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.port = PORTS_BY_SECURITY[is_secure]
5038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.handle_proxy(proxy, proxy_port, proxy_user, proxy_pass)
5058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # define exceptions from http_client that we want to catch and retry
5068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.http_exceptions = (http_client.HTTPException, socket.error,
5078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                socket.gaierror, http_client.BadStatusLine)
5088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # define subclasses of the above that are not retryable.
5098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.http_unretryable_exceptions = []
5108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if HAVE_HTTPS_CONNECTION:
5118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.http_unretryable_exceptions.append(
5128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                https_connection.InvalidCertificateException)
5138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # define values in socket exceptions we don't want to catch
5158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.socket_exception_values = (errno.EINTR,)
5168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if https_connection_factory is not None:
5178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.https_connection_factory = https_connection_factory[0]
5188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.http_exceptions += https_connection_factory[1]
5198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
5208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.https_connection_factory = None
5218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if (is_secure):
5228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.protocol = 'https'
5238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
5248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.protocol = 'http'
5258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.host = host
5268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.path = path
5278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # if the value passed in for debug
5288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not isinstance(debug, six.integer_types):
5298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            debug = 0
5308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.debug = config.getint('Boto', 'debug', debug)
5318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.host_header = None
5328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Timeout used to tell http_client how long to wait for socket timeouts.
5348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Default is to leave timeout unchanged, which will in turn result in
5358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # the socket's default global timeout being used. To specify a
5368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # timeout, set http_socket_timeout in Boto config. Regardless,
5378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # timeouts will only be applied if Python is 2.6 or greater.
5388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.http_connection_kwargs = {}
5398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if (sys.version_info[0], sys.version_info[1]) >= (2, 6):
5408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # If timeout isn't defined in boto config file, use 70 second
5418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # default as recommended by
5428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # http://docs.aws.amazon.com/amazonswf/latest/apireference/API_PollForActivityTask.html
5438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.http_connection_kwargs['timeout'] = config.getint(
5448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'Boto', 'http_socket_timeout', 70)
5458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if isinstance(provider, Provider):
5478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Allow overriding Provider
5488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.provider = provider
5498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
5508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self._provider_type = provider
5518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.provider = Provider(self._provider_type,
5528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                     aws_access_key_id,
5538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                     aws_secret_access_key,
5548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                     security_token,
5558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                     profile_name)
5568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Allow config file to override default host, port, and host header.
5588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.provider.host:
5598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.host = self.provider.host
5608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.provider.port:
5618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.port = self.provider.port
5628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.provider.host_header:
5638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.host_header = self.provider.host_header
5648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._pool = ConnectionPool()
5668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._connection = (self.host, self.port, self.is_secure)
5678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._last_rs = None
5688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._auth_handler = auth.get_auth_handler(
5698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            host, config, self.provider, self._required_auth_capability())
5708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if getattr(self, 'AuthServiceName', None) is not None:
5718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.auth_service_name = self.AuthServiceName
5728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.request_hook = None
5738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __repr__(self):
5758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return '%s:%s' % (self.__class__.__name__, self.host)
5768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _required_auth_capability(self):
5788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return []
5798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _get_auth_service_name(self):
5818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return getattr(self._auth_handler, 'service_name')
5828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # For Sigv4, the auth_service_name/auth_region_name properties allow
5848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # the service_name/region_name to be explicitly set instead of being
5858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # derived from the endpoint url.
5868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _set_auth_service_name(self, value):
5878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._auth_handler.service_name = value
5888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    auth_service_name = property(_get_auth_service_name, _set_auth_service_name)
5898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _get_auth_region_name(self):
5918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return getattr(self._auth_handler, 'region_name')
5928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _set_auth_region_name(self, value):
5948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._auth_handler.region_name = value
5958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    auth_region_name = property(_get_auth_region_name, _set_auth_region_name)
5968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
5978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def connection(self):
5988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_http_connection(*self._connection)
5998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    connection = property(connection)
6008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def aws_access_key_id(self):
6028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.provider.access_key
6038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    aws_access_key_id = property(aws_access_key_id)
6048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gs_access_key_id = aws_access_key_id
6058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    access_key = aws_access_key_id
6068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def aws_secret_access_key(self):
6088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.provider.secret_key
6098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    aws_secret_access_key = property(aws_secret_access_key)
6108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    gs_secret_access_key = aws_secret_access_key
6118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    secret_key = aws_secret_access_key
6128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def profile_name(self):
6148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.provider.profile_name
6158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    profile_name = property(profile_name)
6168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_path(self, path='/'):
6188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # The default behavior is to suppress consecutive slashes for reasons
6198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # discussed at
6208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # https://groups.google.com/forum/#!topic/boto-dev/-ft0XPUy0y8
6218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # You can override that behavior with the suppress_consec_slashes param.
6228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not self.suppress_consec_slashes:
6238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return self.path + re.sub('^(/*)/', "\\1", path)
6248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        pos = path.find('?')
6258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if pos >= 0:
6268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            params = path[pos:]
6278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            path = path[:pos]
6288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
6298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            params = None
6308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if path[-1] == '/':
6318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            need_trailing = True
6328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
6338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            need_trailing = False
6348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        path_elements = self.path.split('/')
6358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        path_elements.extend(path.split('/'))
6368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        path_elements = [p for p in path_elements if p]
6378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        path = '/' + '/'.join(path_elements)
6388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if path[-1] != '/' and need_trailing:
6398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            path += '/'
6408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if params:
6418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            path = path + params
6428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return path
6438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def server_name(self, port=None):
6458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not port:
6468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            port = self.port
6478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if port == 80:
6488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            signature_host = self.host
6498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
6508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # This unfortunate little hack can be attributed to
6518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # a difference in the 2.6 version of http_client.  In old
6528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # versions, it would append ":443" to the hostname sent
6538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # in the Host header and so we needed to make sure we
6548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # did the same when calculating the V2 signature.  In 2.6
6558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # (and higher!)
6568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # it no longer does that.  Hence, this kludge.
6578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if ((ON_APP_ENGINE and sys.version[:3] == '2.5') or
6588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    sys.version[:3] in ('2.6', '2.7')) and port == 443:
6598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                signature_host = self.host
6608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
6618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                signature_host = '%s:%d' % (self.host, port)
6628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return signature_host
6638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def handle_proxy(self, proxy, proxy_port, proxy_user, proxy_pass):
6658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.proxy = proxy
6668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.proxy_port = proxy_port
6678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.proxy_user = proxy_user
6688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.proxy_pass = proxy_pass
6698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if 'http_proxy' in os.environ and not self.proxy:
6708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            pattern = re.compile(
6718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '(?:http://)?'
6728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '(?:(?P<user>[\w\-\.]+):(?P<pass>.*)@)?'
6738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '(?P<host>[\w\-\.]+)'
6748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                '(?::(?P<port>\d+))?'
6758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            )
6768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            match = pattern.match(os.environ['http_proxy'])
6778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if match:
6788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy = match.group('host')
6798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy_port = match.group('port')
6808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy_user = match.group('user')
6818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy_pass = match.group('pass')
6828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
6838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if not self.proxy:
6848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy = config.get_value('Boto', 'proxy', None)
6858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if not self.proxy_port:
6868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy_port = config.get_value('Boto', 'proxy_port', None)
6878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if not self.proxy_user:
6888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy_user = config.get_value('Boto', 'proxy_user', None)
6898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if not self.proxy_pass:
6908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self.proxy_pass = config.get_value('Boto', 'proxy_pass', None)
6918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not self.proxy_port and self.proxy:
6938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            print("http_proxy environment variable does not specify "
6948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                  "a port, using default")
6958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.proxy_port = self.port
6968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
6978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.no_proxy = os.environ.get('no_proxy', '') or os.environ.get('NO_PROXY', '')
6988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.use_proxy = (self.proxy is not None)
6998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_http_connection(self, host, port, is_secure):
7018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        conn = self._pool.get_http_connection(host, port, is_secure)
7028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if conn is not None:
7038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return conn
7048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
7058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return self.new_http_connection(host, port, is_secure)
7068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def skip_proxy(self, host):
7088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not self.no_proxy:
7098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return False
7108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.no_proxy == "*":
7128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return True
7138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        hostonly = host
7158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        hostonly = host.split(':')[0]
7168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for name in self.no_proxy.split(','):
7188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if name and (hostonly.endswith(name) or host.endswith(name)):
7198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                return True
7208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return False
7228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def new_http_connection(self, host, port, is_secure):
7248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if host is None:
7258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            host = self.server_name()
7268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Make sure the host is really just the host, not including
7288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # the port number
7298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        host = host.split(':', 1)[0]
7308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        http_connection_kwargs = self.http_connection_kwargs.copy()
7328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Connection factories below expect a port keyword argument
7348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        http_connection_kwargs['port'] = port
7358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Override host with proxy settings if needed
7378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.use_proxy and not is_secure and \
7388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                not self.skip_proxy(host):
7398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            host = self.proxy
7408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            http_connection_kwargs['port'] = int(self.proxy_port)
7418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if is_secure:
7438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.debug(
7448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                'establishing HTTPS connection: host=%s, kwargs=%s',
7458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                host, http_connection_kwargs)
7468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if self.use_proxy and not self.skip_proxy(host):
7478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = self.proxy_ssl(host, is_secure and 443 or 80)
7488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            elif self.https_connection_factory:
7498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = self.https_connection_factory(host)
7508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            elif self.https_validate_certificates and HAVE_HTTPS_CONNECTION:
7518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = https_connection.CertValidatingHTTPSConnection(
7528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    host, ca_certs=self.ca_certificates_file,
7538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    **http_connection_kwargs)
7548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
7558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = http_client.HTTPSConnection(
7568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    host, **http_connection_kwargs)
7578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
7588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.debug('establishing HTTP connection: kwargs=%s' %
7598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                           http_connection_kwargs)
7608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if self.https_connection_factory:
7618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # even though the factory says https, this is too handy
7628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # to not be able to allow overriding for http also.
7638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = self.https_connection_factory(
7648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    host, **http_connection_kwargs)
7658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
7668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = http_client.HTTPConnection(
7678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    host, **http_connection_kwargs)
7688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.debug > 1:
7698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            connection.set_debuglevel(self.debug)
7708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # self.connection must be maintained for backwards-compatibility
7718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # however, it must be dynamically pulled from the connection pool
7728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # set a private variable which will enable that
7738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if host.split(':')[0] == self.host and is_secure == self.is_secure:
7748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self._connection = (host, port, is_secure)
7758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Set the response class of the http connection to use our custom
7768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # class.
7778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        connection.response_class = HTTPResponse
7788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return connection
7798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def put_http_connection(self, host, port, is_secure, connection):
7818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._pool.put_http_connection(host, port, is_secure, connection)
7828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
7838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def proxy_ssl(self, host=None, port=None):
7848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if host and port:
7858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            host = '%s:%d' % (host, port)
7868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
7878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            host = '%s:%d' % (self.host, self.port)
7888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Seems properly to use timeout for connect too
7898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        timeout = self.http_connection_kwargs.get("timeout")
7908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if timeout is not None:
7918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            sock = socket.create_connection((self.proxy,
7928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                             int(self.proxy_port)), timeout)
7938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
7948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            sock = socket.create_connection((self.proxy, int(self.proxy_port)))
7958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug("Proxy connection: CONNECT %s HTTP/1.0\r\n", host)
7968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        sock.sendall("CONNECT %s HTTP/1.0\r\n" % host)
7978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        sock.sendall("User-Agent: %s\r\n" % UserAgent)
7988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.proxy_user and self.proxy_pass:
7998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            for k, v in self.get_proxy_auth_header().items():
8008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                sock.sendall("%s: %s\r\n" % (k, v))
8018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # See discussion about this config option at
8028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # https://groups.google.com/forum/?fromgroups#!topic/boto-dev/teenFvOq2Cc
8038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if config.getbool('Boto', 'send_crlf_after_proxy_auth_headers', False):
8048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                sock.sendall("\r\n")
8058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
8068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            sock.sendall("\r\n")
8078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        resp = http_client.HTTPResponse(sock, strict=True, debuglevel=self.debug)
8088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        resp.begin()
8098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if resp.status != 200:
8118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Fake a socket error, use a code that make it obvious it hasn't
8128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # been generated by the socket library
8138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise socket.error(-71,
8148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               "Error talking to HTTP proxy %s:%s: %s (%s)" %
8158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               (self.proxy, self.proxy_port,
8168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                resp.status, resp.reason))
8178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # We can safely close the response, it duped the original socket
8198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        resp.close()
8208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        h = http_client.HTTPConnection(host)
8228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.https_validate_certificates and HAVE_HTTPS_CONNECTION:
8248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            msg = "wrapping ssl socket for proxied connection; "
8258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if self.ca_certificates_file:
8268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                msg += "CA certificate file=%s" % self.ca_certificates_file
8278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
8288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                msg += "using system provided SSL certs"
8298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.debug(msg)
8308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            key_file = self.http_connection_kwargs.get('key_file', None)
8318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            cert_file = self.http_connection_kwargs.get('cert_file', None)
8328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            sslSock = ssl.wrap_socket(sock, keyfile=key_file,
8338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                      certfile=cert_file,
8348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                      cert_reqs=ssl.CERT_REQUIRED,
8358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                      ca_certs=self.ca_certificates_file)
8368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            cert = sslSock.getpeercert()
8378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            hostname = self.host.split(':', 0)[0]
8388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if not https_connection.ValidateCertificateHostname(cert, hostname):
8398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                raise https_connection.InvalidCertificateException(
8408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    hostname, cert, 'hostname mismatch')
8418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
8428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Fallback for old Python without ssl.wrap_socket
8438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if hasattr(http_client, 'ssl'):
8448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                sslSock = http_client.ssl.SSLSocket(sock)
8458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
8468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                sslSock = socket.ssl(sock, None, None)
8478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                sslSock = http_client.FakeSocket(sock, sslSock)
8488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # This is a bit unclean
8508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        h.sock = sslSock
8518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return h
8528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def prefix_proxy_to_path(self, path, host=None):
8548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        path = self.protocol + '://' + (host or self.server_name()) + path
8558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return path
8568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_proxy_auth_header(self):
8588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        auth = encodebytes(self.proxy_user + ':' + self.proxy_pass)
8598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return {'Proxy-Authorization': 'Basic %s' % auth}
8608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # For passing proxy information to other connection libraries, e.g. cloudsearch2
8628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_proxy_url_with_auth(self):
8638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not self.use_proxy:
8648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return None
8658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.proxy_user or self.proxy_pass:
8678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if self.proxy_pass:
8688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                login_info = '%s:%s@' % (self.proxy_user, self.proxy_pass)
8698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            else:
8708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                login_info = '%s@' % self.proxy_user
8718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
8728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            login_info = ''
8738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return 'http://%s%s:%s' % (login_info, self.proxy, str(self.proxy_port or self.port))
8758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def set_host_header(self, request):
8778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        try:
8788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            request.headers['Host'] = \
8798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                self._auth_handler.host_header(self.host, request)
8808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        except AttributeError:
8818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            request.headers['Host'] = self.host.split(':', 1)[0]
8828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def set_request_hook(self, hook):
8848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.request_hook = hook
8858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _mexe(self, request, sender=None, override_num_retries=None,
8878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi              retry_handler=None):
8888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
8898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        mexe - Multi-execute inside a loop, retrying multiple times to handle
8908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi               transient Internet errors by simply trying again.
8918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi               Also handles redirects.
8928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        This code was inspired by the S3Utils classes posted to the boto-users
8948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Google group by Larry Bates.  Thanks!
8958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
8968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
8978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('Method: %s' % request.method)
8988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('Path: %s' % request.path)
8998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('Data: %s' % request.body)
9008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('Headers: %s' % request.headers)
9018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('Host: %s' % request.host)
9028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('Port: %s' % request.port)
9038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('Params: %s' % request.params)
9048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        response = None
9058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        body = None
9068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        ex = None
9078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if override_num_retries is None:
9088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            num_retries = config.getint('Boto', 'num_retries', self.num_retries)
9098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
9108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            num_retries = override_num_retries
9118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        i = 0
9128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        connection = self.get_http_connection(request.host, request.port,
9138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                              self.is_secure)
9148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
9158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Convert body to bytes if needed
9168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not isinstance(request.body, bytes) and hasattr(request.body,
9178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                           'encode'):
9188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            request.body = request.body.encode('utf-8')
9198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
9208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        while i <= num_retries:
9218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            # Use binary exponential backoff to desynchronize client requests.
9228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            next_sleep = min(random.random() * (2 ** i),
9238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                             boto.config.get('Boto', 'max_retry_delay', 60))
9248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            try:
9258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # we now re-sign each request before it is retried
9268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                boto.log.debug('Token: %s' % self.provider.security_token)
9278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                request.authorize(connection=self)
9288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # Only force header for non-s3 connections, because s3 uses
9298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # an older signing method + bucket resource URLs that include
9308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # the port info. All others should be now be up to date and
9318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # not include the port.
9328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if 's3' not in self._required_auth_capability():
9338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if not getattr(self, 'anon', False):
9348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        if not request.headers.get('Host'):
9358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                            self.set_host_header(request)
9368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                boto.log.debug('Final headers: %s' % request.headers)
9378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                request.start_time = datetime.now()
9388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if callable(sender):
9398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    response = sender(connection, request.method, request.path,
9408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                      request.body, request.headers)
9418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                else:
9428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    connection.request(request.method, request.path,
9438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                       request.body, request.headers)
9448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    response = connection.getresponse()
9458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                boto.log.debug('Response headers: %s' % response.getheaders())
9468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                location = response.getheader('location')
9478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # -- gross hack --
9488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # http_client gets confused with chunked responses to HEAD requests
9498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # so I have to fake it out
9508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if request.method == 'HEAD' and getattr(response,
9518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                        'chunked', False):
9528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    response.chunked = 0
9538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if callable(retry_handler):
9548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    status = retry_handler(response, i, next_sleep)
9558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if status:
9568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        msg, i, next_sleep = status
9578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        if msg:
9588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                            boto.log.debug(msg)
9598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        time.sleep(next_sleep)
9608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        continue
9618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                if response.status in [500, 502, 503, 504]:
9628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    msg = 'Received %d response.  ' % response.status
9638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    msg += 'Retrying in %3.1f seconds' % next_sleep
9648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    boto.log.debug(msg)
9658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    body = response.read()
9668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if isinstance(body, bytes):
9678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        body = body.decode('utf-8')
9688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                elif response.status < 300 or response.status >= 400 or \
9698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        not location:
9708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    # don't return connection to the pool if response contains
9718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    # Connection:close header, because the connection has been
9728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    # closed and default reconnect behavior may do something
9738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    # different than new_http_connection. Also, it's probably
9748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    # less efficient to try to reuse a closed connection.
9758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    conn_header_value = response.getheader('connection')
9768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if conn_header_value == 'close':
9778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        connection.close()
9788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    else:
9798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        self.put_http_connection(request.host, request.port,
9808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                 self.is_secure, connection)
9818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if self.request_hook is not None:
9828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        self.request_hook.handle_request_data(request, response)
9838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    return response
9848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                else:
9858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    scheme, request.host, request.path, \
9868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        params, query, fragment = urlparse(location)
9878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if query:
9888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        request.path += '?' + query
9898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    # urlparse can return both host and port in netloc, so if
9908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    # that's the case we need to split them up properly
9918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if ':' in request.host:
9928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        request.host, request.port = request.host.split(':', 1)
9938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    msg = 'Redirecting: %s' % scheme + '://'
9948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    msg += request.host + request.path
9958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    boto.log.debug(msg)
9968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    connection = self.get_http_connection(request.host,
9978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                          request.port,
9988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                          scheme == 'https')
9998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    response = None
10008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    continue
10018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            except PleaseRetryException as e:
10028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                boto.log.debug('encountered a retry exception: %s' % e)
10038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = self.new_http_connection(request.host, request.port,
10048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                      self.is_secure)
10058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                response = e.response
10068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                ex = e
10078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            except self.http_exceptions as e:
10088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                for unretryable in self.http_unretryable_exceptions:
10098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                    if isinstance(e, unretryable):
10108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        boto.log.debug(
10118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                            'encountered unretryable %s exception, re-raising' %
10128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                            e.__class__.__name__)
10138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                        raise
10148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                boto.log.debug('encountered %s exception, reconnecting' %
10158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                               e.__class__.__name__)
10168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                connection = self.new_http_connection(request.host, request.port,
10178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                      self.is_secure)
10188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                ex = e
10198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            time.sleep(next_sleep)
10208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            i += 1
10218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # If we made it here, it's because we have exhausted our retries
10228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # and stil haven't succeeded.  So, if we have a response object,
10238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # use it to raise an exception.
10248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        # Otherwise, raise the exception that must have already happened.
10258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.request_hook is not None:
10268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.request_hook.handle_request_data(request, response, error=True)
10278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if response:
10288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise BotoServerError(response.status, response.reason, body)
10298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif ex:
10308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise ex
10318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
10328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            msg = 'Please report this exception as a Boto Issue!'
10338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise BotoClientError(msg)
10348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def build_base_http_request(self, method, path, auth_path,
10368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                params=None, headers=None, data='', host=None):
10378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        path = self.get_path(path)
10388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if auth_path is not None:
10398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            auth_path = self.get_path(auth_path)
10408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if params is None:
10418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            params = {}
10428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
10438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            params = params.copy()
10448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if headers is None:
10458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            headers = {}
10468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
10478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            headers = headers.copy()
10488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.host_header and not boto.utils.find_matching_headers('host', headers):
10498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            headers['host'] = self.host_header
10508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        host = host or self.host
10518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.use_proxy:
10528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if not auth_path:
10538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                auth_path = path
10548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            path = self.prefix_proxy_to_path(path, host)
10558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if self.proxy_user and self.proxy_pass and not self.is_secure:
10568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # If is_secure, we don't have to set the proxy authentication
10578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                # header here, we did that in the CONNECT to the proxy.
10588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                headers.update(self.get_proxy_auth_header())
10598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return HTTPRequest(method, self.protocol, host, self.port,
10608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                           path, auth_path, params, headers, data)
10618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def make_request(self, method, path, headers=None, data='', host=None,
10638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                     auth_path=None, sender=None, override_num_retries=None,
10648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                     params=None, retry_handler=None):
10658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Makes a request to the server, with stock multiple-retry logic."""
10668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if params is None:
10678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            params = {}
10688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        http_request = self.build_base_http_request(method, path, auth_path,
10698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                    params, headers, data, host)
10708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self._mexe(http_request, sender, override_num_retries,
10718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                          retry_handler=retry_handler)
10728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def close(self):
10748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """(Optional) Close any open HTTP connections.  This is non-destructive,
10758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        and making a new request will open a connection again."""
10768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug('closing all HTTP connections')
10788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self._connection = None  # compat field
10798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass AWSQueryConnection(AWSAuthConnection):
10828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    APIVersion = ''
10848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    ResponseError = BotoServerError
10858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
10868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, aws_access_key_id=None, aws_secret_access_key=None,
10878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 is_secure=True, port=None, proxy=None, proxy_port=None,
10888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 proxy_user=None, proxy_pass=None, host=None, debug=0,
10898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 https_connection_factory=None, path='/', security_token=None,
10908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 validate_certs=True, profile_name=None, provider='aws'):
10918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        super(AWSQueryConnection, self).__init__(
10928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            host, aws_access_key_id,
10938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            aws_secret_access_key,
10948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            is_secure, port, proxy,
10958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            proxy_port, proxy_user, proxy_pass,
10968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            debug, https_connection_factory, path,
10978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            security_token=security_token,
10988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            validate_certs=validate_certs,
10998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            profile_name=profile_name,
11008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            provider=provider)
11018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _required_auth_capability(self):
11038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return []
11048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_utf8_value(self, value):
11068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return boto.utils.get_utf8_value(value)
11078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def make_request(self, action, params=None, path='/', verb='GET'):
11098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        http_request = self.build_base_http_request(verb, path, None,
11108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                    params, {}, '',
11118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                    self.host)
11128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if action:
11138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            http_request.params['Action'] = action
11148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if self.APIVersion:
11158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            http_request.params['Version'] = self.APIVersion
11168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self._mexe(http_request)
11178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def build_list_params(self, params, items, label):
11198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if isinstance(items, six.string_types):
11208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            items = [items]
11218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for i in range(1, len(items) + 1):
11228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            params['%s.%d' % (label, i)] = items[i - 1]
11238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def build_complex_list_params(self, params, items, label, names):
11258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """Serialize a list of structures.
11268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        For example::
11288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            items = [('foo', 'bar', 'baz'), ('foo2', 'bar2', 'baz2')]
11308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            label = 'ParamName.member'
11318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            names = ('One', 'Two', 'Three')
11328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            self.build_complex_list_params(params, items, label, names)
11338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        would result in the params dict being updated with these params::
11358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ParamName.member.1.One = foo
11378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ParamName.member.1.Two = bar
11388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ParamName.member.1.Three = baz
11398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ParamName.member.2.One = foo2
11418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ParamName.member.2.Two = bar2
11428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            ParamName.member.2.Three = baz2
11438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type params: dict
11458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param params: The params dict.  The complex list params
11468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            will be added to this dict.
11478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type items: list of tuples
11498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param items: The list to serialize.
11508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type label: string
11528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param label: The prefix to apply to the parameter.
11538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :type names: tuple of strings
11558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        :param names: The names associated with each tuple element.
11568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
11588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for i, item in enumerate(items, 1):
11598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            current_prefix = '%s.%s' % (label, i)
11608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            for key, value in zip(names, item):
11618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                full_key = '%s.%s' % (current_prefix, key)
11628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                params[full_key] = value
11638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    # generics
11658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_list(self, action, params, markers, path='/',
11678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                 parent=None, verb='GET'):
11688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not parent:
11698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            parent = self
11708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        response = self.make_request(action, params, path, verb)
11718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        body = response.read()
11728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug(body)
11738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not body:
11748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('Null body %s' % body)
11758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise self.ResponseError(response.status, response.reason, body)
11768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif response.status == 200:
11778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            rs = ResultSet(markers)
11788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            h = boto.handler.XmlHandler(rs, parent)
11798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if isinstance(body, six.text_type):
11808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                body = body.encode('utf-8')
11818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            xml.sax.parseString(body, h)
11828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return rs
11838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
11848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('%s %s' % (response.status, response.reason))
11858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('%s' % body)
11868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise self.ResponseError(response.status, response.reason, body)
11878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
11888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_object(self, action, params, cls, path='/',
11898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                   parent=None, verb='GET'):
11908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not parent:
11918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            parent = self
11928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        response = self.make_request(action, params, path, verb)
11938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        body = response.read()
11948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug(body)
11958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not body:
11968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('Null body %s' % body)
11978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise self.ResponseError(response.status, response.reason, body)
11988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif response.status == 200:
11998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            obj = cls(parent)
12008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            h = boto.handler.XmlHandler(obj, parent)
12018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if isinstance(body, six.text_type):
12028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                body = body.encode('utf-8')
12038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            xml.sax.parseString(body, h)
12048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return obj
12058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
12068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('%s %s' % (response.status, response.reason))
12078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('%s' % body)
12088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise self.ResponseError(response.status, response.reason, body)
12098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
12108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_status(self, action, params, path='/', parent=None, verb='GET'):
12118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not parent:
12128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            parent = self
12138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        response = self.make_request(action, params, path, verb)
12148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        body = response.read()
12158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        boto.log.debug(body)
12168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if not body:
12178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('Null body %s' % body)
12188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise self.ResponseError(response.status, response.reason, body)
12198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        elif response.status == 200:
12208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            rs = ResultSet()
12218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            h = boto.handler.XmlHandler(rs, parent)
12228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            xml.sax.parseString(body, h)
12238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return rs.status
12248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        else:
12258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('%s %s' % (response.status, response.reason))
12268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            boto.log.error('%s' % body)
12278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            raise self.ResponseError(response.status, response.reason, body)
1228