
    q                        d Z ddlmZ ddlmZ ddlmZ ddlmZ ddlZddlZddlZddl	Z	ddl
Z
ddlZddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddl Z ddl m!Z! ejD                  re#Z$ ed       Z% G d de&      Z' G d de&      Z(d Z) G d de&      Z*d Z+ G d de jX                        Z- G d d e jX                        Z.y)!zEMedia helper functions and classes for Google Cloud Storage JSON API.    )absolute_import)print_function)division)unicode_literalsN)http_client)urllib)	cStringIO)
exceptions)BadRequestException)LazyWrapper)ProgressCallbackWithTimeout)DEBUGLEVEL_DUMP_REQUESTS)SSL_TIMEOUT_SEC)TRANSFER_BUFFER_SIZE)UTF8)	text_util)	parse_uric                  ,    t        j                  d      S )Nz\d+)recompile     'platform/gsutil/gslib/gcs_json_media.py<lambda>r   2   s    RZZ%7r   c                   J    e Zd ZdZd Zed        Zej                  d        Zy)BytesTransferredContainera  Container class for passing number of bytes transferred to lower layers.

  For resumed transfers or connection rebuilds in the middle of a transfer, we
  need to rebuild the connection class with how much we've transferred so far.
  For uploads, we don't know the total number of bytes uploaded until we've
  queried the server, but we need to create the connection class to pass to
  httplib2 before we can query the server. This container object allows us to
  pass a reference into Upload/DownloadCallbackConnection.
  c                     d| _         y )Nr   -_BytesTransferredContainer__bytes_transferredselfs    r   __init__z"BytesTransferredContainer.__init__@   s
     Dr   c                     | j                   S Nr   r    s    r   bytes_transferredz+BytesTransferredContainer.bytes_transferredC   s    ###r   c                     || _         y r$   r   r!   values     r   r%   z+BytesTransferredContainer.bytes_transferredG   s
    $Dr   N)__name__
__module____qualname____doc__r"   propertyr%   setterr   r   r   r   r   5   s:    ! $ $ % %r   r   c                   (    e Zd ZdZeddddfdZd Zy)$UploadCallbackConnectionClassFactoryzCreates a class that can override an httplib2 connection.

  This is used to provide progress callbacks and disable dumping the upload
  payload during debug statements. It can later be used to provide on-the-fly
  hash digestion during upload.
  r   Nc                 X    || _         || _        || _        || _        || _        || _        y r$   )bytes_uploaded_containerbuffer_size
total_sizeprogress_callbackloggerdebug)r!   r2   r3   r4   r5   r6   r7   s          r   r"   z-UploadCallbackConnectionClassFactory.__init__T   s1     %=D!"D DO.DDKDJr   c                     | j                   | j                  | j                  | j                  | j                  | j
                   G fddt        j                        }|S )z/Returns a connection class that overrides send.c                   j    e Zd ZdZW ZdZW  ZdZW ZdZ	dZ
dZdZd Zd
fd	ZfdZdfd		Zy)YUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnectionz&Connection class override for uploads.FN g      ?c                 \    t         |d<   t        j                  j                  | g|i | y Ntimeoutr   httplib2HTTPSConnectionWithTimeoutr"   r!   argskwargss      r   r"   zbUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection.__init__z   *    +y++44TKDKFKr   c                 8   | j                   j                  d       t        j                  r| j                   }nYg }| j                   D ]H  }t	        |t
              r|j                  |       %|j                  |j                  t                     J dj                  |      }t        |      }t        k(  rrj                  d|z         | j                   dd= t	        |t              r||z  }d}| j                  ||       || j                  |       yy)zSend the currently buffered request and clear the buffer.

        Appends an extra \r\n to the buffer.

        Args:
          message_body: if specified, this is appended to the request.
        )r   r   s   
zsend: %sN)num_metadata_bytes)_bufferextendsixPY2
isinstancebytesappendencoder   joinlenr   r7   strsend)	r!   message_bodyencode_chunkeditemsitemmsgrG   outer_debugouter_loggers	          r   _send_outputzfUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection._send_output   s     	J'77,,%%lld$&ll4 ll4;;t,-	 #
 ll5! X22|


