
    G                     P   d 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	Z	ddl
mZmZ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mZmZ dd
lmZmZm Z m!Z!  ejD                  e#      Z$dZ%dZ&dZ'dZ(d0dee)   de*fdZ+de*fdZ,defdZ-d Z.d Z/d Z0d Z1d Z2d Z3d Z4d Z5 G d de6      Z7d Z8 G d d e6      Z9 G d! d"e6      Z: G d# d$e6      Z; G d% d&e6      Z<d' Z= G d( d)e      Z> G d* d+e      Z? G d, d-e      Z@ej                  fd.ZBe#d/k(  r eB        yy)1zDHTTP server for dulwich that implements the git smart HTTP protocol.    )BytesION)ListTupleOptional)WSGIRequestHandlerServerHandler
WSGIServermake_server)parse_qs)	log_utils)ReceivableProtocol)BaseRepoNotGitRepositoryRepo)DictBackendDEFAULT_HANDLERSgenerate_info_refsgenerate_objects_info_packsz200 OKz404 Not Foundz403 Forbiddenz500 Internal Server Error	timestampreturnc                     g d}g d}| t        j                          } t        j                  |       d d \  }}}}}}}	d||	   |||   ||||fz  S )N)MonTueWedThuFriSatSun)NJanFebMarAprMayJunJulAugSepOctNovDec   z#%s, %02d %3s %4d %02d:%02d:%02d GMD)timegmtime)
r   weekdaysmonthsyearmonthdayhhmmsswds
             lib/third_party/dulwich/web.pydate_time_stringr8   F   sw     AHF IIK	'+{{9'=bq'A$D%b"b"0u


4      c                 `    d| j                   d| j                          j                  d      z   S )a  Extract the URL prefix from a regex match.

    Args:
      mat: A regex match object.
    Returns: The URL prefix, defined as the text before the match in the
        original string. Normalized to start with one leading slash and end
        with zero.
    /N)stringstartstrip)mats    r7   
url_prefixr@   k   s+     Mciik*00555r9   c                 6    | j                  t        |            S )z>Get a Repo instance for the given backend and URL regex match.)open_repositoryr@   )backendr?   s     r7   get_reporD   w   s    "":c?33r9   c              #   *  K   || j                  d       y	 | j                  t        |       	 |j                  d      }|sn| 	 |j                          y# t        $ r | j                  d       Y /w xY w# |j                          w xY ww)a!  Send a file-like object to the request output.

    Args:
      req: The HTTPGitRequest object to send output to.
      f: An open file-like object to send; will be closed.
      content_type: The MIME type for the file.
    Returns: Iterator over the contents of the file, as chunks.
    NzFile not foundi (  zError reading file)	not_foundrespondHTTP_OKreadIOErrorerrorclose)reqfcontent_typedatas       r7   	send_filerQ   |   s      	ymm,--
G\*66%=DJ	  
 	
	  .ii,--. 	
	s:   B0A 
A> BA;8A> :A;;A> >BBc                 V    | j                  dt        j                  j                        S )Nr;   )replaceospathsep)urls    r7   _url_to_pathrX      s    ;;sBGGKK((r9   c                     | j                          t        |j                               }t        j	                  d|       t        | t        ||      j                  |      d      S )NzSending plain text file %s
text/plain)nocacherX   grouploggerinforQ   rD   get_named_filerM   rC   r?   rU   s       r7   get_text_filera      sK    KKM		$D
KK,d3S(7C0??E|TTr9   c              #     K   |j                  d      |j                  d      z   j                  d      }t        j                  d|       t	        ||      j
                  }|j                  |      s| j                  d       y 	 ||   j                         }| j                          | j                  t        d       | y # t        $ r | j                  d       Y y w xY ww)N      asciizSending loose object %szObject not foundzError reading objectzapplication/x-git-loose-object)r\   encoder]   r^   rD   object_storecontains_looserF   as_legacy_objectrJ   rK   cache_foreverrG   rH   )rM   rC   r?   sharg   rP   s         r7   get_loose_objectrl      s     99Q<#))A,&
.
.w
7C
KK)3/GS)66L&&s+mm.//C 113 KK9:
J  ii.//s*   BC'C +C'C$!C'#C$$C'c                     | j                          t        |j                               }t        j	                  d|       t        | t        ||      j                  |      d      S )NSending pack file %sz application/x-git-packed-objectsrj   rX   r\   r]   r^   rQ   rD   r_   r`   s       r7   get_pack_filerp      sU    		$D
KK&-#--d3* r9   c                     | j                          t        |j                               }t        j	                  d|       t        | t        ||      j                  |      d      S )Nrn   z$application/x-git-packed-objects-tocro   r`   s       r7   get_idx_filerr      sU    		$D
KK&-#--d3. r9   c              #     K   t        | j                  d         }|j                  dd g      d   }	 t        ||      }|r| j                  s| j                  j                  |j                  d      d       }|| j                  d       y | j                          | j                  t        d|z        }t        t               j                   |      }	 ||t#        |      g|	| d      }
|
j$                  j'                  d	|j                  d      z   d
z          |
j$                  j'                  d        |
j)                          y | j                          | j                  t        d       t*        j-                  d       t/        |      D ]  }|  y # t        $ r&}| j                  t        |             Y d }~y d }~ww xY ww)NQUERY_STRINGservicer   re   Unsupported servicezapplication/x-%s-advertisementT)stateless_rpcadvertise_refss
   # service=   
