
    q                        S r SSKJr  SSKJr  SSKJr  SSKJr  SSKrSSKrSSKrSSK	r	SSK
r
SSKrSSKJr  SSKJr  SS	KJr  SS
KJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSKJr  SSK r SSK J!r!  \RD                  (       a  \#r$\" S 5      r% " S S\&5      r' " S S\&5      r(S r) " S S\&5      r*S r+ " S S\ RX                  5      r- " S S \ RX                  5      r.g)!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                  .    [         R                  " S5      $ )Nz\d+)recompile     'platform/gsutil/gslib/gcs_json_media.py<lambda>r   2   s    RZZ%7r   c                   R    \ rS rSrSrS r\S 5       r\R                  S 5       rSr	g)BytesTransferredContainer5   a  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                     SU l         g )Nr   -_BytesTransferredContainer__bytes_transferredselfs    r   __init__"BytesTransferredContainer.__init__@   s
     Dr   c                     U R                   $ Nr   r!   s    r   bytes_transferred+BytesTransferredContainer.bytes_transferredC   s    ###r   c                     Xl         g r&   r   r"   values     r   r'   r(   G   s    $r   )__bytes_transferredN)
__name__
__module____qualname____firstlineno____doc__r#   propertyr'   setter__static_attributes__r   r   r   r   r   5   s:    ! $ $ % %r   r   c                   2    \ rS rSrSr\SSSS4S jrS rSrg)$UploadCallbackConnectionClassFactoryL   zCreates 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                 L    Xl         X l        X0l        X@l        XPl        X`l        g r&   )bytes_uploaded_containerbuffer_size
total_sizeprogress_callbackloggerdebug)r"   r9   r:   r;   r<   r=   r>   s          r   r#   -UploadCallbackConnectionClassFactory.__init__T   s%     %=!" O.KJr   c                    ^^^^^^ U R                   mU R                  mU R                  mU R                  mU R                  mU R
                  m " UUUUUU4S jS[        R                  5      nU$ )z/Returns a connection class that overrides send.c                   |   > \ rS rSrSr YrSr Y rSr Yr	Sr
