1717import urllib .parse
1818import html
1919import http .client
20+ import email .message
21+ import email .utils
2022import tempfile
2123import time
24+ import datetime
2225from io import BytesIO
2326
2427import unittest
@@ -333,6 +336,13 @@ def setUp(self):
333336 self .base_url = '/' + self .tempdir_name
334337 with open (os .path .join (self .tempdir , 'test' ), 'wb' ) as temp :
335338 temp .write (self .data )
339+ mtime = os .fstat (temp .fileno ()).st_mtime
340+ # compute last modification datetime for browser cache tests
341+ last_modif = datetime .datetime .fromtimestamp (mtime ,
342+ datetime .timezone .utc )
343+ self .last_modif_datetime = last_modif .replace (microsecond = 0 )
344+ self .last_modif_header = email .utils .formatdate (
345+ last_modif .timestamp (), usegmt = True )
336346
337347 def tearDown (self ):
338348 try :
@@ -445,43 +455,42 @@ def test_head(self):
445455 'application/octet-stream' )
446456
447457 def test_browser_cache (self ):
448- #constructs the path relative to the root directory of the HTTPServer
449- response = self .request (self .base_url + '/test' )
450- self .check_status_and_reason (response , HTTPStatus .OK , data = self .data )
451- last_modif = response .headers ['Last-modified' ]
452-
453- # send new request to the same url with request header
454- # If-Modified-Since set to Last-Modified : must return 304
455- from email .message import Message
456- headers = Message ()
457- headers ['If-Modified-Since' ] = last_modif
458+ """Check that when a request to /test is sent with the request header
459+ If-Modified-Since set to date of last modification, the server returns
460+ status code 304, not 200
461+ """
462+ headers = email .message .Message ()
463+ headers ['If-Modified-Since' ] = self .last_modif_header
458464 response = self .request (self .base_url + '/test' , headers = headers )
459465 self .check_status_and_reason (response , HTTPStatus .NOT_MODIFIED )
460466
461- # if If-None-Match header is present, ignore If-Modified-Since
462- headers ['If-None-Match' ] = "*"
467+ # one hour after last modification : must return 304
468+ new_dt = self .last_modif_datetime + datetime .timedelta (hours = 1 )
469+ headers = email .message .Message ()
470+ headers ['If-Modified-Since' ] = email .utils .format_datetime (new_dt ,
471+ usegmt = True )
463472 response = self .request (self .base_url + '/test' , headers = headers )
464- self .check_status_and_reason (response , HTTPStatus .OK )
473+ self .check_status_and_reason (response , HTTPStatus .NOT_MODIFIED )
465474
475+ def test_browser_cache_file_changed (self ):
466476 # with If-Modified-Since earlier than Last-Modified, must return 200
467- import datetime
468- import email .utils
469- dt = email .utils .parsedate_to_datetime (last_modif )
477+ dt = self .last_modif_datetime
470478 # build datetime object : 365 days before last modification
471479 old_dt = dt - datetime .timedelta (days = 365 )
472- headers = Message ()
480+ headers = email . message . Message ()
473481 headers ['If-Modified-Since' ] = email .utils .format_datetime (old_dt ,
474482 usegmt = True )
475483 response = self .request (self .base_url + '/test' , headers = headers )
476484 self .check_status_and_reason (response , HTTPStatus .OK )
477485
478- # one hour after last modification : must return 304
479- new_dt = dt + datetime .timedelta (hours = 1 )
480- headers = Message ()
481- headers ['If-Modified-Since' ] = email .utils .format_datetime (new_dt ,
482- usegmt = True )
486+ def test_browser_cache_with_If_None_Match_header (self ):
487+ # if If-None-Match header is present, ignore If-Modified-Since
488+
489+ headers = email .message .Message ()
490+ headers ['If-Modified-Since' ] = self .last_modif_header
491+ headers ['If-None-Match' ] = "*"
483492 response = self .request (self .base_url + '/test' , headers = headers )
484- self .check_status_and_reason (response , HTTPStatus .NOT_MODIFIED )
493+ self .check_status_and_reason (response , HTTPStatus .OK )
485494
486495 def test_invalid_requests (self ):
487496 response = self .request ('/' , method = 'FOO' )
@@ -492,6 +501,15 @@ def test_invalid_requests(self):
492501 response = self .request ('/' , method = 'GETs' )
493502 self .check_status_and_reason (response , HTTPStatus .NOT_IMPLEMENTED )
494503
504+ def test_last_modified (self ):
505+ """Checks that the datetime returned in Last-Modified response header
506+ is the actual datetime of last modification, rounded to the second
507+ """
508+ response = self .request (self .base_url + '/test' )
509+ self .check_status_and_reason (response , HTTPStatus .OK , data = self .data )
510+ last_modif_header = response .headers ['Last-modified' ]
511+ self .assertEqual (last_modif_header , self .last_modif_header )
512+
495513 def test_path_without_leading_slash (self ):
496514 response = self .request (self .tempdir_name + '/test' )
497515 self .check_status_and_reason (response , HTTPStatus .OK , data = self .data )
0 commit comments