Z#-
.LLO lC(

#,		#*<	=# ))L
! $r   c           
         |dk(  rLdj                  |D cg c]  }t        |       c}      }|| _        t        k(  r͉rˉj	                  d       n|dk(  r:	 t        dj                  |D cg c]  }t        |       c}            }|| _        nz|dk(  ru	 dj                  |D cg c]  }t        |       c}      }t               j                  |      }t        |      dkD  r%t        |d         t        |d         z
  dz   | _        | j                  dk(  r}| j                  rq| j                  re| j                  t        | j                        z  | _        d| _        d	| _        d	| _        t        k(  r rj	                  d
| j                  z         t        j                  j                   | |g|  y	c c}w c c}w # t        $ r Y w xY wc c}w # t        $ r Y w xY w)a  Overrides HTTPConnection.putheader.

        Send a request header line to the server. For example:
        h.putheader('Accept', 'text/html').

        This override records the content encoding, length, and range of the
        payload. For uploads where the content-range difference does not match
        the content-length, progress printing will under-report progress. These
        headers are used to calculate a multiplier to correct the progress.

        For example: the content-length for gzip transport encoded data
        represents the compressed size of the data while the content-range
        difference represents the uncompressed size. Dividing the
        content-range difference by the content-length gives the ratio to
        multiply the progress by to correctly report the relative progress.

        Args:
          header: The header.
          *values: A set of values for the header.
        zcontent-encodingr;   z4send: Using gzip transport encoding for the request.content-lengthzcontent-range   r   gzipNz&send: Setting progress modifier to %s.)rP   rR   header_encodingr   r7   intheader_length
