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):
'PATH_INFO': '/cau/crl/123',
'REQUEST_METHOD': 'GET',
})[0], 404)
self.assertEqual(request({
min_date = round(time.time())
status, _, header_dict, _ = request({
'PATH_INFO': '/cau/crl',
'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({
'PATH_INFO': '/cau/csr/123/456',
......
......@@ -22,8 +22,10 @@ Small-ish functions needed in many places.
"""
from __future__ import absolute_import, print_function
from binascii import a2b_base64, b2a_base64
import calendar
from collections import defaultdict
import datetime
import email
import json
import os
import threading
......@@ -443,6 +445,25 @@ def datetime2timestamp(value):
"""
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):
"""
A sleep was interrupted by a KeyboardInterrupt
......
......@@ -147,6 +147,12 @@ class BadMethod(ApplicationError):
"""
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):
"""
HTTP conflict
......@@ -543,7 +549,7 @@ class Application(object):
# CORS headers added, add more
self._optionAddCORSHeaders(method_dict, cors_header_list)
else:
raise BadMethod
raise BadMethod(method_dict.keys() + ['OPTIONS'])
else:
subpath = action_dict.get('subpath', SUBPATH_FORBIDDEN)
if (
......@@ -592,6 +598,7 @@ class Application(object):
# Note: header_list and cors_header_list are expected to contain
# distinct header sets. This may not always stay true for "Vary".
header_list.extend(cors_header_list)
header_list.append(('Date', utils.timestamp2IMFfixdate(time.time())))
start_response(status, header_list)
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