1818
1919from roundup .anypy .cgi_ import cgi
2020from roundup .cgi import client , actions , exceptions
21- from roundup .cgi .exceptions import FormError , NotFound , Redirect
21+ from roundup .cgi .exceptions import FormError , NotFound , Redirect , NotModified
2222from roundup .exceptions import UsageError , Reject
2323from roundup .cgi .templating import HTMLItem , HTMLRequest , NoTemplate
2424from roundup .cgi .templating import HTMLProperty , _HTMLItem , anti_csrf_nonce
@@ -1942,6 +1942,7 @@ def _make_client(self, form, classname='user', nodeid='1',
19421942 if nodeid is not None :
19431943 cl .nodeid = nodeid
19441944 cl .db = self .db
1945+ cl .request = MockNull ()
19451946 cl .db .Otk = cl .db .getOTKManager ()
19461947 #cl.db.Otk = MockNull()
19471948 #cl.db.Otk.data = {}
@@ -2382,6 +2383,83 @@ def testRegisterActionUnusedUserCheck(self):
23822383 if os .path .exists (SENDMAILDEBUG ):
23832384 os .remove (SENDMAILDEBUG )
23842385
2386+ def testserve_static_files_cache_headers (self ):
2387+ """Note for headers the real headers class is case
2388+ insensitive.
2389+ """
2390+ # make a client instance
2391+ cl = self ._make_client ({})
2392+ # Make local copy in cl to not modify value in class
2393+ cl .Cache_Control = copy .copy (cl .Cache_Control )
2394+
2395+ # TEMPLATES dir is searched by default. So this file exists.
2396+ # Check the returned values.
2397+ cl .serve_static_file ("style.css" )
2398+
2399+ # gather the conditional request headers from the 200 response
2400+ inm = cl .additional_headers ['ETag' ]
2401+ ims = cl .additional_headers ['Last-Modified' ]
2402+
2403+
2404+ # loop over all header value possibilities that will
2405+ # result in not modified.
2406+ for headers in [
2407+ {'if-none-match' : inm },
2408+ {'if-modified-since' : ims },
2409+ {'if-none-match' : inm , 'if-modified-since' : ims },
2410+ {'if-none-match' : inm , 'if-modified-since' : "fake" },
2411+ {'if-none-match' : "fake" , 'if-modified-since' : ims },
2412+ ]:
2413+ print (headers )
2414+
2415+ # Request same file with if-modified-since header
2416+ # expect NotModified with same ETag and Last-Modified headers.
2417+ cl .request .headers = headers
2418+ cl .response_code = None
2419+ cl .additional_headers = {}
2420+
2421+ with self .assertRaises (NotModified ) as cm :
2422+ cl .serve_static_file ("style.css" )
2423+
2424+ self .assertEqual (cm .exception .args , ())
2425+
2426+ self .assertEqual (cl .response_code , None )
2427+ self .assertEqual (cl .additional_headers ['ETag' ], inm )
2428+ self .assertEqual (cl .additional_headers ['Last-Modified' ], ims )
2429+
2430+
2431+ ## run two cases that should not return NotModified
2432+ for headers in [
2433+ {},
2434+ {'if-none-match' : "fake" , 'if-modified-since' : "fake" },
2435+ ]:
2436+ cl .request .headers = headers
2437+ cl .response_code = None
2438+ cl .additional_headers = {}
2439+
2440+ cl .serve_static_file ("style.css" )
2441+
2442+ self .assertEqual (cl .response_code , None )
2443+ self .assertEqual (cl .additional_headers ['ETag' ], inm )
2444+ self .assertEqual (cl .additional_headers ['Last-Modified' ], ims )
2445+
2446+ ## test pure cgi case
2447+ # headers attribute does not exist
2448+ cl .request = None
2449+ cl .response_code = None
2450+ cl .additional_headers = {}
2451+
2452+ cl .env ["HTTP_IF_MODIFIED_SINCE" ] = ims
2453+
2454+ with self .assertRaises (NotModified ) as cm :
2455+ cl .serve_static_file ("style.css" )
2456+
2457+ self .assertEqual (cm .exception .args , ())
2458+
2459+ self .assertEqual (cl .response_code , None )
2460+ self .assertEqual (cl .additional_headers ['ETag' ], inm )
2461+ self .assertEqual (cl .additional_headers ['Last-Modified' ], ims )
2462+
23852463 def testserve_static_files (self ):
23862464 # make a client instance
23872465 cl = self ._make_client ({})
@@ -2390,8 +2468,8 @@ def testserve_static_files(self):
23902468
23912469 # hijack _serve_file so I can see what is found
23922470 output = []
2393- def my_serve_file (a , b , c , d ):
2394- output .append ((a ,b ,c ,d ))
2471+ def my_serve_file (a , b , c , d , e ):
2472+ output .append ((a ,b ,c ,d , e ))
23952473 cl ._serve_file = my_serve_file
23962474
23972475 # check case where file is not found.
@@ -2401,8 +2479,9 @@ def my_serve_file(a, b, c, d):
24012479 # TEMPLATES dir is searched by default. So this file exists.
24022480 # Check the returned values.
24032481 cl .serve_static_file ("issue.index.html" )
2404- self .assertEqual (output [0 ][1 ], "text/html" )
2405- self .assertEqual (output [0 ][3 ],
2482+ print (output )
2483+ self .assertEqual (output [0 ][2 ], "text/html" )
2484+ self .assertEqual (output [0 ][4 ],
24062485 normpath ('_test_cgi_form/html/issue.index.html' ))
24072486 del output [0 ] # reset output buffer
24082487
@@ -2415,8 +2494,8 @@ def my_serve_file(a, b, c, d):
24152494 # explicitly allow html directory
24162495 cl .instance .config ['STATIC_FILES' ] = 'html -'
24172496 cl .serve_static_file ("issue.index.html" )
2418- self .assertEqual (output [0 ][1 ], "text/html" )
2419- self .assertEqual (output [0 ][3 ],
2497+ self .assertEqual (output [0 ][2 ], "text/html" )
2498+ self .assertEqual (output [0 ][4 ],
24202499 normpath ('_test_cgi_form/html/issue.index.html' ))
24212500 del output [0 ] # reset output buffer
24222501
@@ -2425,15 +2504,15 @@ def my_serve_file(a, b, c, d):
24252504
24262505 # find file in first directory
24272506 cl .serve_static_file ("messagesummary.py" )
2428- self .assertEqual (output [0 ][1 ], "text/x-python" )
2429- self .assertEqual (output [0 ][3 ],
2507+ self .assertEqual (output [0 ][2 ], "text/x-python" )
2508+ self .assertEqual (output [0 ][4 ],
24302509 normpath ( "_test_cgi_form/detectors/messagesummary.py" ))
24312510 del output [0 ] # reset output buffer
24322511
24332512 # find file in second directory
24342513 cl .serve_static_file ("README.txt" )
2435- self .assertEqual (output [0 ][1 ], "text/plain" )
2436- self .assertEqual (output [0 ][3 ],
2514+ self .assertEqual (output [0 ][2 ], "text/plain" )
2515+ self .assertEqual (output [0 ][4 ],
24372516 normpath ("_test_cgi_form/extensions/README.txt" ))
24382517 del output [0 ] # reset output buffer
24392518
@@ -2448,25 +2527,25 @@ def my_serve_file(a, b, c, d):
24482527 f = open ('_test_cgi_form/detectors/README.txt' , 'a' ).close ()
24492528 # find file now in first directory
24502529 cl .serve_static_file ("README.txt" )
2451- self .assertEqual (output [0 ][1 ], "text/plain" )
2452- self .assertEqual (output [0 ][3 ],
2530+ self .assertEqual (output [0 ][2 ], "text/plain" )
2531+ self .assertEqual (output [0 ][4 ],
24532532 normpath ("_test_cgi_form/detectors/README.txt" ))
24542533 del output [0 ] # reset output buffer
24552534
24562535 cl .instance .config ['STATIC_FILES' ] = ' detectors extensions '
24572536 # make sure lack of trailing - allows searching TEMPLATES
24582537 cl .serve_static_file ("issue.index.html" )
2459- self .assertEqual (output [0 ][1 ], "text/html" )
2460- self .assertEqual (output [0 ][3 ],
2538+ self .assertEqual (output [0 ][2 ], "text/html" )
2539+ self .assertEqual (output [0 ][4 ],
24612540 normpath ("_test_cgi_form/html/issue.index.html" ))
24622541 del output [0 ] # reset output buffer
24632542
24642543 # Make STATIC_FILES a single element.
24652544 cl .instance .config ['STATIC_FILES' ] = 'detectors'
24662545 # find file now in first directory
24672546 cl .serve_static_file ("messagesummary.py" )
2468- self .assertEqual (output [0 ][1 ], "text/x-python" )
2469- self .assertEqual (output [0 ][3 ],
2547+ self .assertEqual (output [0 ][2 ], "text/x-python" )
2548+ self .assertEqual (output [0 ][4 ],
24702549 normpath ("_test_cgi_form/detectors/messagesummary.py" ))
24712550 del output [0 ] # reset output buffer
24722551
@@ -2475,8 +2554,8 @@ def my_serve_file(a, b, c, d):
24752554 f = open ('_test_cgi_form/detectors/css/README.css' , 'a' ).close ()
24762555 # use subdir in filename
24772556 cl .serve_static_file ("css/README.css" )
2478- self .assertEqual (output [0 ][1 ], "text/css" )
2479- self .assertEqual (output [0 ][3 ],
2557+ self .assertEqual (output [0 ][2 ], "text/css" )
2558+ self .assertEqual (output [0 ][4 ],
24802559 normpath ("_test_cgi_form/detectors/css/README.css" ))
24812560 del output [0 ] # reset output buffer
24822561
@@ -2486,18 +2565,19 @@ def my_serve_file(a, b, c, d):
24862565 os .mkdir ('_test_cgi_form/html/css' )
24872566 f = open ('_test_cgi_form/html/css/README1.css' , 'a' ).close ()
24882567 cl .serve_static_file ("README1.css" )
2489- self .assertEqual (output [0 ][1 ], "text/css" )
2490- self .assertEqual (output [0 ][3 ],
2568+ self .assertEqual (output [0 ][2 ], "text/css" )
2569+ self .assertEqual (output [0 ][4 ],
24912570 normpath ("_test_cgi_form/html/css/README1.css" ))
24922571 self .assertTrue ( "Cache-Control" in cl .additional_headers )
24932572 self .assertEqual ( cl .additional_headers ,
24942573 {'Cache-Control' : 'public, max-age=3600' } )
2574+ print (cl .additional_headers )
24952575 del output [0 ] # reset output buffer
24962576
24972577 cl .Cache_Control ['README1.css' ] = 'public, max-age=60'
24982578 cl .serve_static_file ("README1.css" )
2499- self .assertEqual (output [0 ][1 ], "text/css" )
2500- self .assertEqual (output [0 ][3 ],
2579+ self .assertEqual (output [0 ][2 ], "text/css" )
2580+ self .assertEqual (output [0 ][4 ],
25012581 normpath ("_test_cgi_form/html/css/README1.css" ))
25022582 self .assertTrue ( "Cache-Control" in cl .additional_headers )
25032583 self .assertEqual ( cl .additional_headers ,
0 commit comments