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