Ϫfe dZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl mZddlmZmZddlmZmZddlmZdd lmZdd lmZdd lmZdd lmZmZm Z m!Z!dd l"m#Z#ddl$m%Z%ddl&m'Z'ddl(m)Z)GddeZ*GddeZ+GddeZ,GddeZ-GddeZ.GddeZ/GddeZ0Gdd eZ1Gd!d"eZ2Gd#d$eZ3Gd%d&eZ4y)'z" Tests for L{twisted.web.static}. N)BytesIO)skipIf) verifyObject)abstract interfaces)compatlog) networkString)FilePath)platform)TestCase)httpresourcescriptstatic)FOUND)UnsupportedMethod_render) DummyRequestceZdZdZdZdZy)StaticDataTestsz Tests for L{Data}. ctjdd}tdgd_t |}fd}|j ||S)zV L{Data.render} returns an empty response body for a I{HEAD} request. foobarHEADc\jdjjdyN assertEqualjoinwrittenignoredrequestselfs >/usr/lib/python3/dist-packages/twisted/web/test/test_static.py cbRenderedz4StaticDataTests.test_headRequest..cbRendered.   SXXgoo6 {{66*u%  +T[['Br N)__name__ __module__ __qualname____doc__r1r6r r)rr s Cr rczeZdZdZdZdZdZdZdZdZ dZ d Z d Z e ejd d Zd ZdZdZdZdZe ej.j1dvdj3ej.dZdZdZdZdZdZdZ dZ!dZ"dZ#dZ$dZ%y )!StaticFileTestsz2 Tests for the basic behavior of L{File}. ct||SNr)r(rr's r)rzStaticFileTests._renderDsx))r ctjd5}tj|j d}|j |j dgddd|j tdy#1swY%xYw)z Passing C{1} as the value to L{File}'s C{ignoredExts} argument issues a warning and sets the ignored extensions to the wildcard C{"*"}. Trecord ignoredExts*Nwarningscatch_warningsrFilemktempr"rElenr(caughtWarningsfiles r)test_ignoredExtTruez#StaticFileTests.test_ignoredExtTrueGsn  $ $D 1 6^;;t{{}!>Bctjd5}tj|j d}|j |j gddd|j tdy#1swY%xYw)z Passing C{1} as the value to L{File}'s C{ignoredExts} argument issues a warning and sets the ignored extensions to the empty list. TrArrDNrCrGrMs r)test_ignoredExtFalsez$StaticFileTests.test_ignoredExtFalseSsl  $ $D 1 3^;;t{{}!jjdyNr" responseCoder%s r)r*z1StaticFileTests.test_notFound..cbRendered   W113 7r r rKmakedirsrrJrXrrgetChildForRequestrr.r(baserOchildr0r*r's` @r) test_notFoundzStaticFileTests.test_notFoundwsv  & {{499% {+++D': LL ( 8 j!r cdt|j}|jtj|j }t dg}tj||}|j|tj|j|j |j y)z The C{''} child of a L{File} which corresponds to a directory in the filesystem is a L{DirectoryLister}. r N) r rKrbrrJrXrrrcassertIsInstanceDirectoryListerr"r(rerOr'rfs r)test_emptyChildzStaticFileTests.test_emptyChilds{  & {{499%u%++D': eV%;%;< TYY/r cTt|jj}|j|j dj dj tj|j}tdg}tj||}|j|tjtj |j}|j#|j||j%|}|j|t&y)z The C{u''} child of a L{File} which corresponds to a directory whose path is text is a L{DirectoryLister} that renders to a binary listing. @see: U{https://twistedmatrix.com/trac/ticket/9438} z text-filewr N)r rK asTextModerbrfopencloserrJrXrrrcrirjr nativeStringr"r5bytes)r(textBasetextFiler'rf nativePathresponses r)test_emptyChildUnicodeParentz,StaticFileTests.test_emptyChildUnicodeParentsDKKM*557{#((-335;;x}}-u%++Hg> eV%;%;<((7  Z0<<( h.r c0tj}|jtj|j }t dgtj|}j|}fd}|j||S)z If a request is made which encounters a L{File} before a final segment which cannot be looked up in the filesystem due to security considerations, a not found response is sent. s..c>jjdyr\r^r%s r)r*zBStaticFileTests.test_securityViolationNotFound..cbRenderedr`r rards` @r)test_securityViolationNotFoundz.StaticFileTests.test_securityViolationNotFoundsv  & {{499%w'++D': LL ( 8 j!r z(Cannot remove read permission on Windowsc`tj}|jdj|jd|j dt j |j}tdgj|}fd}|j||S)z If the file in the filesystem which would satisfy a request cannot be read, L{File.render} sets the HTTP response code to I{FORBIDDEN}. r irc>jjdy)Nir^r%s r)r*z:StaticFileTests.test_forbiddenResource..cbRenderedr`r ) r rKrW addCleanupchmodrrJrXrrr.)r(rerOr0r*r's` @r)test_forbiddenResourcez&StaticFileTests.test_forbiddenResources  &   E* 1 {{499%u% LLw ' 8 j!r cvj}t|tr|jd}t |}|j t j|j}tdgtj|}j|}fd}|j||S)z A request whose path cannot be decoded as UTF-8 receives a not found response, and the failure is logged. asciicjjdjtjtdy)Nr]rC)r"r_rLflushLoggedErrorsUnicodeDecodeErrorr%s r)r*z8StaticFileTests.test_undecodablePath..cbRendereds:   W113 7   S!7!78J!KLa Pr )rK isinstancersdecoder rbrrJrXrrrcrr.)r(rXrerOrfr0r*r's` @r)test_undecodablePathz$StaticFileTests.test_undecodablePaths {{} dE ";;w'D~ {{499%y)++D': LL ( Q j!r c~|jtjdjtj y)zN L{File.forbidden} defaults to L{resource.ForbiddenResource}. .N)rirrJ forbiddenrForbiddenResourcer(s r)test_forbiddenResource_defaultz.StaticFileTests.test_forbiddenResource_defaults) fkk$/998;U;UVr cbt|j}|jddd}GfddtjGfddt j }||j}||_tdg}|j|}|j|y) z The resource rendered for forbidden requests is stored as a class member so that users can customize it. r scustom-forbidden-responsec6ttjd)Nr)OSErrorerrnoEACCESr;r r)failingOpenForReadingzOStaticFileTests.test_forbiddenResource_customize..failingOpenForReadings%,,+ +r ceZdZfdZy)QStaticFileTests.test_forbiddenResource_customize..CustomForbiddenResourcecSr?r;r(r'markerResponses r)r5zXStaticFileTests.test_forbiddenResource_customize..CustomForbiddenResource.render  %%r Nr7r8r9r5rsr)CustomForbiddenResourcer &r rceZdZWZy)JStaticFileTests.test_forbiddenResource_customize..CustomStaticFileN)r7r8r9r)rsr)CustomStaticFiler s /1Ir rN) r rKrWrResourcerrJrXopenForReadingrr5r") r(rerr fileResourcer'resultrrs @@r) test_forbiddenResource_customizez0StaticFileTests.test_forbiddenResource_customizes  & 5 , &h&7&7 & 2v{{ 2( 2 &; #u%$$W- 0r ctj}|j|jdj dt j |j}dg|_tdgtj|}j|}fd}|j||S)a  If a request is made which encounters a L{File} before a final empty segment, a file in the L{File} instance's C{indexNames} list which exists in the path the L{File} was created with is served as the response to the request. foo.barbazr cjdjjdjjj dddyNr rcontent-lengthr3r"r#r$responseHeaders getRawHeadersr%s r)r*z3StaticFileTests.test_indexNames..cbRendered)J   SXXgoo6 ?   ''556GHKT r )r rKrbrfrWrrJrX indexNamesrrrcrr.rds` @r)test_indexNameszStaticFileTests.test_indexNamess &  9((0{{499%$+u%++D': LL (  j!r cptj}|j|jdj dt j |j}tdgtj|}j|}fd}|j||S)z If a request is made which encounters a L{File} before a final segment which names a file in the path the L{File} was created with, that file is served as the response to the request. rrfoo.barcjdjjdjjj dddyrrr%s r)r*z3StaticFileTests.test_staticFile..cbRenderedBrr r rKrbrfrWrrJrXrrrcrr.rds` @r)test_staticFilezStaticFileTests.test_staticFile2s  &  9((0{{499% |,++D': LL (  j!r )utf-8mcbsz>Cannot write unicode filenames with file system encoding of {}cd}dtj}|j|j|j t j |j}t|jdgtj|}j|}fd}|j||S)zx A request for a existing unicode file path encoded as UTF-8 returns the contents of that file. uῆscontentrc jdjjjjj ddt t ty)Nr rr)r"r#r$rrr strrL)r&contentr'r(s r)r*zBStaticFileTests.test_staticFileUnicodeFileName..cbRenderedbsY   SXXgoo6 @   ''556GHKc#g,/0 r )r rKrbrfrWrrJrXrencoderrcrr.) r(namererOrfr0r*rr's ` @@r)test_staticFileUnicodeFileNamez.StaticFileTests.test_staticFileUnicodeFileNameKs= &  4##G,{{499% G 456++D': LL (  j!r ctj|j}tdg}|j d|}|j ||j y)z A L{static.File} created for a directory which does not exist should return childNotFound from L{static.File.getChild}. rN)rrJrKrgetChildr" childNotFound)r( staticFiler'rfs r)test_staticFileDeletedGetChildz.StaticFileTests.test_staticFileDeletedGetChildlsL [[/  |,##J8  8 89r ctjj}tdgtdgj |j |j }fd}|j ||S)z{ A L{static.File} created for a file which does not exist should render its C{childNotFound} page. rc8fd}j|S)Ncjdjjdjjyrr!)r&r'request2r(s r)r*zUStaticFileTests.test_staticFileDeletedRender..cbRendered2..cbRendereds/  '//!:CHHXEUEU.cbRendered2s X MM* %Hr )rrJrKrrrr.)r(rd2rr0r'rs` @@@r)test_staticFileDeletedRenderz,StaticFileTests.test_staticFileDeletedRendervso [[/  |, - LLW - \\*22H =  {# r crt|j}|jddGfddtjGfddt j }||j}tdg}|jd|}|j|}|j|y) zs The resource rendered for child not found requests can be customize using a class member. r scustom-child-not-found-responseceZdZfdZy)YStaticFileTests.test_getChildChildNotFound_customize..CustomChildNotFoundResourcecSr?r;rs r)r5z`StaticFileTests.test_getChildChildNotFound_customize..CustomChildNotFoundResource.renderrr Nrrsr)CustomChildNotFoundResourcerrr rceZdZWZy)NStaticFileTests.test_getChildChildNotFound_customize..CustomStaticFileN)r7r8r9r)rsr)rrs 79Mr rs no-child.txtN) r rKrWrrrrJrXrrr5r") r(rerrr'rfrrrs @@r)$test_getChildChildNotFound_customizez4StaticFileTests.test_getChildChildNotFound_customizes  & ; &(*;*; & :v{{ :( 2 01%%ow?g& 0r ctj}|jdtj|j }t dgd_t|}fd}|j||S)zd L{static.File.render} returns an empty response body for I{HEAD} requests. rr rc\jdjjdyrr!r%s r)r*z4StaticFileTests.test_headRequest..cbRenderedr+r ) r rKrWrrJrXrr-rr.)r(rXrOr0r*r's` @r)r1z StaticFileTests.test_headRequestsj  & {{499%u%  D' " = j!r ctj}|j|jdj dt j |j}dtji|_ tdgtj|}j|}fd}|j||S)a! If a request is made which encounters a L{File} before a final segment which names a file with an extension which is in the L{File}'s C{processors} mapping, the processor associated with that extension is used to serve the response to the request. rsTfrom twisted.web.static import Data resource = Data(b'dynamic world', 'text/plain') .barrcjdjjdjjj dddy)Nr s dynamic worldrrs13rr%s r)r*z3StaticFileTests.test_processors..cbRenderedsK   SXXgoo68H I   ''556GHKU r )r rKrbrfrWrrJrXrResourceScript processorsrrrcrr.rds` @r)test_processorszStaticFileTests.test_processorss &  9(( A {{499%!6#8#89 |,++D': LL (  j!r cPtjd}|j|jg|j d|j d|j|jddgtjdd}|j|jddgy)z The list of ignored extensions can be set by passing a value to L{File.__init__} or by calling L{File.ignoreExt} later. rz.foor)r.bazrDrN)rrJr"rE ignoreExt)r(rOs r)test_ignoreExtzStaticFileTests.test_ignoreExts {{4  ))2. v v ))FF+;<{{4-=> ))FF+;} file in the path the L{File} was created with if such a file exists and the L{File} has been configured to ignore the I{} extension. rrzfoo.quuxrZ)rrDrc\jdjjdy)Nr rr!r%s r)r*zAStaticFileTests.test_ignoredExtensionsIgnored..cbRendereds   SXXgoo6 ?r rrds` @r)test_ignoredExtensionsIgnoredz-StaticFileTests.test_ignoredExtensionsIgnoreds &  9((0 :)))4{{499)<x(++D': LL ( @ j!r ct|j}|j|jdjt j |j }tdg}d|_tj||}|j|j|||j|jt|j|j j#ddgy)z A request for a path which is a directory but does not have a trailing slash will be redirected to a URL which does have a slash by L{File}. foldersfoldershttp://dummy/folder#baz?foo=barslocations http://dummy/folder/#baz?foo=barN)r rKrbrfrrJrXrurirrcsuccessResultOfrr"r_rrrrks r)+test_directoryWithoutTrailingSlashRedirectsz;StaticFileTests.test_directoryWithoutTrailingSlashRedirectss  &  8%%'{{499% {+8 ++D': T\\%9: --u5   # # 1 1+ > 0 1 r ctt|j}|jt j |j }fd|_|fS)z Create a L{File} that when opened for reading, returns a L{StringIO}. @return: 2-tuple of the opened "file" and the L{File}. @rtype: L{tuple} cSr?r;)fakeFilesr)z;StaticFileTests._makeFilePathWithStringIO..sHr )StringIOr rKtouchrrJrXrp)r(rXrOrs @r)_makeFilePathWithStringIOz)StaticFileTests._makeFilePathWithStringIOsH: & {{499%$ ~r c|j\}}tdg}d|_|jt |||j dj |jd|j|jy)zm A HEAD request opens the file, gets the size, and then closes it after the request. rrr N) rrr-rrr"r#r$ assertTrueclosedr(rrOr's r)test_HEADClosesFilez#StaticFileTests.test_HEADClosesFilesk 779$t$  WT734 '//2C8 (r c"|j\}}tdg}d|_d|_|j t |||j dj|jd|j|jy)zQ A GET request that is cached closes the file after the request. rsGETc"tjSr?)rCACHED)_s r)rz>StaticFileTests.test_cachedRequestClosesFile..1s DKKr r N) rrr-setLastModifiedrrr"r#r$rrrs r)test_cachedRequestClosesFilez,StaticFileTests.test_cachedRequestClosesFile)ss779$t$"7 WT734 '//2C8 (r N)&r7r8r9r:rrPrSrUr6rgrlrxr{rr isWindowsrrrrrrsysgetfilesystemencodinglowerformatrrrrr1rrrrrrrr;r r)r=r=?s* 1 1 1 C* 0/.* H   "LMN.0W 1662 !!!#))+3DD f.S..01   8:*10$< =0 *  ) )r r=ceZdZdZddZdZdZdZdZdZ d Z d Z d Z d Z d ZdZdZdZdZdZdZdZdZy)StaticMakeProducerTestsz) Tests for L{File.makeProducer}. Nct|j}|j|tj|j }||_||_|S)z Make a L{static.File} resource that has C{content} for its content. @param content: The L{bytes} to use as the contents of the resource. @param type: Optional value for the content type of the resource. )r rKrWrrJ _asBytesPathencodingtype)r(rrrfileNamers r)makeResourceWithContentz/StaticMakeProducerTests.makeResourceWithContent<sMDKKM*G$;;x4467$ r ci}|jjD];\}}|jjds&|d||j<=|S)z Extract the content-* headers from the L{DummyRequest} C{request}. This returns the subset of C{request.outgoingHeaders} of headers that start with 'content-'. scontent-r)rgetAllRawHeadersr startswith)r(r'contentHeaderskvs r)r z&StaticMakeProducerTests.contentHeadersJs[++<<> 1DAqwwy##K0,-aDqwwy) 1r c|jd}tg}|j5}|j||}|j |t j dddy#1swYyxYw)zp makeProducer when no Range header is set returns an instance of NoRangeStaticProducer. r N)r rr makeProducerrirNoRangeStaticProducer)r(rr'rOproducers r),test_noRangeHeaderGivesNoRangeStaticProducerzDStaticMakeProducerTests.test_noRangeHeaderGivesNoRangeStaticProducerWsq //4r" $X $ $ & J$,x,,Wd;H  ! !(F,H,H I J J Js 4A++A4c|jd}tg}|j5}|j|||j t j |jdddy#1swYyxYw)zp makeProducer when no Range header is set sets the responseCode on the request to 'OK'. r N)r rrrr"rOKr_)r(rr'rOs r)test_noRangeHeaderSets200OKz3StaticMakeProducerTests.test_noRangeHeaderSets200OKbso //4r" $X $ $ & <$ !H ! !'4 0   TWWg&:&: ; < < A55A>c<d}d}d}|jd|z||}tg}|j5}|j|||j t |d|fzt |d|j |dddy#1swYyxYw) zo makeProducer when no Range header is set sets the Content-* headers for the response. { text/plaingziparr%d) content-typercontent-encodingN)r rrrr"r r )r(length contentTypecontentEncodingrr'rOs r)$test_noRangeHeaderSetsContentHeaderszBBcdtg}|jjddd}d}|jd||}|j5}|j |||j t|t|ddd |j|d d d y #1swYy xYw) makeProducer when the Range header requests a single, satisfiable byte range sets the Content-* headers appropriately. r&r'rrr(rs bytes 1-3/6r)rr  content-rangerN) rr*r+r rrr"r r )r(r'r"r#rrOs r)"test_singleRangeSetsContentHeadersz:StaticMakeProducerTests.test_singleRangeSetsContentHeaderss r"++HlC"  // K/0 %X $ $ & $ !H ! !'4 0   %2;%?)6)G&4'+  ##G,    s A B&&B/c&tg}|jjdd|jd}|j5}|j ||}|j |tjdddy#1swYyxYw)z makeProducer still returns an instance of L{SingleRangeStaticProducer} when the Range header requests a single unsatisfiable byte range. r& bytes=4-10abcNr)r-s r)=test_singleUnsatisfiableRangeReturnsSingleRangeStaticProducerzUStaticMakeProducerTests.test_singleUnsatisfiableRangeReturnsSingleRangeStaticProducers r"++HmD//7 $X $ $ & N$,x,,Wd;H  ! !(F,L,L M N N Nr/c:tg}|jjdd|jd}|j5}|j |||j tj|jdddy#1swYyxYw)z makeProducer sets the response code of the request to of 'Requested Range Not Satisfiable' when the Range header requests a single unsatisfiable byte range. r&r;r<N rr*r+r rrr"rREQUESTED_RANGE_NOT_SATISFIABLEr_r3s r)?test_singleUnsatisfiableRangeSets416ReqestedRangeNotSatisfiablezWStaticMakeProducerTests.test_singleUnsatisfiableRangeSets416ReqestedRangeNotSatisfiables r"++HmD//7 $X $ $ & Y$ !H ! !'4 0   TAA7CWCW X Y Y Yr5c8tg}|jjddd}|jd|}|j5}|j |||j dddd |j|d d d y #1swYy xYw) z makeProducer when the Range header requests a single, unsatisfiable byte range sets the Content-* headers appropriately. r&r;rr<r text/plain0 bytes */3rrr8Nrr*r+r rrr"r r(r'r"rrOs r)/test_singleUnsatisfiableRangeSetsContentHeaderszGStaticMakeProducerTests.test_singleUnsatisfiableRangeSetsContentHeaderss r"++HmD" //[/I $X $ $ & $ !H ! !'4 0   %2'+&2 ##G,      9BBc8tg}|jjddd}|jd|}|j5}|j |||j dddd |j|d d d y #1swYy xYw) z makeProducer when the Range header requests a single byte range that partly overlaps the resource sets the Content-* headers appropriately. r&s bytes=2-10rr<rCrD1s bytes 2-2/3rGNrHrIs r)6test_singlePartiallyOverlappingRangeSetsContentHeaderszNStaticMakeProducerTests.test_singlePartiallyOverlappingRangeSetsContentHeaderss r"++HmD" //[/I $X $ $ & $ !H ! !'4 0   %2'+&4 ##G,     rKc&tg}|jjdd|jd}|j5}|j ||}|j |tjdddy#1swYyxYw)z makeProducer when the Range header requests a single byte range returns an instance of MultipleRangeStaticProducer. r& bytes=1-3,5-6r(N rr*r+r rrrirMultipleRangeStaticProducerr-s r)2test_multipleRangeGivesMultipleRangeStaticProducerzJStaticMakeProducerTests.test_multipleRangeGivesMultipleRangeStaticProducers r"++H6FG// : $X $ $ & P$,x,,Wd;H  ! !(F,N,N O P P Pr/c:tg}|jjdd|jd}|j5}|j |||j tj|jdddy#1swYyxYw)z makeProducer when the Range header requests a multiple satisfiable byte ranges sets the response code on the request to 'Partial Content'. r&rPr(Nr1r3s r)'test_multipleRangeSets206PartialContentz?StaticMakeProducerTests.test_multipleRangeSets206PartialContents r"++H6FG// : $X $ $ & I$ !H ! !'4 0   T1173G3G H I I Ir5c|tg}|jjdd|jdd}|j5}|j ||}|j |}|jddht|jd}|jD]\}}} |t|z }|jd |fz|d|jd||d} |jd tjd | |j!d |d d d y #1swYy xYw) r7r&rPs abcdefghijklr)rrrrNs(multipart/byteranges; boundary="[^"]*"\Zr )rr*r+r rrr r"setkeys rangeInforLassertInassertNotIdenticalrematch assertNotIn) r(r'rrOrr expectedLengthboundaryoffsetsizer"s r)#test_mutipleRangeSetsContentHeadersz;StaticMakeProducerTests.test_mutipleRangeSetsContentHeaderssL r"++H6FG//&/Q $X $ $ & B$,x,,Wd;H!009N   "O4c.:M:M:O6P N*2*<*< 0&&$#h-/ 0   ))>:K+L  MM/> :(9K  # #E{S    0. A3 B B Bs CD22D;c&tg}|jjdd|jd}|j5}|j ||}|j |tjdddy#1swYyxYw)z makeProducer still returns an instance of L{SingleRangeStaticProducer} when the Range header requests multiple ranges, none of which are satisfiable. r&bytes=10-12,15-20r<NrQr-s r)Btest_multipleUnsatisfiableRangesReturnsMultipleRangeStaticProducerzZStaticMakeProducerTests.test_multipleUnsatisfiableRangesReturnsMultipleRangeStaticProducer1s r"++H6JK//7 $X $ $ & P$,x,,Wd;H  ! !(F,N,N O P P Pr/c:tg}|jjdd|jd}|j5}|j |||j tj|jdddy#1swYyxYw)z makeProducer sets the response code of the request to of 'Requested Range Not Satisfiable' when the Range header requests multiple ranges, none of which are satisfiable. r&rfr<Nr?r3s r)Btest_multipleUnsatisfiableRangesSets416ReqestedRangeNotSatisfiablezZStaticMakeProducerTests.test_multipleUnsatisfiableRangesSets416ReqestedRangeNotSatisfiable>s r"++H6JK//7 $X $ $ & Y$ !H ! !'4 0   TAA7CWCW X Y Y Yr5cptg}|jjddd}|jjdd|jd|}|j5}|j |||j ddd d |j|d d d y #1swYy xYw) z makeProducer when the Range header requests multiple ranges, none of which are satisfiable, sets the Content-* headers appropriately. r&r;rrfr<rCrErFrD)rr8rNrHrIs r)1test_multipleUnsatisfiableRangeSetsContentHeaderszIStaticMakeProducerTests.test_multipleUnsatisfiableRangeSetsContentHeadersKs r"++HmD" ++H6JK//[/I $X $ $ & $ !H ! !'4 0   '+&2%2 ##G,     s *9B,,B5c:tg}|jjdd|jd}|j5}|j |||j tj|jdddy#1swYyxYw)z makeProducer when the Range header requests multiple ranges, at least one of which matches, sets the response code to 'Partial Content'. r&sbytes=1-3,100-200r(Nr1r3s r) test_oneSatisfiableRangeIsEnoughz8StaticMakeProducerTests.test_oneSatisfiableRangeIsEnough`s r"++H6JK// : $X $ $ & I$ !H ! !'4 0   T1173G3G H I I Ir5)NN)r7r8r9r:r r rrr$r.r4r9r=rArJrNrSrUrdrgrirkrmr;r r)rr7sr   J <. N I0 N Y(( P I!BF P Y* Ir rceZdZdZdZdZy)StaticProducerTestsz3 Tests for the abstract L{StaticProducer}. ct}tjd|}|j|j |j y)zu L{StaticProducer.stopProducing} closes the file object the producer is producing data from. N)rrStaticProducer stopProducingrrr( fileObjectrs r)test_stopProducingClosesFilez0StaticProducerTests.test_stopProducingClosesFilers; Z ((z:   ))*r ct}tjtg|}|j |j d|j y)z L{StaticProducer.stopProducing} sets the request instance variable to None, which indicates to subclasses' resumeProducing methods that no more data should be produced. N)rrrqrrrassertIdenticalr'rss r)#test_stopProducingSetsRequestToNonez7StaticProducerTests.test_stopProducingSetsRequestToNone|sD Z ((b)9:F  T8#3#34r N)r7r8r9r:rurxr;r r)roroms+ 5r roc(eZdZdZdZdZdZdZy)NoRangeStaticProducerTestsz- Tests for L{NoRangeStaticProducer}. c`ttjtjddy)zG L{NoRangeStaticProducer} implements L{IPullProducer}. N)rr IPullProducerrrrs r)test_implementsIPullProducerz7NoRangeStaticProducerTests.test_implementsIPullProducers" Z--v/K/KDRV/WXr ctg}d}tj|t|}|j |j |dj |jy)zs L{NoRangeStaticProducer.resumeProducing} writes content from the resource to the request. r(r N)rrrrstartr"r#r$r(r'rrs r)#test_resumeProducingProducesContentz>NoRangeStaticProducerTests.test_resumeProducingProducesContentsS r"//'9JK  #((7??";r ctg}d}tj|t|gd}d|_|j d|ddzdz|dd z|d d d zg}|j ||jy ) a L{MultipleRangeStaticProducer.start} writes about C{abstract.FileDescriptor.bufferSize} bytes of content from the resource to the request at once. To be specific about the 'about' above: it can write slightly more, for example in the case where the first boundary plus the first chunk is less than C{bufferSize} but first boundary plus the first chunk plus the second boundary is more, but this is unimportant as in practice the boundaries are fairly small. On the other side, it is important for performance to bundle up several small chunks into one call to request.write. s01234567890123456789))rrr)brWr)crrrrrrrrWrrN)rrrRrrrr"r$)r(r'rrrs r)rzBMultipleRangeStaticProducerTests.test_resumeProducingBuffersOutput#sr"#55 Xg&(S !  71Q< $ &2 6 BrNT !  7??3r ctg}|j}g}|j|jt j |t ddg}|j|jdg|y)z L{MultipleRangeStaticProducer.resumeProducing} calls finish() on the request after it is done producing content. r()r rCrN) rrr.rrrRrrr"rs r)rz:MultipleRangeStaticProducerTests.test_finishCalledWhenDone@sq r" --/ ""<#6#6755 Xi(;-   $.r Nrr;r r)rrs ? 4:/r rceZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZy) RangeTestsa Tests for I{Range-Header} support in L{twisted.web.static.File}. @type file: L{file} @ivar file: Temporary (binary) file containing the content to be served. @type resource: L{static.File} @ivar resource: A leaf web resource using C{file} as content. @type request: L{DummyRequest} @ivar request: A fake request, requesting C{resource}. @type catcher: L{list} @ivar catcher: List which gathers all log information. ct|j}d|_|j|j|j |_t j|j j|_ d|j_ tdg|_ |j j|j_ g|_tj |jj"y)a Create a temporary file with a fixed payload of 64 bytes. Create a resource for that file and create a request which will be for that resource. Each test can set a different range header to test different aspects of the implementation. s@uE7a0y0S﬷M6k{  мkYI oZbk&%݂q/AYrCr N)r rKpayloadrWrprOrrJrrisLeafrr'rcatcherr addObserverr)r(rXs r)setUpzRangeTests.setUpcs & *  %IIK  DIINN3   #SE* 99>>    ++,r c|jjtj|jj y)zB Clean up the resource file and the log observer. N)rOrqr removeObserverrrrs r)tearDownzRangeTests.tearDowns*  4<<../r c|jj}|j|dd||j|jgd|y)zU Asserts that a given log message occurred with an expected message. messagerzAn additional log occurred: N)rpopr")r(rlogItems r) _assertLoggedzRangeTests._assertLoggedsN,,""$ +A.9 r-I'+UVr cr|jj}|jt|d|jt|d|jt|d|jt|d|jt|d|jt|d|jt|dy) zw L{File._parseRangeHeader} raises L{ValueError} when passed syntactically invalid byte ranges. sbytess unknown=1-2sbytes=3sbytes=-s bytes=foo-s bytes=-foos bytes=5-4N)r_parseRangeHeaderr4 ValueError)r(fs r)test_invalidRangeszRangeTests.test_invalidRangess MM + + *a2 *a8 *a4 *a4 *a7 *a7 *a6r c\|j|jjddgy)z A single bytes range without an explicit stop position is parsed into a two-tuple giving the start position and L{None}. sbytes=0-)rNNr"rrrs r)test_rangeMissingStopz RangeTests.test_rangeMissingStop% 88E {Sr c\|j|jjddgy)z A single bytes range without an explicit start position is parsed into a two-tuple of L{None} and the end position. sbytes=-3)NrNrrs r)test_rangeMissingStartz!RangeTests.test_rangeMissingStartrr c\|j|jjddgy)z A single bytes range with explicit start and stop positions is parsed into a two-tuple of those positions. s bytes=2-5)rrWNrrs r) test_rangezRangeTests.test_ranges% 88FQr c|j|jjddg|j|jjddg|j|jjddg|j|jjddg|j|jjddg|j|jjddgy) z A single bytes range with whitespace in allowed places is parsed in the same way as it would be without the whitespace. s bytes=1-2 rCrs bytes =1-2 s bytes= 1-2s bytes=1 -2s bytes=1- 2s bytes=1-2 Nrrs r)test_rangeWithSpacezRangeTests.test_rangeWithSpaces 88H6(S 88H6(S 88G&R 88G&R 88G&R 88G&Rr c\|j|jjddgy)z If there are multiple byte ranges but only one is non-null, the non-null range is parsed and its start and stop returned. sbytes=1-2, , , rNrrs r)test_nullRangeElementsz!RangeTests.test_nullRangeElementss)  MM + +,B CfX r c^|j|jjdddgy)zd If multiple byte ranges are specified their starts and stops are returned. s bytes=1-2,3-4r)rrNrrs r)test_multipleRangeszRangeTests.test_multipleRangess,  MM + +,< =?O r c|jjjdd|jj |j|j t dj|jjdy)zp A correct response to a range request is as long as the length of the requested range. r&s bytes=0-43r ,N) r'r*r+rr5r"rLr#r$rs r)test_bodyLengthzRangeTests.test_bodyLengths\ ##00=I T\\* SXXdll&:&:; ?6Aq]aS!: & ?  ##009GW;WX T\\* 22D4H4HI88 6 LL ( ( 6 6 G J  %( ''1E1E(FQ YU4y1 ELD&1a   ]4==+=+=>^@T U#O4 E3   SZ +   SXq )   SY (A(A(C D   T\\!a!e4d7m D  E @sH> c ddt|jdzfg}dj|Dcgc]\}}t|d|c}}}|jj j dd|z|jj|j|j|jjtjtjd|jjj!d d j#d }|j%d j|jj&|}|jt|t|t)||D]\}\}}|jt|jj*|d |d\}} } |jt-|||jt-| t/||jj1d z |jt-| |jj1|j|j||d z|dycc}}w)z The response to a request for multiple bytes ranges is a MIME-ish multipart response, even when one of the ranged falls off the end of the resource. rrrrrr&rrrrrCr rrrN)rLrr#r r'r*r+rr5r"r_rr2r]r^rrrrr$rrrminrrs r)0test_multipleRangeRequestWithRangeOverlappingEndz;RangeTests.test_multipleRangeRequestWithRangeOverlappingEnd5s b#dll"3b"89: 995> ?6Aq]aS!: & ?  ##009GW;WX T\\* 22D4H4HI88 6 LL ( ( 6 6 G J  %( ''1E1E(FQ YU4y1 ELD&1a   ]4==+=+=>^@T U#O4 E3   SZ +   SXs1dmm.G.G.IA.M'N O   SY (A(A(C D   T\\!a!e4d7m D  E @sI; c|jjjdd|jj |j|j dj |jj|jdd|j tdj |jjd|j |jjtj|j |jjjddd |j |jjjd dd y) z If the end byte position is omitted, then it is treated as if the length of the resource was specified by the end byte position. r&s bytes=23-r N)r8rsbytes 23-63/64rs41r'r*r+rr5r"r#r$rrLr_rr2rrrs r)test_implicitEndzRangeTests.test_implicitEndPs  ##00<H T\\* $,,"6"67bc9JK SXXdll&:&:;J T\\* 22DGG< $,,"6"67F  LL ( ( 6 67H I! L S&( ( r c |jjjdd|jj |j|j |jj tj|j dj|jjd|j |jjjddd|j |jjjddtdt|jfzy ) a If a range is unsatisfiable due to the start not being less than the length of the resource, the response is 416 (Requested range not satisfiable) and no data is written to the response body (RFC 2616, section 14.35.1). r&s bytes=67-108r rrrEr8z bytes */%dN)r'r*r+rr5r"r_rr@r#r$rrr rLrrs r)test_invalidStartBytePosz#RangeTests.test_invalidStartBytePoss ##00?K T\\*  LL % %t'K'K  $,,"6"67=  LL ( ( 6 67H I! Ld   LL ( ( 6 67G H K ,#dll*;)== > r N)r7r8r9r:rrrrrrrrrrrrrrrrrr r rrr;r r)rrRsy -80W78TTR S  B & DE4E6 $ & ( *   r rceZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z eej d d ZdZdZdZy)DirectoryListerTestsz. Tests for L{static.DirectoryLister}. c,tdg}||_|Sr)rr)r(rr's r)_requestzDirectoryListerTests._requestsu% r ct|j}|jtj|j }|j |jd}|jd||jd|y)zm L{static.DirectoryLister} prints the request uri as header of the rendered content. rs"

