From 0221d1ad2042333baa47f954433552b6dd6f605e Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Thu, 30 Aug 2018 08:34:37 -0500 Subject: [PATCH] Introduce and use locale-naive rfc2822 date format function (#44868) * Introduce and use locale-naive rfc2822 date format function. Fixes #44857 * Adjust test expected response --- .../fragments/urls-if-modified-since.yaml | 2 ++ lib/ansible/module_utils/urls.py | 19 ++++++++++++++++++- lib/ansible/modules/net_tools/basics/uri.py | 7 +++---- test/units/module_utils/urls/test_Request.py | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/urls-if-modified-since.yaml diff --git a/changelogs/fragments/urls-if-modified-since.yaml b/changelogs/fragments/urls-if-modified-since.yaml new file mode 100644 index 00000000000..f2ecfb62730 --- /dev/null +++ b/changelogs/fragments/urls-if-modified-since.yaml @@ -0,0 +1,2 @@ +bugfixes: +- get_url / uri - Use custom rfc2822 date format function instead of locale specific strftime (https://github.com/ansible/ansible/issues/44857) diff --git a/lib/ansible/module_utils/urls.py b/lib/ansible/module_utils/urls.py index 4c145b4d69d..9434778e1fb 100644 --- a/lib/ansible/module_utils/urls.py +++ b/lib/ansible/module_utils/urls.py @@ -822,6 +822,23 @@ def maybe_add_ssl_handler(url, validate_certs): return SSLValidationHandler(hostname, port) +def rfc2822_date_string(timetuple, zone='-0000'): + """Accepts a timetuple and optional zone which defaults to ``-0000`` + and returns a date string as specified by RFC 2822, e.g.: + + Fri, 09 Nov 2001 01:08:47 -0000 + + Copied from email.utils.formatdate and modified for separate use + """ + return '%s, %02d %s %04d %02d:%02d:%02d %s' % ( + ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][timetuple[6]], + timetuple[2], + ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][timetuple[1] - 1], + timetuple[0], timetuple[3], timetuple[4], timetuple[5], + zone) + + class Request: def __init__(self, headers=None, use_proxy=True, force=False, timeout=10, validate_certs=True, url_username=None, url_password=None, http_agent=None, force_basic_auth=False, @@ -1037,7 +1054,7 @@ class Request: request.add_header('cache-control', 'no-cache') # or we do it if the original is more recent than our copy elif last_mod_time: - tstamp = last_mod_time.strftime('%a, %d %b %Y %H:%M:%S +0000') + tstamp = rfc2822_date_string(last_mod_time.timetuple()) request.add_header('If-Modified-Since', tstamp) # user defined headers now, which may override things we've set above diff --git a/lib/ansible/modules/net_tools/basics/uri.py b/lib/ansible/modules/net_tools/basics/uri.py index dc4a3318058..cad7b998b60 100644 --- a/lib/ansible/modules/net_tools/basics/uri.py +++ b/lib/ansible/modules/net_tools/basics/uri.py @@ -405,6 +405,7 @@ def uri(module, url, dest, body, body_format, method, headers, socket_timeout): else: data = body + kwargs = {} if dest is not None: # Stash follow_redirects, in this block we don't want to follow # we'll reset back to the supplied value soon @@ -424,15 +425,13 @@ def uri(module, url, dest, body, body_format, method, headers, socket_timeout): dest = os.path.join(dest, url_filename(url)) # if destination file already exist, only download if file newer if os.path.exists(dest): - t = datetime.datetime.utcfromtimestamp(os.path.getmtime(dest)) - tstamp = t.strftime('%a, %d %b %Y %H:%M:%S +0000') - headers['If-Modified-Since'] = tstamp + kwargs['last_mod_time'] = datetime.datetime.utcfromtimestamp(os.path.getmtime(dest)) # Reset follow_redirects back to the stashed value module.params['follow_redirects'] = follow_redirects resp, info = fetch_url(module, url, data=data, headers=headers, - method=method, timeout=socket_timeout) + method=method, timeout=socket_timeout, **kwargs) try: content = resp.read() diff --git a/test/units/module_utils/urls/test_Request.py b/test/units/module_utils/urls/test_Request.py index e6b23b5b7c0..aad4de4b404 100644 --- a/test/units/module_utils/urls/test_Request.py +++ b/test/units/module_utils/urls/test_Request.py @@ -362,7 +362,7 @@ def test_Request_open_last_mod(urlopen_mock, install_opener_mock): args = urlopen_mock.call_args[0] req = args[0] - assert req.headers.get('If-modified-since') == now.strftime('%a, %d %b %Y %H:%M:%S +0000') + assert req.headers.get('If-modified-since') == now.strftime('%a, %d %b %Y %H:%M:%S -0000') def test_Request_open_headers_not_dict(urlopen_mock, install_opener_mock):