ValueErrorDECIMAL_REGEXfindallrQ   header_rangefloatsize_modifierr   HTTPSConnection	putheader)r!   headervaluesvr(   rangesrY   rZ   s         r   rj   zcUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection.putheader   s   * ''''626a3q6623%!&$
44FH'' 8AQ 89:E!&D & GGV4VSVV45E"_,,U3F 6{Q#&vay>Cq	N#Ba"Gd
   F*t/A/A#0059K9K3LL$
!#$
#$
"$
44G $ 2 2 4 5 	##--dFDVDO 3 !9  5  sN   F:G -F??G G 'G9AG ?G 	GGG 	G$#G$c                    | j                   sId| _         r@t              | _        | j                  j                  | j                  j
                         t        |t        j                        rt        |      }n2t        |t        j                        rt        j                  |      }n|}|j                  | j                        }|rt        j                  r!t        j                   j#                  | |       ndt        |t$              r!t        j                   j#                  | |       n3t        j                   j#                  | |j'                  t(                     t+        |      }|r||k  r||z  }d}n||z  }d}| j                  r3t-        || j.                  z        }| j                  j                  |       |j                  | j                        }|ryy)a  Overrides HTTPConnection.send.

        Args:
          data: string or file-like object (implements read()) of data to send.
          num_metadata_bytes: number of bytes that consist of metadata
              (headers, etc.) not representing the data being uploaded.
        Tr   N)processed_initial_bytesr   callback_processorProgressr2   r%   rL   rJ   	text_typer	   binary_typeBytesIOreadGCS_JSON_BUFFER_SIZErK   r@   rA   rS   rM   rO   r   rQ   ra   rh   )r!   datarG   full_bufferpartial_buffersent_data_bytesouter_progress_callbackouter_total_sizes         r   rS   z^UploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection.send   s    ++)-$
&$&A "9';D###,,--??A dCMM*!$+coo.D)++$))$*C*CDWW//44T>J.%01166t^L1166--d35//!_4!33o#$  O3  !o$$ "/D4F4F"FGO ##,,_=&++D,E,EF.7 r   )NF)r   )r)   r*   r+   r,   r2   rp   rw   rq   sizer`   rb   rf   rh   r"   r[   rj   rS   )outer_buffer_sizeouter_bytes_uploaded_containerrY   rZ   r|   r}   s   r   UploadCallbackConnectionr:   k   sR    2!? !&.domlmL%"N=E~3Gr   r   )r2   r3   r4   r5   r6   r7   r@   rA   )r!   r   r   r   rY   rZ   r|   r}   s     @@@@@@r   GetConnectionClassz7UploadCallbackConnectionClassFactory.GetConnectionClassb   si    %)%B%B"(("44;;L**KoG oG8#F#F oGb $#r   r)   r*   r+   r,   r   r"   r   r   r   r   r0   r0   L   s#     0!%z$r   r0   c                 ^    | j                   dddt        j                  dffd	}|| _         y)zWraps upload_http so we only use our custom connection_type on PUTs.

  POSTs are used to refresh oauth tokens, and we don't want to process the
  data sent in those requests.

  Args:
    upload_http: httplib2.Http instance to wrap
  GETNc                 >    |dk(  s|dk(  r|}nd } | |||||      S )NPUTPOSTmethodbodyheadersredirectionsconnection_typer   )urir   r   r   r   r   override_connection_typerequest_origs          r   
NewRequestz)WrapUploadHttpRequest.<locals>.NewRequest*  s?     &F*!0!%%! '%1(@B Br   )requestr@   DEFAULT_MAX_REDIRECTS)upload_httpr   r   s     @r   WrapUploadHttpRequestr     s7     $$, &<<!%B$ #+r   c                   &    e Zd ZdZedddfdZd Zy)&DownloadCallbackConnectionClassFactorya  Creates a class that can override an httplib2 connection.

  This is used to provide progress callbacks, disable dumping the download
  payload during debug statements, and provide on-the-fly hash digestion during
  download. On-the-fly digestion is particularly important because httplib2
  will decompress gzipped content on-the-fly, thus this class provides our
  only opportunity to calculate the correct hash for an object that has a
  gzip hash in the cloud.
  r   Nc                 J    || _         || _        || _        || _        || _        y r$   )r3   r4   r5   	digestersbytes_downloaded_container)r!   r   r3   r4   r5   r   s         r   r"   z/DownloadCallbackConnectionClassFactory.__init__J  s*     #D DO.DDN&@D#r   c                 >      G  fddt         j                        }|S )z6Returns a connection class that overrides getresponse.c                       e Zd ZdZW  j                  ZW  j                  ZW  j                  Z	W  j                  ZdZdZd ZddZy)]DownloadCallbackConnectionClassFactory.GetConnectionClass.<locals>.DownloadCallbackConnectionz(Connection class override for downloads.FNc                 \    t         |d<   t        j                  j                  | g|i | y r=   r?   rB   s      r   r"   zfDownloadCallbackConnectionClassFactory.GetConnectionClass.<locals>.DownloadCallbackConnection.__init__b  rE   r   c                      t         j                  j                         }|j                  t         j                  t         j
                  fvr|S |j                  d fd	}||_        |S )a  Wraps an HTTPResponse to perform callbacks and hashing.

        In this function, self is a DownloadCallbackConnection.

        Args:
          buffering: Unused. This function uses a local buffer.

        Returns:
          HTTPResponse object with wrapped read function.
        c                 .   | r	| t         kD  rt        d| dt         d      | xs t         } j                  sgd_        j                  rTt	        j
                  j                        _        j                  j                  j                  j                          |       }t        |      }j                  rj                  j                  |       j                  r/j                  D ]   }j                  |   j                  |       " |S )a  Overrides HTTPConnection.getresponse.read.

          This function only supports reads of TRANSFER_BUFFER_SIZE or smaller.

          Args:
            amt: Integer n where 0 < n <= TRANSFER_BUFFER_SIZE. This is a
                 keyword argument to match the read function it overrides,
                 but it is required.

          Returns:
            Data read from HTTPConnection.
          zInvalid HTTP read size z during download, expected .T)r   r   rp   r|   r   r}   rq   rr    outer_bytes_downloaded_containerr%   rQ   outer_digestersupdate)amtrx   read_lengthalgorig_read_funcr!   s       r   rv   zwDownloadCallbackConnectionClassFactory.GetConnectionClass.<locals>.DownloadCallbackConnection.getresponse.<locals>.readw  s     22%*,- - --C--+/D(++(C'')E)E)Gd%%%..77IIK  $$D	+$$##,,[9!!++""3'..t4 ,+r   r$   )r   HTTPConnectiongetresponsestatusOKPARTIAL_CONTENTrv   )r!   	bufferingorig_responserv   r   s   `   @r   r   ziDownloadCallbackConnectionClassFactory.GetConnectionClass.<locals>.DownloadCallbackConnection.getresponsef  sf     $22>>tD(3(C(C(E E
&++#	J "r   )F)r)   r*   r+   r,   r4   r}   r   r   r5   r|   r   r   rp   rq   r"   r   r    s   r   DownloadCallbackConnectionr   Y  sH    4o $ 6 6)-)H)H& %L8r   r   )r@   rA   )r!   r   s   ` r   r   z9DownloadCallbackConnectionClassFactory.GetConnectionClassV  s     EX%H%H EN &%r   r   r   r   r   r   r   ?  s!     0!%
AJ&r   r   c                     d }| j                   dddt        j                  dffd	}t        j                  ||       | _        || _         | S )zOverrides download request functions for an httplib2.Http object.

  Args:
    download_http: httplib2.Http.object to wrap / override.

  Returns:
    Wrapped / overridden httplib2.Http object.
  c
                 z   | j                   D 
cg c]'  }
|
j                  ||      r|
j                  |      |
f) }}
|xr t        |      d   d   xs d}
|
r|
j	                  ||||       | j                  |||||      \  }}|
rE|
j                  ||      r3|
j	                  ||||       | j                  |||||      \  }}d|_        |j                  dk(  r| j                  |||||      D ]l  }|j	                  ||||       | j                  |||||      \  }}|j                  dk7  s?| j                   j                  |       |j                  ||        n | j                  s|dv s|j                  dk(  r| j                  rk|j                  dv r\|r>d|vr&|j                  d	k7  rt        j                  d
||      d|v r;|d   }t        |      \  }}}}}|#t         j"                  j%                  ||      |d<   |j                  dk(  r8|dv r4|d   |d<   d|vr||d<   t        j&                  |||| j(                  |	       d|v r|d= d|v r|d= d|v r| j*                  s|d= d|v r|d   }t-        j.                  |      }d|vr||d<   |}|j                  dv rd}d}| j	                  |||||dz
  |j0                        \  }}||_        ||fS t        j4                  d||      ||fS |j                  dv r0|dv r,d|v r||d<   t        j&                  |||| j(                  |	       ||fS c c}
w )zlDo the actual request using the connection object.
    Also follow one level of redirects if necessary.
    r   r^   Ni  )r   HEAD/  ),  -  .  r   i3  locationr   z:Redirected but the response is missing a Location: header.r   z-x-permanent-redirect-urlzcontent-locationzif-none-matchzif-modified-sinceauthorization)r   r   r   )r   r   r   r   z4Redirected more times than redirection_limit allows.)      )authorizationsinscopedepthsortedr   _conn_requestresponse_stale_digestr   _auth_from_challengerN   follow_all_redirectsfollow_redirectsr@   RedirectMissingLocationr   r   parseurljoin_updateCachecacheforward_authorization_headerscopydeepcopy	__class__previousRedirectLimit)r!   connhostabsolute_urirequest_urir   r   r   r   cachekeyauthauthsr   contentr   r   scheme	authoritypathqueryfragmentold_responseredirect_methods                          r   OverrideRequestz0WrapDownloadHttpRequest.<locals>.OverrideRequest  s    ;?:M:M 2:M$dK0 zz+&-:ME 2(VE]1%a(0DD
ll6;6,,T;-46Xw 	x	&V['48"00{F15w@7!"#44
Wh9-fk7DA"00{F15w@7??c!



$
$]
3

 
 4
0
9 	!!f&???c!			8?? 7A $A x'HOOs,B22L'# # 8#
+H9B89L6VYeX %+\\%9%9,%Qhz"__#/(A4<Z4HH01!1-9h)*!!'8Wdjj"*,'( G++,(44(8#
+H==2L!51=l-.$O*, %od"&,,/g)!^ $	 #/ #0Xw
 !-H g &&D! ! g ??j(V-F ))5(%
&gx$**&	( gi2s   ,L8r   Nc                 F    |dk(  r | ||||d       S  | |||||      S )Nr   r   r   )r   r   r   r   r   r   r   s         r   r   z+WrapDownloadHttpRequest.<locals>.NewRequest  sE     #f4")*.0 0 #f4")*9; ;r   )r   r@   r   types
MethodType_request)download_httpr   r   r   s      @r   WrapDownloadHttpRequestr     sT    *Z~ &&,"t&<<!%
; !++O]K-$-	r   c                       e Zd ZdZd Zy)HttpWithNoRetriesa<  httplib2.Http variant that does not retry.

  httplib2 automatically retries requests according to httplib2.RETRIES, but
  in certain cases httplib2 ignores the RETRIES value and forces a retry.
  Because httplib2 does not handle the case where the underlying request body
  is a stream, a retry may cause a non-idempotent write as the stream is
  partially consumed and not reset before the retry occurs.

  Here we override _conn_request to disable retries unequivocally, so that
  uploads may be retried at higher layers that properly handle stream request
  bodies.
  c                    	 t        |d      r|j                  |j                          |j                  ||||       	 |j'                         }d}	|dk(  r|j                          n|j)                         }	t        j*                  |      }|dk7  rt        j,                  ||	      }	||	fS # t        j
                  $ r  t        j                  $ r3 |j                          t        j                  d|j                  z        t        j                  j                  $ r |j                           t        j                  $ rS}d}t        |d      rt        |d      d   }n|j                  }|t        j                  j                   k(  r Y d }~Rd }~wt"        j$                  $ r |j                           w xY w# t        j                  t"        j$                  f$ r |j                           w xY w)NsockUnable to find the server at %sr   rC   r;   r   )hasattrr   connectr   socketr>   gaierrorcloser@   ServerNotFoundErrorr   sslSSLErrorerrorgetattrerrnoECONNREFUSEDr   HTTPExceptionr   rv   Response_decompressContent)
r!   r   r   r   r   r   eerrr   r   s
             r   r   zHttpWithNoRetries._conn_request9  s   	v	499#4
ll6;g6*A!!#h
 g	6	

--/""8,h	6	--h@gG >> ?? 4
jjl(()J)-*3 4 4<<   
jjl<< c	F	a #gg	++	+ 
,$$ 
jjl
 LL+334 
jjls$   <B+ F; +BF8AF(F8;5G0N)r)   r*   r+   r,   r   r   r   r   r   r   +  s    )r   r   c                   \     e Zd ZdZ fdZed        Zej                  d        Zd Z xZ	S )HttpWithDownloadStreama  httplib2.Http variant that only pushes bytes through a stream.

  httplib2 handles media by storing entire chunks of responses in memory, which
  is undesirable particularly when multiple instances are used during
  multi-threaded/multi-process copy. This class copies and then overrides some
  httplib2 functions to use a streaming copy approach that uses small memory
  buffers.

  Also disables httplib2 retries (for reasons stated in the HttpWithNoRetries
  class doc).
  c                 l    d | _         t        j                         | _        t	        t
        |   |i | y r$   )_streamlogging	getLogger_loggersuperr   r"   )r!   rC   kwdsr   s      r   r"   zHttpWithDownloadStream.__init__r  s/    DL$$&DL	
 $0$?$?r   c                     | j                   S r$   r  r    s    r   streamzHttpWithDownloadStream.streamw  s    <<r   c                     || _         y r$   r  r'   s     r   r	  zHttpWithDownloadStream.stream{  s	    DLr   c                    	 t        |d      r|j                  |j                          |j                  ||||       	 |j'                         }d}	|dk(  r)|j                          t        j(                  |      }||	fS |dk(  r>|j*                  t"        j,                  t"        j.                  fv rd }
t        |d      r|j1                  d	      }
|}d}	 |j3                  t4              }|rP| j6                  t9        j:                  d
      t=        j>                  | j6                  |       |tA        |      z  }nni|
itC        |      tC        |
      k7  rR| jD                  jG                  tH        jJ                  d||
|       |jL                  d	= tO        |      |jL                  d	<   t        j(                  |      }||	fS |j3                         }	t        j(                  |      }t        jP                  ||	      }	||	fS # t        j
                  $ r  t        j                  $ r3 |j                          t        j                  d|j                  z        t        j                  j                  $ r |j                           t        j                  $ rS}d}t        |d      rt        |d      d   }n|j                  }|t        j                  j                   k(  r Y d }~d }~wt"        j$                  $ r |j                           w xY w# t        j                  t"        j$                  f$ r}|j                           d }~ww xY w)Nr   r   r   rC   r;   r   r   rX   r]   z5Cannot exercise HttpWithDownloadStream with no streamzlOnly got %s bytes out of content-length %s for request URI %s. Resetting content-length to match bytes read.))r   r   r   r   r   r>   r   r   r@   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   	getheaderrv   r   r	  apitools_exceptionsInvalidUserInputErrorr   write_to_fdrQ   longr  logr  DEBUGrX   rR   r   )r!   r   r   r   r   r   r   r   r   r   content_lengthhttp_stream
bytes_readnew_datas                 r   r   z$HttpWithDownloadStream._conn_request  s   	v	499#4
ll6;g6.4A!!#h
 g	6	

$$X.X gW U?x;>>3>3N3N3P  P8U##--.>?.
 %%&:;({{"'==IK K!!$++x8#h-'J  &^ 44 ,,

mm 'F ll+,+.z?(,,'
($$X. g	 --/$$X.--h@gW >> ?? 4
jjl(()J)-*3 4 4<<   
jjl<< c	F	a #gg	++	+ 
,$$  jjl	 LL+334 
jjls0   <H L BLAK''(L#M5MM)
r)   r*   r+   r,   r"   r-   r	  r.   r   __classcell__)r   s   @r   r   r   e  s@    
@
   
== Pr   r   )/r,   
__future__r   r   r   r   r   r  r   r   r   rJ   	six.movesr   r   r	   apitools.base.pyr
   r  gslib.cloud_apir   gslib.lazy_wrapperr   gslib.progress_callbackr   gslib.utils.constantsr   r   r   r   gslib.utilsr   r@   r   PY3ra   r  rd   objectr   r0   r   r   r   Httpr   r   r   r   r   <module>r#     s    L & %  '   	   
 !   > / * ? : 1 6 & !  77	$ 89% %.P$6 P$f#@a&V a&HEP7 7tkX]] kr   