rZ   zEmulating dumb info/refs)r   environgetrD   r   rF   strdumbhandlersrf   	forbiddenr[   rG   rH   r   r   rI   r@   protowrite_pkt_linehandler]   r^   r   )rM   rC   r?   paramsru   repoehandler_clswriter   handlertexts               r7   get_info_refsr      sy    ckk.12FjjTF+A.G% sxxll&&w~~g'>E-- 566G%E%OP"79>>59_
 	$$]W^^G5L%Lu%TU$$T* 	G\*./&t,DJ -7  mmCF##s.   /G
F EG
	G!G=G
GG
c                     | j                          | j                  t        d       t        j	                  d       t        t        ||            S )NrZ   zEmulating dumb info/packs)r[   rG   rH   r]   r^   r   rD   )rM   rC   r?   s      r7   get_info_packsr      s8    KKMKK&
KK+,&x'=>>r9   c                       e Zd ZdZd ZddZy)_LengthLimitedFilea  Wrapper class to limit the length of reads from a file-like object.

    This is used to ensure EOF is read from the wsgi.input object once
    Content-Length bytes are read. This behavior is required by the WSGI spec
    but not implemented in wsgiref as of 2.5.
    c                      || _         || _        y N)_input_bytes_avail)selfinput	max_bytess      r7   __init__z_LengthLimitedFile.__init__   s    %r9   c                     | j                   dk  ry|dk(  s|| j                   kD  r| j                   }| xj                   |z  c_         | j                  j                  |      S )Nr   r9   )r   r   rI   )r   sizes     r7   rI   z_LengthLimitedFile.read   sX    !2: 1 11$$DT!{{%%r9   N)r   )__name__
__module____qualname____doc__r   rI    r9   r7   r   r      s    &&r9   r   c              #   Z  K   |j                         j                  d      }t        j                  d|       | j                  j                  |j                  d      d       }|| j                  d       y 	 t        ||       | j                          | j                  t        d|z        }t        | j                   d   j"                  |      } ||t%        |      g||       }|j'                          y # t        $ r&}| j                  t        |             Y d }~y d }~ww xY ww)Nr;   zHandling service request for %sre   rv   zapplication/x-%s-result
wsgi.input)rw   )r\   lstripr]   r^   r~   r{   rf   r   rD   r   rF   r|   r[   rG   rH   r   rz   rI   r@   r   )	rM   rC   r?   ru   r   r   r   r   r   s	            r7   handle_service_requestr   	  s     iik  %G
KK17;,,""7>>'#:DAKmm122# KKMKK!:W!DEEs{{<8==uEE 'JsO#4e3OGNN  mmCF##s1   A7D+:C9 A3D+9	D(D#D+#D((D+c                       e Zd ZdZddefdZd Zeddfdede	e   de	e
eeef         fd	Zd
edefdZd
edefdZd
edefdZddZddZy)HTTPGitRequestzzClass encapsulating the state of a single git HTTP request.

    :ivar environ: the WSGI environment for the request.
    Nr}   c                 X    || _         || _        || _        || _        g | _        g | _        y r   )rz   r}   r~   _start_response_cache_headers_headers)r   rz   start_responser}   r~   s        r7   r   zHTTPGitRequest.__init__$  s.    	 - r9   c                 >    | j                   j                  ||f       y)zAdd a header to the response.N)r   append)r   namevalues      r7   
add_headerzHTTPGitRequest.add_header,  s    dE]+r9   statusrO   headersc                     |r| j                   j                  |       |r| j                   j                  d|f       | j                   j                  | j                         | j	                  || j                         S )z9Begin a response with the given status and other headers.zContent-Type)r   extendr   r   r   )r   r   rO   r   s       r7   rG   zHTTPGitRequest.respond0  sb     MM  )MM  .,!?@T001##FDMM::r9   messager   c                     g | _         t        j                  d|       | j                  t        d       |j                  d      S )z;Begin a HTTP 404 response and return the text of a message.zNot found: %srZ   re   )r   r]   r^   rG   HTTP_NOT_FOUNDrf   r   r   s     r7   rF   zHTTPGitRequest.not_found?  5     OW-^\2~~g&&r9   c                     g | _         t        j                  d|       | j                  t        d       |j                  d      S )z;Begin a HTTP 403 response and return the text of a message.zForbidden: %srZ   re   )r   r]   r^   rG   HTTP_FORBIDDENrf   r   s     r7   r   zHTTPGitRequest.forbiddenF  r   r9   c                     g | _         t        j                  d|       | j                  t        d       |j                  d      S )z;Begin a HTTP 500 response and return the text of a message.z	Error: %srZ   re   )r   r]   rK   rG   
HTTP_ERRORrf   r   s     r7   rK   zHTTPGitRequest.errorM  s5     ['*Z.~~g&&r9   c                     g d| _         y)z2Set the response to never be cached by the client.))ExpireszFri, 01 Jan 1980 00:00:00 GMT)Pragmazno-cache)Cache-Controlz$no-cache, max-age=0, must-revalidateN)r   )r   s    r7   r[   zHTTPGitRequest.nocacheT  s    
r9   c                 r    t        j                          }dt        |      fdt        |dz         fdg| _        y)z4Set the response to be cached forever by the client.Dater   i3)r   zpublic, max-age=31536000N)r,   r8   r   )r   nows     r7   rj   zHTTPGitRequest.cache_forever\  s:    iik%c*+(x899
r9   )FN)r   N)r   r   r   r   boolr   r   rH   r|   r   r   r   rG   bytesrF   r   rK   r[   rj   r   r9   r7   r   r     s    
d , &*37	;; sm; $uS#X/0	;' ' '' ' ''S 'U '

r9   r   c                      e Zd ZdZd ej
                  d      fed ej
                  d      fed ej
                  d      fed ej
                  d      fed ej
                  d      fed ej
                  d      fe	d ej
                  d	      fe
d ej
                  d
      fed ej
                  d      fed ej
                  d      fei
ZddefdZd Zy)HTTPGitApplicationz}Class encapsulating the state of a git WSGI application.

    :ivar backend: the Backend object backing this application
    GETz/HEAD$z/info/refs$z/objects/info/alternates$z/objects/info/http-alternates$z/objects/info/packs$z&/objects/([0-9a-f]{2})/([0-9a-f]{38})$z(/objects/pack/pack-([0-9a-f]{40})\.pack$z'/objects/pack/pack-([0-9a-f]{40})\.idx$POSTz/git-upload-pack$z/git-receive-pack$Nr}   c                     || _         || _        t        t              | _        || _        || j                  j                  |       y y r   )rC   r}   dictr   r~   fallback_appupdate)r   rC   r}   r~   r   s        r7   r   zHTTPGitApplication.__init__  sB    	-.(MM  *  r9   c                    |d   }|d   }t        ||| j                  | j                        }d }| j                  j	                         D ]1  \  }}||k7  r|j                  |      }	|	s | j                  ||f   } n |0| j                  | j                  ||      S |j                  d      gS  ||| j                  	      S )N	PATH_INFOREQUEST_METHOD)r}   r~   z#Sorry, that method is not supported)	r   r}   r~   serviceskeyssearchr   rF   rC   )
r   rz   r   rU   methodrM   r   smethodspathr?   s
             r7   __call__zHTTPGitApplication.__call__  s    {#)*^$))dmm
 "mm002NGU& ,,t$C--7 3 ?  ,((.AA&KLMMsDLL#..r9   )FNN)r   r   r   r   recompilera   r   r   rl   rp   rr   r   r   r   r   r   r   r9   r7   r   r   f  s    



8$%}	


=)*M	


678-	


;<=}	


123^BJJ?@	
 BJJBC	
 BJJAB	
 	/013I	0124J'H,+d +/r9   r   c                       e Zd ZdZd Zd Zy)GunzipFilterzkWSGI middleware that unzips gzip-encoded requests before
    passing on to the underlying application.
    c                     || _         y r   appr   applications     r7   r   zGunzipFilter.__init__  	    r9   c                 ~   |j                  dd      dk(  r>	 |d   j                          |d   }t        j                  d |d      |d<   |d= d	|v r|d	= | j                  ||      S # t        t        t        f$ rB t        j                  d      }t        j                  |d   |       |j                  d       Y w xY w)
NHTTP_CONTENT_ENCODING gzipr   i   r   r)filenamefileobjmodeCONTENT_LENGTH)r{   tellAttributeErrorrJ   NotImplementedErrortempfileSpooledTemporaryFileshutilcopyfileobjseekr   GzipFiler   )r   rz   r   
wsgi_inputs       r7   r   zGunzipFilter.__call__  s    ;;.3v=
#%**,$\2
 %)MMz%GL! /07*,-xx00! #G-@A #
 &::;KL
""7<#8*E"#s   A& &AB<;B<Nr   r   r   r   r   r   r   r9   r7   r   r     s    1r9   r   c                       e Zd ZdZd Zd Zy)LimitedInputFilterzgWSGI middleware that limits the input length of a request to that
    specified in Content-Length.
    c                     || _         y r   r   r   s     r7   r   zLimitedInputFilter.__init__  r   r9   c                     |j                  dd      }|rt        |d   t        |            |d<   | j                  ||      S )Nr   r   r   )r{   r   intr   )r   rz   r   content_lengths       r7   r   zLimitedInputFilter.__call__  sI    
 !%5r:$6%s>':%GL! xx00r9   Nr   r   r9   r7   r   r     s    
1r9   r   c                  D    t        | i |}t        t        |            }|S )zpFactory function to create an instance of HTTPGitApplication,
    correctly wrapped with needed middleware.
    )r   r   r   )argskwargsr   wrapped_apps       r7   make_wsgi_chainr     s(     d
-f
-C$\#%67Kr9   c                   "    e Zd ZdZd Zd Zd Zy)ServerHandlerLoggerz@ServerHandler that uses dulwich's logger for logging exceptions.c                 2    t         j                  d|       y Nz/Exception happened during processing of request)exc_infor]   	exceptionr   r  s     r7   log_exceptionz!ServerHandlerLogger.log_exception      = 	 	
r9   c                 0    t        j                  |g|  y r   r]   r^   r   formatr   s      r7   log_messagezServerHandlerLogger.log_message      F"T"r9   c                 (    t        j                  |  y r   r]   rK   r   r   s     r7   	log_errorzServerHandlerLogger.log_error      dr9   N)r   r   r   r   r  r  r  r   r9   r7   r  r    s    J
#r9   r  c                   (    e Zd ZdZd Zd Zd Zd Zy)WSGIRequestHandlerLoggerzEWSGIRequestHandler that uses dulwich's logger for logging exceptions.c                 2    t         j                  d|       y r  r  r  s     r7   r  z&WSGIRequestHandlerLogger.log_exception  r	  r9   c                 0    t        j                  |g|  y r   r  r  s      r7   r  z$WSGIRequestHandlerLogger.log_message  r  r9   c                 (    t        j                  |  y r   r  r  s     r7   r  z"WSGIRequestHandlerLogger.log_error  r  r9   c                 @   | j                   j                         | _        | j                         syt	        | j                   | j
                  | j                         | j                               }| |_        |j                  | j                  j                                y)zHandle a single HTTP requestN)rfilereadlineraw_requestlineparse_requestr  wfile
get_stderrget_environrequest_handlerrunserverget_app)r   r   s     r7   r   zWSGIRequestHandlerLogger.handle   sv      $zz224!!#%JJ

DOO$5t7G7G7I
 #'DKK'')*r9   N)r   r   r   r   r  r  r  r   r   r9   r7   r  r    s    O
#+r9   r  c                       e Zd Zd Zy)WSGIServerLoggerc                 F    t         j                  dt        |      z         y)zHandle an error. z7Exception happened during processing of request from %sN)r]   r  r|   )r   requestclient_addresss      r7   handle_errorzWSGIServerLogger.handle_error  s     E.!"	
r9   N)r   r   r   r+  r   r9   r7   r'  r'    s    
r9   r'  c                 >   ddl }|j                         }|j                  ddddd       |j                  d	d
dt        dd       |j	                  |       \  }}t        |      dkD  r|d   }nt        j                         }t        j                          t        dt        |      i      }t        |      }t        |j                  |j                  |t         t"              }t$        j'                  d|j                  |j                         |j)                          y)z,Entry point for starting an HTTP git server.r   Nz-lz--listen_addresslisten_address	localhostzBinding IP address.)destdefaulthelpz-pz--portporti@  zPort to listen on.)r/  typer0  r1  rc   r;   )handler_classserver_classz'Listening for HTTP connections on %s:%d)optparseOptionParser
add_optionr   
parse_argslenrT   getcwdr   default_logging_configr   r   r   r
   r-  r2  r  r'  r]   r^   serve_forever)	argvr6  parseroptionsr   gitdirrC   r   r$  s	            r7   mainrB    s   ""$F
"   !   %%d+MGT
4y1}a$$&3V-.G
'
"C.%F KK1
 r9   __main__r   )Cr   ior   r   r   r   rT   r   sysr,   typingr   r   r   wsgiref.simple_serverr   r   r	   r
   urllib.parser   dulwichr   dulwich.protocolr   dulwich.repor   r   r   dulwich.serverr   r   r   r   	getLoggerr   r]   rH   r   r   r   floatr|   r8   r@   rD   rQ   rX   ra   rl   rp   rr   r   r   objectr   r   r   r   r   r   r   r  r  r'  r>  rB  r   r9   r7   <module>rP     sm  , K     	 	 
  ( (  "  
  
		X	&   (
" "3 "J	6s 	64h 4
2)U"!H?& &.*E
V E
P:/ :/z16 1@1 1*-  +1 +:
z 
 hh *Z zF r9   