
    	]j{9                     p   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mZmZ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"  ejF                  e$      Z% G d d      Z& ed       G d de&e             Z' ed       G d de&e             Z(y)    N)Union)unquote)extract_message)settings)HttpRequestHttpResponseHttpResponseRedirectStreamingHttpResponse)extend_schema)Projectstatus)IsAuthenticated)Response)APIView)Task)get_storage_by_url)parse_rangec                   h    e Zd Zdededeeef   defdZ	dedeeef   dedefdZ
d Zd	 Zd
 Zd Zy)ResolveStorageUriAPIMixinrequestfileuriinstancereturnc                 R   t        |      j                  }|j                  |j                        st	        t
        j                        S 	 t        j                  |j                               j                         }t!        |t"              r|n|j$                  }|j&                  }t)        ||      }|s2t        j+                  d|        t	        t
        j,                        S t/        |d      s3t        j+                  d	| d
       t	        t
        j,                        S |j0                  }	|	r| j3                  |||      S | j5                  ||||      S # t        $ rB}t        j                  d| d| d|j                   d| d	       t        |      }Y d }~$d }~ww xY w)Nr   zFailed to decode base64  for  : z falling back to unquotezCould not find storage for URI presignzStorage z does not support presign URLs)type__name__has_permissionuserr   r   HTTP_403_FORBIDDENbase64urlsafe_b64decodeencodedecode	Exceptionloggerdebugidr   
isinstancer   projectget_all_import_storage_objectsr   errorHTTP_404_NOT_FOUNDhasattrr   redirect_to_presign_urlproxy_data_from_storage)
selfr   r   r   
model_nameexcr.   storage_objectsstorager   s
             L/root/env/lib/python3.12/site-packages/label_studio/io_storages/proxy_api.pyresolvez!ResolveStorageUriAPIMixin.resolve   sk   (^,,
&&w||46#<#<==	'..w~~/?@GGIG )7;(AQAQ!@@$Wo>LL:7)DE6#<#<==w	*LL8G9,JKL6#<#<==// //:NN//'7SS9  	'LL*7)5Ahkk]RTUXTYYqr g&G		's   1E 	F&$7F!!F&r6   c                 \   	 |j                  |      }||j                  d      t        t        j                        S |d   }d}|j                  d	      r|j                  d	      d
z  }t        |t        j                        }d| |j                  d<   |j                  j                  dd       |j                  j                  dd       |S # t        $ rO}t        j                  d| d| d|j                   d|        t        t        j                        cY d}~S d}~ww xY w)z?Generate and redirect to a presigned URL for the given file URIzFailed to resolve storage uri r   r   r   r   Nurlr   presign_ttl<   )redirect_tor   zno-store, max-age=Cache-Controlbaggagezsentry-trace)resolve_storage_urir)   r*   r0   r,   r   r   r1   getr	   HTTP_303_SEE_OTHERheaderspop)	r5   r   r   r6   resolvedr7   r=   max_ageresponses	            r:   r3   z1ResolveStorageUriAPIMixin.redirect_to_presign_urlB   s   	>33G<H
 x||E2:6#<#<==uo<<&ll=1B6G (C@Y@YZ.@	,J)Y-^T2%  	>LL9'%
|STU]U`U`Taacdgchij6#<#<==	>s   C 	D+AD& D+&D+c              #     K   t         j                  }t         j                  }t        j                         }||z   }d}d}	 |j                  |      D ]S  }t        j                         }	|	|k\  r!t        j                  d| d| d| d        n|dz  }|t        |      z  }| U t        j                         |z
  }	 |j                          t        j                  d|dd| d| d       y# t        $ r$}
t        j                  d|
 d	
       Y d}
~
qd}
~
ww xY w# t        $ r"}
t        j                  d|
        Y d}
~
wd}
~
ww xY w# t        j                         |z
  }	 |j                          n.# t        $ r"}
t        j                  d|
        Y d}
~
nd}
~
ww xY wt        j                  d|dd| d| d       w xY ww)zM
        Generator that stops yielding chunks after timeout seconds.
        r   )
