#NEWLINE# def send_file( self , fp , headers = None , cb = None , num_cb = 10 , query_args = None , chunked_transfer = False , size = None ) : #NEWLINE# #INDENT# '\n        Upload a file to a key into a bucket on S3.\n\n        :type fp: file\n        :param fp: The file pointer to upload. The file pointer must point\n                   point at the offset from which you wish to upload.\n                   ie. if uploading the full file, it should point at the\n                   start of the file. Normally when a file is opened for\n                   reading, the fp will point at the first byte. See the\n                   bytes parameter below for more info.\n\n        :type headers: dict\n        :param headers: The headers to pass along with the PUT request\n\n        :type cb: function\n        :param cb: a callback function that will be called to report\n                   progress on the upload.  The callback should accept\n                   two integer parameters, the first representing the\n                   number of bytes that have been successfully\n                   transmitted to S3 and the second representing the\n                   size of the to be transmitted object.\n\n        :type num_cb: int\n        :param num_cb: (optional) If a callback is specified with the cb\n                       parameter this parameter determines the granularity\n                       of the callback by defining the maximum number of\n                       times the callback will be called during the file\n                       transfer. Providing a negative integer will cause\n                       your callback to be called with each buffer read.\n\n        :type size: int\n        :param size: (optional) The Maximum number of bytes to read from\n                      the file pointer (fp). This is useful when uploading\n                      a file in multiple parts where you are splitting the\n                      file up into different ranges to be uploaded. If not\n                      specified, the default behaviour is to read all bytes\n                      from the file pointer. Less bytes may be available.\n        ' #NEWLINE# provider = self . bucket . connection . provider #NEWLINE# try : #NEWLINE# #INDENT# spos = fp . tell ( ) #NEWLINE# #UNINDENT# except IOError : #NEWLINE# #INDENT# spos = None #NEWLINE# self . read_from_stream = False #NEWLINE# #UNINDENT# def sender( http_conn , method , path , data , headers ) : #NEWLINE# #INDENT# if ( ( spos is not None ) and ( spos != fp . tell ( ) ) ) : #NEWLINE# #INDENT# fp . seek ( spos ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( spos is None ) and self . read_from_stream ) : #NEWLINE# #INDENT# raise provider . storage_data_error ( 'Cannot retry failed request. fp does not support seeking.' ) #NEWLINE# #UNINDENT# #UNINDENT# http_conn . putrequest ( method , path ) #NEWLINE# for key in headers : #NEWLINE# #INDENT# http_conn . putheader ( key , headers [ key ] ) #NEWLINE# #UNINDENT# http_conn . endheaders ( ) #NEWLINE# if ( not self . base64md5 ) : #NEWLINE# #INDENT# m = md5 ( ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# m = None #NEWLINE# #UNINDENT# save_debug = self . bucket . connection . debug #NEWLINE# self . bucket . connection . debug = 0 #NEWLINE# if ( getattr ( http_conn , 'debuglevel' , 0 ) < 3 ) : #NEWLINE# #INDENT# http_conn . set_debuglevel ( 0 ) #NEWLINE# #UNINDENT# data_len = 0 #NEWLINE# if cb : #NEWLINE# #INDENT# if size : #NEWLINE# #INDENT# cb_size = size #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if self . size : #NEWLINE# #INDENT# cb_size = self . size #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# cb_size = 0 #NEWLINE# #UNINDENT# #UNINDENT# if ( chunked_transfer and ( cb_size == 0 ) ) : #NEWLINE# #INDENT# cb_count = ( ( 1024 * 1024 ) / self . BufferSize ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( num_cb > 1 ) : #NEWLINE# #INDENT# cb_count = int ( math . ceil ( ( ( cb_size / self . BufferSize ) / ( num_cb - 1.0 ) ) ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( num_cb < 0 ) : #NEWLINE# #INDENT# cb_count = ( - 1 ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# cb_count = 0 #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# i = 0 #NEWLINE# cb ( data_len , cb_size ) #NEWLINE# #UNINDENT# bytes_togo = size #NEWLINE# if ( bytes_togo and ( bytes_togo < self . BufferSize ) ) : #NEWLINE# #INDENT# chunk = fp . read ( bytes_togo ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# chunk = fp . read ( self . BufferSize ) #NEWLINE# #UNINDENT# if ( spos is None ) : #NEWLINE# #INDENT# self . read_from_stream = True #NEWLINE# #UNINDENT# while chunk : #NEWLINE# #INDENT# chunk_len = len ( chunk ) #NEWLINE# data_len += chunk_len #NEWLINE# if chunked_transfer : #NEWLINE# #INDENT# http_conn . send ( ( '%x;\r\n' % chunk_len ) ) #NEWLINE# http_conn . send ( chunk ) #NEWLINE# http_conn . send ( '\r\n' ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# http_conn . send ( chunk ) #NEWLINE# #UNINDENT# if m : #NEWLINE# #INDENT# m . update ( chunk ) #NEWLINE# #UNINDENT# if bytes_togo : #NEWLINE# #INDENT# bytes_togo -= chunk_len #NEWLINE# if ( bytes_togo <= 0 ) : #NEWLINE# #INDENT# break #NEWLINE# #UNINDENT# #UNINDENT# if cb : #NEWLINE# #INDENT# i += 1 #NEWLINE# if ( ( i == cb_count ) or ( cb_count == ( - 1 ) ) ) : #NEWLINE# #INDENT# cb ( data_len , cb_size ) #NEWLINE# i = 0 #NEWLINE# #UNINDENT# #UNINDENT# if ( bytes_togo and ( bytes_togo < self . BufferSize ) ) : #NEWLINE# #INDENT# chunk = fp . read ( bytes_togo ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# chunk = fp . read ( self . BufferSize ) #NEWLINE# #UNINDENT# #UNINDENT# self . size = data_len #NEWLINE# if m : #NEWLINE# #INDENT# hd = m . hexdigest ( ) #NEWLINE# ( self . md5 , self . base64md5 ) = self . get_md5_from_hexdigest ( hd ) #NEWLINE# #UNINDENT# if chunked_transfer : #NEWLINE# #INDENT# http_conn . send ( '0\r\n' ) #NEWLINE# http_conn . send ( '\r\n' ) #NEWLINE# #UNINDENT# if ( cb and ( ( cb_count <= 1 ) or ( i > 0 ) ) and ( data_len > 0 ) ) : #NEWLINE# #INDENT# cb ( data_len , cb_size ) #NEWLINE# #UNINDENT# response = http_conn . getresponse ( ) #NEWLINE# body = response . read ( ) #NEWLINE# http_conn . set_debuglevel ( save_debug ) #NEWLINE# self . bucket . connection . debug = save_debug #NEWLINE# if ( ( ( response . status == 500 ) or ( response . status == 503 ) or response . getheader ( 'location' ) ) and ( not chunked_transfer ) ) : #NEWLINE# #INDENT# return response #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( ( response . status >= 200 ) and ( response . status <= 299 ) ) : #NEWLINE# #INDENT# self . etag = response . getheader ( 'etag' ) #NEWLINE# if ( self . etag != ( '"%s"' % self . md5 ) ) : #NEWLINE# #INDENT# raise provider . storage_data_error ( 'ETag from S3 did not match computed MD5' ) #NEWLINE# #UNINDENT# return response #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# raise provider . storage_response_error ( response . status , response . reason , body ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# if ( not headers ) : #NEWLINE# #INDENT# headers = { #NEWLINE# #INDENT# #NEWLINE# #UNINDENT# } #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# headers = headers . copy ( ) #NEWLINE# #UNINDENT# headers [ 'User-Agent' ] = UserAgent #NEWLINE# if ( self . storage_class != 'STANDARD' ) : #NEWLINE# #INDENT# headers [ provider . storage_class_header ] = self . storage_class #NEWLINE# #UNINDENT# if headers . has_key ( 'Content-Encoding' ) : #NEWLINE# #INDENT# self . content_encoding = headers [ 'Content-Encoding' ] #NEWLINE# #UNINDENT# if headers . has_key ( 'Content-Type' ) : #NEWLINE# #INDENT# if ( headers [ 'Content-Type' ] is None ) : #NEWLINE# #INDENT# del headers [ 'Content-Type' ] #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# self . content_type = headers [ 'Content-Type' ] #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if self . path : #NEWLINE# #INDENT# self . content_type = mimetypes . guess_type ( self . path ) [ 0 ] #NEWLINE# if ( self . content_type == None ) : #NEWLINE# #INDENT# self . content_type = self . DefaultContentType #NEWLINE# #UNINDENT# headers [ 'Content-Type' ] = self . content_type #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# headers [ 'Content-Type' ] = self . content_type #NEWLINE# #UNINDENT# #UNINDENT# if self . base64md5 : #NEWLINE# #INDENT# headers [ 'Content-MD5' ] = self . base64md5 #NEWLINE# #UNINDENT# if chunked_transfer : #NEWLINE# #INDENT# headers [ 'Transfer-Encoding' ] = 'chunked' #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# headers [ 'Content-Length' ] = str ( self . size ) #NEWLINE# #UNINDENT# headers [ 'Expect' ] = '100-Continue' #NEWLINE# headers = boto . utils . merge_meta ( headers , self . metadata , provider ) #NEWLINE# resp = self . bucket . connection . make_request ( 'PUT' , self . bucket . name , self . name , self , sender = sender , query_args = query_args ) #NEWLINE# self . handle_version_headers ( resp , force = True )