Directory listing for foo

s(Directory listing for fooN r rKrbrrjrXr5rr[r(rXlisterr/s r)test_renderHeaderz&DirectoryListerTests.test_renderHeadersf  & '' 2}}T]]623 ;TB A4Hr ct|j}|jtj|j }|j |jd}|jd||jd|y)zW L{static.DirectoryLister} unquote the request uri before printing it. s foo%20bars&

Directory listing for foo bar

s,Directory listing for foo barNrrs r)test_renderUnquoteHeaderz-DirectoryListerTests.test_renderUnquoteHeadersf & '' 2}}T]]<89 ?F EtLr ct|j}|jtj|j }|j |jd}|jd||jd|y)zl L{static.DirectoryLister} escape "&", "<" and ">" after unquoting the request uri. s foo%26bars*

Directory listing for foo&bar

s0Directory listing for foo&barNrrs r)test_escapeHeaderz&DirectoryListerTests.test_escapeHeadersf  & '' 2}}T]]<89 CTJ I4Pr ct|j}|j|jdj d|jdj ddzt j |j}|j|jd}d}|j||y) ze L{static.DirectoryLister} is able to list all the files inside a directory. file1scontent1file2scontent2irs file1 8B [text/html] file2 7K [text/html] N) r rKrbrfrWrrjrXr5rr[r(rXrr/rs r)test_renderFilesz%DirectoryListerTests.test_renderFiless  &  7&&{3 7&&{T'9:'' 2}}T]]623   dD!r cxt|j}|j|jdj|jdjt j |j }|j|jd}d}|j||y)zk L{static.DirectoryLister} is able to list all the directories inside a directory. dir1zdir2 & 3rs dir1/ [Directory] dir2 & 3/ [Directory] N r rKrbrfrrjrXr5rr[r!s r)test_renderDirectoriesz+DirectoryListerTests.test_renderDirectoriess  &  6##% :'')'' 2}}T]]623   dD!r ct|j}|j|jdj|jdj|jdjt j |j ddg}|j|jd}d}|j||y)z L{static.DirectoryLister} takes an optional C{dirs} argument that filter out the list of directories and files printed. r$dir2dir3)dirsrs dir1/ [Directory] dir3/ [Directory] Nr%r!s r)test_renderFilteredz(DirectoryListerTests.test_renderFiltered(s  &  6##% 6##% 6##%'' 8HI}}T]]623   dD!r c *tjd}tdDcgc] }dddddd }}|j|}|j t |d|j |djd|j |djd|j |d jd|j |d jd|j |d jdycc}w) zu L{static.DirectoryLister} gives an alternate class for each odd and even rows in the table. NrWr)hreftextrcrrrzrCzrrr)rrjr_buildTableContentr"rLrr )r(rielementsrs r)test_oddAndEvenz$DirectoryListerTests.test_oddAndEvenBs ''-1X R L  ++H5 Wq)  --.@AB  --.ABC  --.@AB  --.ABC  --.@AB sDc4t|j}|jtj|j }|j d}|j||j|jjdddy)z L{static.DirectoryLister} produces a MIME-type that indicates that it is HTML, and includes its charset (UTF-8). r rrstext/html; charset=utf-8N) r rKrbrrjrXrr5r"rr)r(rXrreqs r)test_contentTypez%DirectoryListerTests.test_contentTypeUsu  & '' 2mmC  c     - -o >q A ' r c t|j}|j|jdj d|jdj d|jdj d|jdj dt j |j}|jd d d d d }tj|j|}|j|\}}|j|g|j|ddddddddddddddddddddddddgy)zl L{static.DirectoryLister} is able to detect mimetype and encoding of listed files. z file1.txtfile1zfile2.pyspythonz file3.conf.gzsconf compressedzfile4.diff.bz2sdiff compressedrz text/pythonztext/configurationz text/diff)z.txtz.pyz.confz.diff) contentTypesr5Bz [text/plain])rr-rcr.r6Bz [text/python]z[gzip]15Bz[text/configuration]z[bzip2]z [text/diff]N) r rKrbrfrWoslistdirrXsortrrj_getFilesAndDirectoriesr")r(rX directoryr8rr*filess r)test_mimeTypeAndEncodingsz.DirectoryListerTests.test_mimeTypeAndEncodingsdsW  &  ;**84 :)))4 ?#../AB #$//0BCJJtyy) ! )  '' M44Y? e r"  !#' '* !#& &+ !)+!+2 !*,!,) -  r zNo symlink supportct|j}|j|jd}|j d|j |jd|j tj|j}tj|j}|j|j|\}}|j|g|j|gy)z If on the file in the listing points to a broken symlink, it should not be returned by L{static.DirectoryLister._getFilesAndDirectories}. rr7r N)r rKrbrfrWlinkToremoverrjrXr<r=r>r?r")r(rXrrr@r*rAs r)test_brokenSymlinkz'DirectoryListerTests.test_brokenSymlinks  &  7# " TZZ() '' 2JJtyy) 44Y? e r" #r c.tj}|jtj|j }j dtj|}t|}fd}|j||S)zu Any child resource of L{static.DirectoryLister} renders an HTTP I{NOT FOUND} response code. r cZjjtjyr?)r"r_r NOT_FOUNDr%s r)r*z>DirectoryListerTests.test_childrenNotFound..cbRendereds   W114>> Br ) r rKrbrrjrXrrrcrr.)r(rXrrfrr*r's` @r)test_childrenNotFoundz*DirectoryListerTests.test_childrenNotFoundsy  & '' 2--$++FG<( C :& r ct|j}tj|j}|j t |d|jd|j t|d|jdy)zR L{static.DirectoryLister.__repr__} gives the path of the lister. zN)r rKrrjrXr"reprr)r(rXrs r) test_reprzDirectoryListerTests.test_reprsl &'' 2 f)=dii]!'LM V( ..z:DA ..}=wGr N)r7r8r9r:rrrrr"r&r+r2r5rBrr _supportsSymlinksrFrJrNrWr;r r)rrs{ I M Q"4"4"4C&  8 t ***, ,.BC$D$&$M Hr rc<eZdZdZeZdZdZdZdZ dZ y)LoadMimeTypesTestsz Tests for the MIME type loading routine. @cvar UNSET: A sentinel to signify that C{self.paths} has not been set by the mock init. c&|j|_yr?)UNSETpathsrs r)rzLoadMimeTypesTests.setUps ZZ r c||_y)z A mock L{mimetypes.init} that records the value of the passed C{paths} argument. @param paths: The paths that will be recorded. N)r]r(r]s r) _fakeInitzLoadMimeTypesTests._fakeInits  r c|tj|j|j|jdy)zE By default, L{None} is passed to C{mimetypes.init}. initNr loadMimeTypesr`rwr]rs r)test_defaultArgumentIsNonez-LoadMimeTypesTests.test_defaultArgumentIsNones* $..1 TZZ.r cgd}tj||j|j|j|y)zI Passed MIME type files are passed to C{mimetypes.init}. )xyzrbNrdr_s r)test_extraLocationsWorkz*LoadMimeTypesTests.test_extraLocationsWorks1 U8 TZZ/r cttddr[tjtj}|j |j djtjytjtj\}}}}||jd}|j |tjy)z: By default, C{mimetypes.init} is called. signatureNrc) getattrinspectrmrreassertIs parametersdefault mimetypesrc getargspecindex)r(rmargsrdefaults defaultInits r)test_usesGlobalInitFunctionz.LoadMimeTypesTests.test_usesGlobalInitFunctions 7K .))&*>*>?I MM)..v6>>  O#*#5#5f6J6J#K D!Q"4::f#56K MM+y~~ 6r N) r7r8r9r:objectr\rr`rfrkryr;r r)rZrZs) HE /0 7r rZceZdZdZy)StaticDeprecationTestscddlm}|tdg|j|jg}|j t |d|j |dddy)z? L{twisted.web.static.addSlash} is deprecated. r)addSlashr rCrzrs  ".1&/,++66(0*7ChC>u)hu)psIhsIl 5(569/9/x>/X>/BJ/xJ/Zo o d SH8SHl2727j X r