chunk_sizezTime limit (zs) reached after yielding z	 chunks (z bytes)   z%Error during time-limited streaming: Texc_infoNzCouldn't close stream: z!Stream processing finished after z.2fzs, yielded )r   RESOLVER_PROXY_BUFFER_SIZERESOLVER_PROXY_TIMEOUTtime	monotoniciter_chunksr*   warninglenr)   r0   closer+   )r5   stream_bodyrL   timeout
start_timedeadlinechunks_yieldedtotal_byteschunkcurrent_timeeelapseds               r:   time_limited_chunkerz.ResolveStorageUriAPIMixin.time_limited_chunkerZ   s     88
11^^%
'	$00J0G #~~/8+NN&wi/I.IYYbcnboovw  !#s5z)" nn&3G<!!# LL3GC=NK[[depdqqxy  	ULL@DtLTT	U  <6qc:;;< nn&3G<!!# <6qc:;;<LL3GC=NK[[depdqqxys   >GA(C2 )GD" !G2	D;DE DE "	E+EGEGG	)E:9G	:	F%F G	 F%%$G		Gc                    t         j                  }d}|j                  j                  d      x}r"t	        |      \  }}|d}t
        j                  d| d|        	 |dk(  r|dk(  s|dk(  rnp|dkD  r|dk(  s|dk(  r||z   }n[|dk\  r|dkD  r|||z   k\  r||z   n|}nA|dk  r t
        j                  d|        d}||z   }nt
        j                  d|        d}d}d	| d
| }t
        j                  dt        |      dz  dz   d       t
        j                  dt        |xs d      dz  dz   d       t
        j                  d|        |S )a  
        Process and override Range header to limit stream size.
        This function does a trick: limit stream chunk sizes to MAX_RANGE,
        this way we free sync LSE workers for hanging too long,
        because the connection will be closed after the MAX_RANGE chunk is over.

        This function handles several range request formats:
        1 'bytes=0-' and 'bytes=0-0': Passes through unchanged (header probes)
        2 'bytes=123456-' and 'bytes=123456-0': Limits to MAX_RANGE bytes
        3 'bytes=123456-789012': Limits the range if it exceeds MAX_RANGE
        4 'bytes=-1024': Handles negative start (not supported)

        Returns:
            str: Modified range header in format "bytes=start-end" or None if no range header
        NRange z#>> Range read from request: start: z, end: r   z+Start range is negative and not supported: zRange is not covered by logic: zbytes=-z>> stream > start: i   z MBz>> stream > end: z>> stream > range_header: )	r   RESOLVER_PROXY_MAX_RANGE_SIZErF   rD   r   r*   r+   rU   int)r5   r   max_range_sizerange_headerrngstartends          r:   override_range_headerz/ResolveStorageUriAPIMixin.override_range_header   s     "??//%%g..3.$S)JE3{LL>ugWSERS
 zsbyC1Hr	SAXn,!a03u~7M0Men,SV!LSERSn,!@FG#E7!C51LLL.s5z$t/C.DCHILL,S]4-?-D,ESIJLL5l^DE    c                    |j                  d      rt        |d         |j                  d<   |j                  d      r|d   |j                  d<   |j                  d      rH|d   }t        |d      r|j	                  d      |j                  d<   nt        |      |j                  d<   d	|j                  d
<   t
        j                  }d| d|j                  d<   |j                  }t        |j                  |            }|j                   | }	|	 |j                  d<   |j                  d      r)|j                  dxx   |d   j                  d      z  cc<   d|j                  d    d|j                  d<   |S )z2Prepare and set headers for the streaming responseContentLengthzContent-LengthContentRangezContent-RangeLastModifiedstrftimez%a, %d %b %Y %H:%M:%S GMTzLast-ModifiedbyteszAccept-Rangeszprivate, max-age=z, must-revalidaterA   ETag")rD   strrF   r2   rt   r   RESOLVER_PROXY_CACHE_TIMEOUTr#   rh   r"   r,   strip)
r5   rJ   metadatar   r.   last_modrI   r#   
has_accessuser_status_tags
             r:   prepare_headersz)ResolveStorageUriAPIMixin.prepare_headers   sv    <<(14Xo5N1OH-.<<'080HH_-<<'/Hx,4<4E4EFa4b  147M  1 -4) 77.?yHY,Z) ||//56