SrSrSrS rSUU4S jjrUU4S	 jrSUU4S
 jjrSrg)YUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnectionk   z&Connection class override for uploads.FN g      ?c                 ^    [         US'   [        R                  R                  " U /UQ70 UD6  g Ntimeoutr   httplib2HTTPSConnectionWithTimeoutr#   r"   argskwargss      r   r#   bUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection.__init__z   *    +y++44TKDKFKr   c                 `  > U R                   R                  S5        [        R                  (       a  U R                   nOa/ nU R                    HO  n[	        U[
        5      (       a  UR                  U5        M+  UR                  UR                  [        5      5        MQ     SR                  U5      n[        U5      nT[        :X  a  T(       a  TR                  SU-  5        U R                   SS2	 [	        U[        5      (       a  XQ-  nSnU R                  XVS9  Ub  U R                  U5        gg)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   r>   strsend)	r"   message_bodyencode_chunkeditemsitemmsgrQ   outer_debugouter_loggers	          r   _send_outputfUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection._send_output   s     	J'77,,%%lld$&&ll4 ll4;;t,-	 #
 ll5! X22|


Z#-
.LLO lC((

#,		#	=# ))L
! $r   c           
        > US:X  aT  SR                  U Vs/ s H  n[        U5      PM     sn5      nX@l        T[        :X  a  T(       a  TR	                  S5        OUS:X  a<   [        SR                  U Vs/ s H  n[        U5      PM     sn5      5      nX@l        OUS:X  ay   SR                  U Vs/ s H  n[        U5      PM     sn5      n[        5       R                  U5      n[        U5      S:  a%  [        US   5      [        US   5      -
  S-   U l        U R                  S:X  a  U R                  (       a|  U R                  (       ak  U R                  [        U R                  5      -  U l        SU l        S	U l        S	U l        T[        :X  a%  T(       a  TR	                  S
U R                  -  5        [        R                  R                   " X/UQ76   g	s  snf s  snf ! [         a     Nf = fs  snf ! [         a     Nf = f)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-encodingrD   z4send: Using gzip transport encoding for the request.content-lengthzcontent-range   r   gzipNz&send: Setting progress modifier to %s.)rZ   r\   header_encodingr   r>   intheader_length
ValueErrorDECIMAL_REGEXfindallr[   header_rangefloatsize_modifierr   HTTPSConnection	putheader)r"   headervaluesvr+   rangesrc   rd   s         r   ru   cUploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection.putheader   s   * ''''626a3q6623%!&
44FH'' 8AQ 89:E!& & 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 	##--dDVDO 3 !9  5  sN   G#G& 7G!G& %G; 4G6	AG; !G& &
G32G36G; ;
HHc                 "  > U R                   (       dN  SU l         T(       a@  [        TT5      U l        U R                  R                  U R                  R
                  5        [        U[        R                  5      (       a  [        U5      nO8[        U[        R                  5      (       a  [        R                  " U5      nOUnUR                  U R                  5      nU(       Ga)  [        R                  (       a   [        R                   R#                  X5        Og[        U[$        5      (       a   [        R                   R#                  X5        O2[        R                   R#                  XR'                  [(        5      5        [+        U5      nU(       a  X%::  a  XR-  nSnOX%-  nSnU R                  (       a2  [-        XPR.                  -  5      nU R                  R                  U5        UR                  U R                  5      nU(       a  GM(  gg)zOverrides 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Progressr9   r'   rV   rT   	text_typer	   binary_typeBytesIOreadGCS_JSON_BUFFER_SIZErU   rI   rJ   r]   rW   rY   r   r[   rl   rs   )r"   datarQ   full_bufferpartial_buffersent_data_bytesouter_progress_callbackouter_total_sizes         r   r]   ^UploadCallbackConnectionClassFactory.GetConnectionClass.<locals>.UploadCallbackConnection.send   s    ++)-$
&$&A "9';D###,,--??A dCMM**!$+coo..D)++$))$*C*CDWW//44TJ.%001166tL1166--d35//!43o#$  3  !o$$ "/4F4F"FGO ##,,_=&++D,E,EF.7 nr   )r}   rk   rm   rq   r|   rs   )NF)r   )r-   r.   r/   r0   r1   r9   r|   r   r}   sizerk   rm   rq   rs   r#   re   ru   r]   r4   )outer_buffer_sizeouter_bytes_uploaded_containerrc   rd   r   r   s   r   UploadCallbackConnectionrB   k   s]    2!? !&.domlmL%" %"N=E~3G 3Gr   r   )r9   r:   r;   r<   r=   r>   rI   rJ   )r"   r   r   r   rc   rd   r   r   s     @@@@@@r   GetConnectionClass7UploadCallbackConnectionClassFactory.GetConnectionClassb   si    %)%B%B"(("44;;L**KoG oG8#F#F oGb $#r   )r:   r9   r>   r=   r<   r;   	r-   r.   r/   r0   r1   r   r#   r   r4   r   r   r   r6   r6   L   s#     0!%z$r   r6   c                 `   ^ U R                   mSSS[        R                  S4U4S jjnXl         g)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           	      <   > US:X  d  US:X  a  UnOS nT" U UUUUUS9$ )NPUTPOSTmethodbodyheadersredirectionsconnection_typer   )urir   r   r   r   r   override_connection_typerequest_origs          r   
NewRequest)WrapUploadHttpRequest.<locals>.NewRequest*  s?     &F*!0!%%! '%1(@B Br   )requestrI   DEFAULT_MAX_REDIRECTS)upload_httpr   r   s     @r   WrapUploadHttpRequestr     s5     $$, &<<!%B$ #r   c                   0    \ rS rSrSr\SSS4S jrS rSrg)&DownloadCallbackConnectionClassFactoryi?  a  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                 @    X l         X0l        X@l        XPl        Xl        g r&   )r:   r;   r<   	digestersbytes_downloaded_container)r"   r   r:   r;   r<   r   s         r   r#   /DownloadCallbackConnectionClassFactory.__init__J  s      # O.N&@#r   c                 @   ^   " U 4S jS[         R                  5      nU$ )z6Returns a connection class that overrides getresponse.c                      > \ rS rSrSr Y R
                  r Y R                  r Y R                  r
 Y R                  rSrSrS rSS jrSrg)	]DownloadCallbackConnectionClassFactory.GetConnectionClass.<locals>.DownloadCallbackConnectioniY  z(Connection class override for downloads.FNc                 ^    [         US'   [        R                  R                  " U /UQ70 UD6  g rF   rH   rK   s      r   r#   fDownloadCallbackConnectionClassFactory.GetConnectionClass.<locals>.DownloadCallbackConnection.__init__b  rO   r   c                    ^ ^ [         R                  R                  T 5      nUR                  [         R                  [         R
                  4;  a  U$ UR                  mSUU 4S jjnX2l        U$ )zWraps 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                 t  > U (       a
  U [         :  a  [        SU < S[         < S35      eU =(       d    [         n TR                  (       dl  STl        TR                  (       aT  [	        TR
                  TR                  5      Tl        TR                  R                  TR                  R                  5        T" U 5      n[        U5      nTR                  (       a  TR                  R                  U5        TR                  (       a1  TR                   H!  nTR                  U   R                  U5        M#     U$ )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   r|   r   r   r   r}   r~    outer_bytes_downloaded_containerr'   r[   outer_digestersupdate)amtr   read_lengthalgorig_read_funcr"   s       r   r   wDownloadCallbackConnectionClassFactory.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_CONTENTr   )r"   	bufferingorig_responser   r   s   `   @r   r   iDownloadCallbackConnectionClassFactory.GetConnectionClass.<locals>.DownloadCallbackConnection.getresponsef  si     $22>>tD(3(C(C(E E
&++#	 #	J "r   )r}   r|   )F)r-   r.   r/   r0   r1   r;   r   r   r   r<   r   r   r   r|   r}   r#   r   r4   r!   s   r   DownloadCallbackConnectionr   Y  sH    4o $ 6 6)-)H)H& %L8r   r   )rI   rJ   )r"   r   s   ` r   r   9DownloadCallbackConnectionClassFactory.GetConnectionClassV  s     EX%H%H EN &%r   )r:   r   r   r<   r;   r   r   r   r   r   r   ?  s!     0!%
AJ&r   r   c                    ^ S nU R                   mSSS[        R                  S4U4S jjn[        R                  " X5      U l        X l         U $ )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
           	         U R                    V
s/ s H.  n
U
R                  X$5      (       d  M  U
R                  U5      U
4PM0     nn
U=(       a    [        U5      S   S   =(       d    Sn
U
(       a  U
R	                  XTXv5        U R                  XXVU5      u  pU
(       aD  U
R                  X5      (       a.  U
R	                  XTXv5        U R                  XUXg5      u  pSUl        UR                  S:X  a  U R                  X$X|U5       Hh  nUR	                  XTXv5        U R                  XUXg5      u  pUR                  S:w  d  M<  U R                   R                  U5        UR                  X5          O   U R                  (       d  US;   d  UR                  S:X  Ga  U R                  (       Ga  UR                  S;   Gaq  U(       GaR  SU;  a'  UR                  S	:w  a  [        R                  " S
X5      eSU;   a;  US   n[        U5      u  nnnnnUc"  [         R"                  R%                  X?5      US'   UR                  S:X  a:  US;   a4  US   US'   SU;  a  X<S'   [        R&                  " X|XR(                  U	5        SU;   a  US	 SU;   a  US	 SU;   a  U R*                  (       d  US	 SU;   ae  US   n[,        R.                  " U5      nSU;  a  UUS'   UnUR                  S;   a  SnSnU R	                  UUXgUS-
  UR0                  S9u  pUUl        X4$ [        R4                  " SX5      eUR                  S;   a2  US;   a,  SU;   a  X<S'   [        R&                  " X|XR(                  U	5        X4$ s  sn
f )zdDo the actual request using the connection object.
Also follow one level of redirects if necessary.
r   ri   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_challengerX   follow_all_redirectsfollow_redirectsrI   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   OverrideRequest0WrapDownloadHttpRequest.<locals>.OverrideRequest  s    ;?:M:M 2:M$d0 .tzz+&-:ME 2(VE]1%a(0DD
ll66,,T-46X 	x	&	&V'8"00F15@!"#44
W9-f7A"00F15@??c!



$
$]
3

 
 
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-9)*!!'Wjj"*,'( G++,(44(8#
+H==2L!51=l-.$O*, %od"&,,/)!^ $	 #/ #0X
 !-H  &&D! ! ??j(V-F ))5%
&g**&	( i2s
   M2M2r   Nc           	      4   > US:X  a	  T" XUX4S S9$ T" XUX4US9$ )Nr   r   r   )r   r   r   r   r   r   r   s         r   r   +WrapDownloadHttpRequest.<locals>.NewRequest  s=     #4")*.0 0 #4")*9; ;r   )r   rI   r   types
MethodType_request)download_httpr   r   r   s      @r   WrapDownloadHttpRequestr     sP    *Z~ &&,"t&<<!%
; !++OK-$	r   c                       \ rS rSrSrS rSrg)HttpWithNoRetriesi+  a*  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                     [        US5      (       a  UR                  c  UR                  5         UR                  X2XE5         UR'                  5       nSn	US:X  a  UR                  5         OUR)                  5       n	[        R*                  " U5      nUS:w  a  [        R,                  " X5      n	X4$ ! [        R
                   a    e [        R                   a4    UR                  5         [        R                  " SUR                  -  5      e[        R                  R                   a    UR                  5         e [        R                   aY  nSn[        US5      (       a  [        US5      S   nOUR                  nU[        R                  R                   :X  a  e  S nAGN_S nAf["        R$                   a    UR                  5         e f = f! [        R                  ["        R$                  4 a    UR                  5         e f = f)NsockUnable to find the server at %sr   rL   rD   r   )hasattrr  connectr   socketrG   gaierrorcloserI   ServerNotFoundErrorr   sslSSLErrorerrorgetattrerrnoECONNREFUSEDr   HTTPExceptionr   r   Response_decompressContent)
r"   r   r   r   r   r   eerrr   r   s
             r   r   HttpWithNoRetries._conn_request9  s   	v		499#4
ll66*A!!#h
 g	6	

--/""8,h	6	--h@G >> ?? 4
jjl(()J)-*3 4 4<<   
jjl<< c	F		a #gg	++	+ 
,$$ 
jjl
 LL+334 
jjls&   A B1 G 1BG
AF!!)G
6Hr   N)r-   r.   r/   r0   r1   r   r4   r   r   r   r   r   +  s    )r   r   c                   f   ^  \ rS rSrSrU 4S jr\S 5       r\R                  S 5       rS r	Sr
U =r$ )HttpWithDownloadStreamie  a  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                 p   > S U l         [        R                  " 5       U l        [        [
        U ]  " U0 UD6  g r&   )_streamlogging	getLogger_loggersuperr  r#   )r"   rL   kwdsr   s      r   r#   HttpWithDownloadStream.__init__r  s/    DL$$&DL	
 $0$?$?r   c                     U R                   $ r&   r  r!   s    r   streamHttpWithDownloadStream.streamw  s    <<r   c                     Xl         g r&   r   r*   s     r   r!  r"  {  s    Lr   c                     [        US5      (       a  UR                  c  UR                  5         UR                  X2XE5         UR'                  5       nSn	US:X  a)  UR                  5         [        R(                  " U5      nX4$ US:X  GaO  UR*                  ["        R,                  ["        R.                  4;   Ga   S n
[        US5      (       a  UR1                  S	5      n
UnSn UR3                  [4        5      nU(       aS  U R6                  c  [8        R:                  " S
5      e[<        R>                  " U R6                  U5        U[A        U5      -  nOOMr  U
bi  [C        U5      [C        U
5      :w  aQ  U RD                  RG                  [H        RJ                  SXU5        URL                  S		 [O        U5      URL                  S	'   [        R(                  " U5      nX4$ UR3                  5       n	[        R(                  " U5      n[        RP                  " X5      n	 X4$ ! [        R
                   a    e [        R                   a4    UR                  5         [        R                  " SUR                  -  5      e[        R                  R                   a    UR                  5         e [        R                   aY  nSn[        US5      (       a  [        US5      S   nOUR                  nU[        R                  R                   :X  a  e  S nAGNS nAf["        R$                   a    UR                  5         e f = f! [        R                  ["        R$                  4 a  nUR                  5         e S nAff = f)Nr  r  r   rL   rD   r   r   rb   rh   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  rG   r  r  rI   r  r   r	  r
  r  r  r  r  r   r  r   r  r   r   r   	getheaderr   r   r!  apitools_exceptionsInvalidUserInputErrorr   write_to_fdr[   longr  logr  DEBUGrb   r\   r  )r"   r   r   r   r   r   r  r  r   r   content_lengthhttp_stream
bytes_readnew_datas                 r   r   $HttpWithDownloadStream._conn_request  s   	v		499#4
ll66.4A!!#h
 g	6	

$$X.X W U?x;>>3>3N3N3P  P8U###--.>?.
 %%&:;({{"'==IK K!!$++x8#h-'J  &^ 44 ,,

mm 'F ll+,+.z?(,,'
($$X. 	 --/$$X.--h@W >> ?? 4
jjl(()J)-*3 4 4<<   
jjl<< c	F		a #gg	++	+ 
,$$  jjl	 LL+334 
jjls2   A H L6 BL36AL

)L36$M0M++M0)r  r  )r-   r.   r/   r0   r1   r#   r2   r!  r3   r   r4   __classcell__)r   s   @r   r  r  e  sF    
@
   
== P Pr   r  )/r1   
__future__r   r   r   r   r   r  r   r  r   rT   	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   rI   r   PY3rl   r)  ro   objectr   r6   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   