Commit e4cc32f3 authored by Vincent Pelletier's avatar Vincent Pelletier

wsgi: Make response headers RFC7231-compliant.

- 405 (Method Not Allowed) response contains the list of methods allowed on
  current resource
- all responses contain a Date header
parent 9429da8f
...@@ -1778,10 +1778,21 @@ class CaucaseTest(unittest.TestCase): ...@@ -1778,10 +1778,21 @@ class CaucaseTest(unittest.TestCase):
'PATH_INFO': '/cau/crl/123', 'PATH_INFO': '/cau/crl/123',
'REQUEST_METHOD': 'GET', 'REQUEST_METHOD': 'GET',
})[0], 404) })[0], 404)
self.assertEqual(request({
min_date = round(time.time())
status, _, header_dict, _ = request({
'PATH_INFO': '/cau/crl', 'PATH_INFO': '/cau/crl',
'REQUEST_METHOD': 'PUT', 'REQUEST_METHOD': 'PUT',
})[0], 405) })
max_date = round(time.time())
self.assertEqual(status, 405)
self.assertItemsEqual(
[x.strip() for x in header_dict['Allow'].split(',')],
['GET', 'OPTIONS'],
)
response_date = utils.IMFfixdate2timestamp(header_dict['Date'])
self.assertGreaterEqual(response_date, min_date)
self.assertLessEqual(response_date, max_date)
self.assertEqual(request({ self.assertEqual(request({
'PATH_INFO': '/cau/csr/123/456', 'PATH_INFO': '/cau/csr/123/456',
......
...@@ -22,8 +22,10 @@ Small-ish functions needed in many places. ...@@ -22,8 +22,10 @@ Small-ish functions needed in many places.
""" """
from __future__ import absolute_import, print_function from __future__ import absolute_import, print_function
from binascii import a2b_base64, b2a_base64 from binascii import a2b_base64, b2a_base64
import calendar
from collections import defaultdict from collections import defaultdict
import datetime import datetime
import email
import json import json
import os import os
import threading import threading
...@@ -443,6 +445,25 @@ def datetime2timestamp(value): ...@@ -443,6 +445,25 @@ def datetime2timestamp(value):
""" """
return (value - EPOCH).total_seconds() return (value - EPOCH).total_seconds()
def timestamp2IMFfixdate(value):
"""
Convert a timestamp into an IMF-fixdate string following RFC7231.
"""
return email.utils.formatdate(
value,
localtime=False,
usegmt=True,
)
def IMFfixdate2timestamp(value):
"""
Convert an IMF-fixdate string following RFC7231 into a timestamp.
"""
result = email.utils.parsedate(value)
if result is None:
return None
return calendar.timegm(result)
class SleepInterrupt(KeyboardInterrupt): class SleepInterrupt(KeyboardInterrupt):
""" """
A sleep was interrupted by a KeyboardInterrupt A sleep was interrupted by a KeyboardInterrupt
......
...@@ -147,6 +147,12 @@ class BadMethod(ApplicationError): ...@@ -147,6 +147,12 @@ class BadMethod(ApplicationError):
""" """
status = _getStatus(httplib.METHOD_NOT_ALLOWED) status = _getStatus(httplib.METHOD_NOT_ALLOWED)
def __init__(self, allowed_list):
super(BadMethod, self).__init__(allowed_list)
self._response_headers = [
('Allow', ', '.join(allowed_list)),
]
class Conflict(ApplicationError): class Conflict(ApplicationError):
""" """
HTTP conflict HTTP conflict
...@@ -543,7 +549,7 @@ class Application(object): ...@@ -543,7 +549,7 @@ class Application(object):
# CORS headers added, add more # CORS headers added, add more
self._optionAddCORSHeaders(method_dict, cors_header_list) self._optionAddCORSHeaders(method_dict, cors_header_list)
else: else:
raise BadMethod raise BadMethod(method_dict.keys() + ['OPTIONS'])
else: else:
subpath = action_dict.get('subpath', SUBPATH_FORBIDDEN) subpath = action_dict.get('subpath', SUBPATH_FORBIDDEN)
if ( if (
...@@ -592,6 +598,7 @@ class Application(object): ...@@ -592,6 +598,7 @@ class Application(object):
# Note: header_list and cors_header_list are expected to contain # Note: header_list and cors_header_list are expected to contain
# distinct header sets. This may not always stay true for "Vary". # distinct header sets. This may not always stay true for "Vary".
header_list.extend(cors_header_list) header_list.extend(cors_header_list)
header_list.append(('Date', utils.timestamp2IMFfixdate(time.time())))
start_response(status, header_list) start_response(status, header_list)
return result return result
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment