a ~_vF@sdZddlmZddlZddlZddlZddlZddlZddlZddl Z ddl m Z m Z m Z ddlmZmZmZmZddlmZddlmZddlmZdd lmZmZmZdd lmZmZm Z m!Z!e"e#Z$d Z%d Z&d Z'dZ(d>e e)e*dddZ+e*dddZ,edddZ-ddZ.ddZ/ddZ0ddZ1dd Z2d!d"Z3d#d$Z4d%d&Z5Gd'd(d(e6Z7d)d*Z8Gd+d,d,e6Z9Gd-d.d.e6Z:Gd/d0d0e6Z;Gd1d2d2e6ZGd7d8d8eZ?Gd9d:d:eZ@ejAfd;d<ZBe#d=kreBdS)?zDHTTP server for dulwich that implements the git smart HTTP protocol.)BytesION)ListTupleOptional)WSGIRequestHandler ServerHandler WSGIServer make_server)parse_qs) log_utils)ReceivableProtocol)BaseRepoNotGitRepositoryRepo) DictBackendDEFAULT_HANDLERSgenerate_info_refsgenerate_objects_info_packsz200 OKz 404 Not Foundz 403 Forbiddenz500 Internal Server Error) timestampreturnc Cs^gd}gd}|dur t}t|dd\}}}}}}} d|| |||||||fS)N)ZMonZTueZWedZThuZFriZSatZSun) NZJanZFebZMarZAprZMayZJunZJulZAugZSepZOctZNovZDecz#%s, %02d %3s %4d %02d:%02d:%02d GMD)timegmtime) rZweekdaysZmonthsZyearZmonthZdayZhhZmmZssZwdr-/usr/lib/python3/dist-packages/dulwich/web.pydate_time_stringFs rrcCsd|jd|dS)aExtract 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)stringstartstrip)matrrr url_prefixXs r"cCs|t|S)z>Get a Repo instance for the given backend and URL regex match.)Zopen_repositoryr")backendr!rrrget_repodsr$ccs||dur|dVdSzTz(|t||d}|s8q@|Vq(Wnty`|dVYn0W|n |0dS)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. NzFile not foundi(zError reading file) not_foundrespondHTTP_OKreadIOErrorerrorclose)reqf content_typedatarrr send_fileis      r0cCs|dtjjS)Nr)replaceospathsep)Zurlrrr _url_to_pathsr5cCs8|t|}td|t|t|||dS)NzSending plain text file %s text/plain)nocacher5grouploggerinfor0r$get_named_filer,r#r!r3rrr get_text_files   r=ccs|d|dd}td|t||j}||sL|dVdSz||}Wn t y|| dVYdS0| | t d|VdS)NasciizSending loose object %szObject not foundzError reading objectzapplication/x-git-loose-object)r8encoder9r:r$ object_storeZcontains_looser%Zas_legacy_objectr)r* cache_foreverr&r')r,r#r!ZsharBr/rrrget_loose_objects       rDcCs8|t|}td|t|t|||dS)NSending pack file %sz application/x-git-packed-objectsrCr5r8r9r:r0r$r;r<rrr get_pack_files   rGcCs8|t|}td|t|t|||dS)NrEz$application/x-git-packed-objects-tocrFr<rrr get_idx_files   rHc csFt|jd}|ddgd}zt||}Wn6tyd}z|t|VWYd}~dSd}~00|r|js|j| dd}|dur| dVdS| | t d|}ttj|} ||t|g| |dd} | jd | dd | jd| n4| | t d td t|D] } | Vq4dS) NZ QUERY_STRINGservicerr@Unsupported servicezapplication/x-%s-advertisementT) stateless_rpcZadvertise_refss # service= r6zEmulating dumb info/refs)r environgetr$rr%strdumbhandlersrA forbiddenr7r&r'r rr(r"protoZwrite_pkt_linehandler9r:r) r,r#r!paramsrIZrepoe handler_clswriterShandlertextrrr get_info_refss<      r[cCs,||tdtdtt||S)Nr6zEmulating dumb info/packs)r7r&r'r9r:rr$)r,r#r!rrrget_info_packss  r\c@s"eZdZdZddZdddZdS) _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. cCs||_||_dSN)_input _bytes_avail)selfinputZ max_bytesrrr__init__sz_LengthLimitedFile.__init__cCs@|jdkrdS|dks ||jkr&|j}|j|8_|j|S)Nrrd)r`r_r()rasizerrrr(s  z_LengthLimitedFile.readN)rd)__name__ __module__ __qualname____doc__rcr(rrrrr]sr]c cs|d}td||j|dd}|durF|dVdSzt||Wn6t y}z| t |VWYd}~dSd}~00| | td|}t|jdj|}||t|g||d}|dS)NrzHandling service request for %sr@rJzapplication/x-%s-result wsgi.input)rK)r8lstripr9r:rQrNrArRr$rr%rOr7r&r'r rMr(r"rT) r,r#r!rIrWrVrXrSrYrrrhandle_service_requests   rmc@seZdZdZdedddZddZeddfee ee e e eefd d d Z ee d d dZee d ddZee d ddZddddZddddZdS)HTTPGitRequestzzClass encapsulating the state of a single git HTTP request. :ivar environ: the WSGI environment for the request. FNrPcCs(||_||_||_||_g|_g|_dSr^)rMrPrQ_start_response_cache_headers_headers)rarMstart_responserPrQrrrrc s zHTTPGitRequest.__init__cCs|j||fdS)zAdd a header to the response.N)rrappend)ranamevaluerrr add_headerszHTTPGitRequest.add_header)statusr.headerscCs@|r|j||r$|jd|f|j|j|||jS)z9Begin a response with the given status and other headers.z Content-Type)rrextendrtrqrp)rarxr.ryrrrr&s  zHTTPGitRequest.respond)messagercCs(g|_td||td|dS)z;Begin a HTTP 404 response and return the text of a message.z Not found: %sr6r@)rqr9r:r&HTTP_NOT_FOUNDrArar{rrrr%#s  zHTTPGitRequest.not_foundcCs(g|_td||td|dS)z;Begin a HTTP 403 response and return the text of a message.z Forbidden: %sr6r@)rqr9r:r&HTTP_FORBIDDENrAr}rrrrR*s  zHTTPGitRequest.forbiddencCs(g|_td||td|dS)z;Begin a HTTP 500 response and return the text of a message.z Error: %sr6r@)rqr9r*r& HTTP_ERRORrAr}rrrr*1s  zHTTPGitRequest.errorrcCsgd|_dS)z2Set the response to never be cached by the client.))ExpireszFri, 01 Jan 1980 00:00:00 GMT)ZPragmazno-cache) Cache-Controlz$no-cache, max-age=0, must-revalidateN)rq)rarrrr78szHTTPGitRequest.nocachecCs,t}dt|fdt|dfdg|_dS)z4Set the response to be cached forever by the client.ZDateri3)rzpublic, max-age=31536000N)rrrq)raZnowrrrrC@s  zHTTPGitRequest.cache_forever)FN)rgrhrirjboolrcrwr'rOrrrr&bytesr%rRr*r7rCrrrrrns&  rnc@seZdZdZdedfededfededfededfededfededfe ded fe ded fe d ed fe d ed fe i Z dedddZddZdS)HTTPGitApplicationz}Class encapsulating the state of a git WSGI application. :ivar backend: the Backend object backing this application ZGETz/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$ZPOSTz/git-upload-pack$z/git-receive-pack$FNrocCs4||_||_tt|_||_|dur0|j|dSr^)r#rPdictrrQ fallback_appupdate)rar#rPrQrrrrrcas  zHTTPGitApplication.__init__c Cs|d}|d}t|||j|jd}d}|jD]2\}}||krDq2||} | r2|j||f}qfq2|dur|jdur|||S|dgS|||j| S)NZ PATH_INFOZREQUEST_METHOD)rPrQz#Sorry, that method is not supported) rnrPrQserviceskeyssearchrr%r#) rarMrsr3methodr,rYZsmethodZspathr!rrr__call__ks$     zHTTPGitApplication.__call__)FNN)rgrhrirjrecompiler=r[r\rDrGrHrmrrrcrrrrrrJs*    rc@s eZdZdZddZddZdS) GunzipFilterzkWSGI middleware that unzips gzip-encoded requests before passing on to the underlying application. cCs ||_dSr^appraZ applicationrrrrcszGunzipFilter.__init__c Cs|dddkrz|d|d}Wn<tttfydtd}t|d|| dYn0t j d|dd|d<|d=d |vr|d =| ||S) NZHTTP_CONTENT_ENCODINGgziprkirr)filenameZfileobjmodeCONTENT_LENGTH) rNtellAttributeErrorr)NotImplementedErrortempfileZSpooledTemporaryFileshutilZ copyfileobjseekrZGzipFiler)rarMrsZ wsgi_inputrrrrs    zGunzipFilter.__call__Nrgrhrirjrcrrrrrrsrc@s eZdZdZddZddZdS)LimitedInputFilterzgWSGI middleware that limits the input length of a request to that specified in Content-Length. cCs ||_dSr^rrrrrrcszLimitedInputFilter.__init__cCs2|dd}|r&t|dt||d<|||S)Nrrrk)rNr]intr)rarMrsZcontent_lengthrrrrs   zLimitedInputFilter.__call__NrrrrrrsrcOst|i|}tt|}|S)zpFactory function to create an instance of HTTPGitApplication, correctly wrapped with needed middleware. )rrr)argskwargsrZ wrapped_apprrrmake_wsgi_chains rc@s(eZdZdZddZddZddZdS) ServerHandlerLoggerz@ServerHandler that uses dulwich's logger for logging exceptions.cCstjd|ddSNz/Exception happened during processing of request)exc_infor9 exceptionrarrrr log_exceptionsz!ServerHandlerLogger.log_exceptioncGstj|g|RdSr^r9r:raformatrrrr log_messageszServerHandlerLogger.log_messagecGstj|dSr^r9r*rarrrr log_errorszServerHandlerLogger.log_errorN)rgrhrirjrrrrrrrrsrc@s0eZdZdZddZddZddZdd Zd S) WSGIRequestHandlerLoggerzEWSGIRequestHandler that uses dulwich's logger for logging exceptions.cCstjd|ddSrrrrrrrsz&WSGIRequestHandlerLogger.log_exceptioncGstj|g|RdSr^rrrrrrsz$WSGIRequestHandlerLogger.log_messagecGstj|dSr^rrrrrrsz"WSGIRequestHandlerLogger.log_errorcCsL|j|_|sdSt|j|j||}||_| |j dS)zHandle a single HTTP requestN) ZrfilereadlineZraw_requestlineZ parse_requestrZwfileZ get_stderrZ get_environZrequest_handlerrunserverZget_app)rarYrrrrTs zWSGIRequestHandlerLogger.handleN)rgrhrirjrrrrTrrrrrs rc@seZdZddZdS)WSGIServerLoggercCstdt|dS)zHandle an error. z7Exception happened during processing of request from %sN)r9rrO)raZrequestZclient_addressrrr handle_errors zWSGIServerLogger.handle_errorN)rgrhrirrrrrrsrc Csddl}|}|jdddddd|jd d d td d d||\}}t|dkr^|d}nt}t t dt |i}t |}t |j|j|ttd}td|j|j|dS)z,Entry point for starting an HTTP git server.rNz-lz--listen_addresslisten_addressZ localhostzBinding IP address.)destdefaulthelpz-pz--portporti@zPort to listen on.)rtyperrr>r)Z handler_classZ server_classz'Listening for HTTP connections on %s:%d)optparseZ OptionParserZ add_optionr parse_argslenr2getcwdr Zdefault_logging_configrrrr rrrrr9r:Z serve_forever) argvrparserZoptionsrZgitdirr#rrrrrmains2     r__main__)N)Crjiorrrrr2rsysrtypingrrrZwsgiref.simple_serverrrrr Z urllib.parser Zdulwichr Zdulwich.protocolr Z dulwich.repor rrZdulwich.serverrrrrZ getLoggerrgr9r'r|r~rfloatrOrr"r$r0r5r=rDrGrHr[r\objectr]rmrnrrrrrrrrrrrrrsX      !G9