forked from s3lph/matemat
Merge branch 'master' into staging-unstable
This commit is contained in:
commit
f423aa579a
3 changed files with 49 additions and 2 deletions
|
@ -323,7 +323,7 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
# Send the HTTP status code
|
# Send the HTTP status code
|
||||||
self.send_response(hsc)
|
self.send_response(hsc)
|
||||||
# Format the session cookie timeout string and send the session cookie header
|
# Format the session cookie timeout string and send the session cookie header
|
||||||
expires = timeout.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
expires = timeout.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
self.send_header('Set-Cookie',
|
self.send_header('Set-Cookie',
|
||||||
f'matemat_session_id={session_id}; expires={expires}')
|
f'matemat_session_id={session_id}; expires={expires}')
|
||||||
# Compute the body length and add the appropriate header
|
# Compute the body length and add the appropriate header
|
||||||
|
@ -345,6 +345,21 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
filepath: str = os.path.abspath(os.path.join(self.server.webroot, path[1:]))
|
filepath: str = os.path.abspath(os.path.join(self.server.webroot, path[1:]))
|
||||||
# Make sure the file is actually inside the webroot directory and that it exists
|
# Make sure the file is actually inside the webroot directory and that it exists
|
||||||
if os.path.commonpath([filepath, self.server.webroot]) == self.server.webroot and os.path.exists(filepath):
|
if os.path.commonpath([filepath, self.server.webroot]) == self.server.webroot and os.path.exists(filepath):
|
||||||
|
# Parse the If-Modified-Since header to check whether the browser can reuse cached content
|
||||||
|
datestr: str = self.headers.get('If-Modified-Since', 'Thu, 01 Jan 1970 00:00:00 GMT')
|
||||||
|
maxage: datetime = datetime.strptime(datestr, '%a, %d %b %Y %H:%M:%S %Z')
|
||||||
|
# Get file modification time
|
||||||
|
filestat: int = int(os.path.getmtime(filepath))
|
||||||
|
# Create UTC datetime object from mtime
|
||||||
|
fileage: datetime = datetime.utcfromtimestamp(filestat)
|
||||||
|
|
||||||
|
# If the file has not been replaced by a newer version than requested by the client, send a 304 response
|
||||||
|
if fileage <= maxage:
|
||||||
|
self.send_response(304, 'Not Modified')
|
||||||
|
self.send_header('Content-Length', '0')
|
||||||
|
self.end_headers()
|
||||||
|
return
|
||||||
|
|
||||||
# Open and read the file
|
# Open and read the file
|
||||||
with open(filepath, 'rb') as f:
|
with open(filepath, 'rb') as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
|
@ -358,6 +373,8 @@ class HttpHandler(BaseHTTPRequestHandler):
|
||||||
# Send content type and length header
|
# Send content type and length header
|
||||||
self.send_header('Content-Type', mimetype)
|
self.send_header('Content-Type', mimetype)
|
||||||
self.send_header('Content-Length', str(len(data)))
|
self.send_header('Content-Length', str(len(data)))
|
||||||
|
self.send_header('Last-Modified', fileage.strftime('%a, %d %b %Y %H:%M:%S GMT'))
|
||||||
|
self.send_header('Cache-Control', 'max-age=1')
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
# Send the requested resource as response body
|
# Send the requested resource as response body
|
||||||
self.wfile.write(data)
|
self.wfile.write(data)
|
||||||
|
|
|
@ -118,7 +118,7 @@ class MockServer:
|
||||||
)
|
)
|
||||||
# Set up logger
|
# Set up logger
|
||||||
self.logger: logging.Logger = logging.getLogger('matemat unit test')
|
self.logger: logging.Logger = logging.getLogger('matemat unit test')
|
||||||
self.logger.setLevel(0)
|
self.logger.setLevel(logging.DEBUG)
|
||||||
# Initalize a log handler to stderr and set the log format
|
# Initalize a log handler to stderr and set the log format
|
||||||
sh: logging.StreamHandler = logging.StreamHandler()
|
sh: logging.StreamHandler = logging.StreamHandler()
|
||||||
sh.setFormatter(logging.Formatter('%(asctime)s %(name)s [%(levelname)s]: %(message)s'))
|
sh.setFormatter(logging.Formatter('%(asctime)s %(name)s [%(levelname)s]: %(message)s'))
|
||||||
|
|
|
@ -3,6 +3,8 @@ from typing import Any, Dict, Union
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from matemat.exceptions import HttpException
|
from matemat.exceptions import HttpException
|
||||||
from matemat.webserver import HttpHandler, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse
|
from matemat.webserver import HttpHandler, RequestArguments, PageletResponse, RedirectResponse, TemplateResponse
|
||||||
from matemat.webserver.test.abstract_httpd_test import AbstractHttpdTest, test_pagelet
|
from matemat.webserver.test.abstract_httpd_test import AbstractHttpdTest, test_pagelet
|
||||||
|
@ -163,6 +165,34 @@ class TestServe(AbstractHttpdTest):
|
||||||
self.assertEqual(403, packet.statuscode)
|
self.assertEqual(403, packet.statuscode)
|
||||||
self.assertNotEqual(b'This should not be readable', packet.body)
|
self.assertNotEqual(b'This should not be readable', packet.body)
|
||||||
|
|
||||||
|
def test_serve_static_cache(self):
|
||||||
|
# Request a static resource
|
||||||
|
timeout: datetime = datetime.utcnow() + timedelta(hours=1)
|
||||||
|
timeoutstr = timeout.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
|
self.client_sock.set_request(
|
||||||
|
f'GET /static_resource.txt HTTP/1.1\r\nIf-Modified-Since: {timeoutstr}\r\n\r\n'.encode('utf-8'))
|
||||||
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
||||||
|
packet = self.client_sock.get_response()
|
||||||
|
|
||||||
|
# Make sure that no pagelet was called
|
||||||
|
self.assertIsNone(packet.pagelet)
|
||||||
|
# Make sure a 304 Not Modified is sent and the body is empty
|
||||||
|
self.assertEqual(304, packet.statuscode)
|
||||||
|
self.assertEqual(0, len(packet.body))
|
||||||
|
|
||||||
|
def test_serve_static_cache_renew(self):
|
||||||
|
# Request a static resource
|
||||||
|
self.client_sock.set_request(
|
||||||
|
b'GET /static_resource.txt HTTP/1.1\r\nIf-Modified-Since: Mon, 01 Jan 2018 13:37:42 GMT\r\n\r\n')
|
||||||
|
HttpHandler(self.client_sock, ('::1', 45678), self.server)
|
||||||
|
packet = self.client_sock.get_response()
|
||||||
|
|
||||||
|
# Make sure that no pagelet was called
|
||||||
|
self.assertIsNone(packet.pagelet)
|
||||||
|
# Make sure the expected content is served
|
||||||
|
self.assertEqual(200, packet.statuscode)
|
||||||
|
self.assertEqual(b'static resource test', packet.body)
|
||||||
|
|
||||||
def test_serve_not_found(self):
|
def test_serve_not_found(self):
|
||||||
# Request a nonexistent resource
|
# Request a nonexistent resource
|
||||||
self.client_sock.set_request(b'GET /nonexistent HTTP/1.1\r\n\r\n')
|
self.client_sock.set_request(b'GET /nonexistent HTTP/1.1\r\n\r\n')
|
||||||
|
|
Loading…
Reference in a new issue