!WWIj\2&5%6 <<V$(8(>(>s(CC$%&x'7'7'?&@#B ro   c                    	 | j                  |      }|j                  ||      \  }}}|6t        j                  d|        t	        dddt
        j                        S |rd|v rt        j                  |      \  }	}
|	r|	}| j                  |      }|d	   }t        ||xs d
|      }| j                  ||||      }t        j                  r_d|j                  vrQ|j                  j                  d      |j                  j                  d      k(  rt!        t
        j"                        S |S # t$        $ rK}t        j                  d| d       t	        dt'        |      dt
        j                        cY d}~S d}~ww xY w)a:  
        Proxy the data using iter_chunks directly from storage streaming object.

        This implementation forwards Range headers to cloud storages and streams the response
        directly using StreamingHttpResponse. It avoids any intermediate buffering
        but doesn't support backward seeking.
        )rj   Nz)Failed to get direct stream from storage z)Storage stream failed while proxying datazStream is None)r0   detailr   zoctet-stream
StatusCodezapplication/octet-stream)content_typer   rd   zIf-None-Matchrv   z$Error in direct proxy from storage: TrN   )rn   get_bytes_streamr*   r0   r   r   HTTP_424_FAILED_DEPENDENCY	mimetypes
guess_typerb   r
   r   r    RESOLVER_PROXY_ENABLE_ETAG_CACHErF   rD   r   HTTP_304_NOT_MODIFIEDr)   r   )r5   r   urir.   r9   rj   streamr   r{   guessed_type_time_limited_streamstatus_coderJ   r`   s                  r:   r4   z1ResolveStorageUriAPIMixin.proxy_data_from_storage   s   -	55g>L .5-E-EcXd-E-e*FL(~H	RSIUef!<<   >\#A"+"6"6s";a#/L #'";";F"C #<0K,#,2\B\epH
 ++HhQH 88WGOO=[??&&78;K;K;O;OPV;WW'v/K/KLLO 	LL?sCdLSEQ`abQcd88 	s,   AD1 "CD1 /D1 1	F:A F :F FN)r!   
__module____qualname__r   rx   r   r   r   r   r;   r3   rb   rn   r   r4    ro   r:   r   r      sw    &T{ &TS &TE$PW-DX &T]e &TPs eD'M>R `c hp 0$L=~#J5ro   r   T)excludec                   "    e Zd ZdZdgZefZd Zy)TaskResolveStorageUrizA file proxy to presign storage urls at the task level.

    If the storage has presign=False, it will proxy the data through Label Studio
    instead of redirecting to presigned URLs.
    rD   c                 |   | j                   }|j                  d      }|j                  j                  d      }||t        t        j
                        S 	 t        j                  j                  |      }| j                  |||      S # t        j                  $ r t        t        j                        cY S w xY w)LGet the presigned url for a given fileuri or proxy data through Label Studiotask_idr   r   pk)r   rD   GETr   r   HTTP_400_BAD_REQUESTr   objectsDoesNotExistr1   r;   )r5   r   argskwargsr   r   tasks          r:   rD   zTaskResolveStorageUri.get'  s    ,,**Y'++//),?go6#>#>??	><<##w#/D ||GWd33    	>6#<#<==	>    B -B;:B;Nr!   r   r   __doc__http_method_namesr   permission_classesrD   r   ro   r:   r   r     s     )+4ro   r   c                   "    e Zd ZdZdgZefZd Zy)ProjectResolveStorageUrizA file proxy to presign storage urls at the project level.

    If the storage has presign=False, it will proxy the data through Label Studio
    instead of redirecting to presigned URLs.
    rD   c                 |   | j                   }|j                  d      }|j                  j                  d      }||t        t        j
                        S 	 t        j                  j                  |      }| j                  |||      S # t        j                  $ r t        t        j                        cY S w xY w)r   
project_idr   r   r   )r   rD   r   r   r   r   r   r   r   r1   r;   )r5   r   r   r   r   r   r.   s          r:   rD   zProjectResolveStorageUri.getC  s    ,,ZZ-
++//),?j06#>#>??	>oo))Z)8G ||GWg66 ## 	>6#<#<==	>r   Nr   r   ro   r:   r   r   8  s     )+7ro   r   ))r%   loggingr   rR   typingr   urllib.parser   core.utils.exceptionsr   django.confr   django.httpr   r   r	   r
   drf_spectacular.utilsr   projects.modelsr   rest_frameworkr   rest_framework.permissionsr   rest_framework.responser   rest_framework.viewsr   tasks.modelsr   "label_studio.io_storages.functionsr   label_studio.io_storages.utilsr   	getLoggerr!   r*   r   r   r   r   ro   r:   <module>r      s           1   ^ ^ / # ! 6 , (  A 6			8	$@ @F t45w 4 46 t78' 7 7ro   