From 17481d85242e5230a3416f66ab9c1b8320958a8c Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Wed, 19 Apr 2017 21:44:04 +0900 Subject: [PATCH] Send If-modified-since header on downloading images --- sphinx/transforms/post_transforms/images.py | 16 ++++++++++++++-- sphinx/util/__init__.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/sphinx/transforms/post_transforms/images.py b/sphinx/transforms/post_transforms/images.py index d2c6cbe25..b8b05715d 100644 --- a/sphinx/transforms/post_transforms/images.py +++ b/sphinx/transforms/post_transforms/images.py @@ -10,6 +10,7 @@ """ import os +from math import ceil from hashlib import sha1 from six import text_type @@ -17,6 +18,7 @@ from docutils import nodes from sphinx.transforms import SphinxTransform from sphinx.util import logging, requests +from sphinx.util import epoch_to_rfc1123, rfc1123_to_epoch from sphinx.util.images import guess_mimetype, get_image_extension, parse_data_uri from sphinx.util.osutil import ensuredir @@ -70,8 +72,13 @@ class ImageDownloader(BaseImageConverter): ensuredir(os.path.join(self.imagedir, dirname)) path = os.path.join(self.imagedir, dirname, basename) try: - r = requests.get(node['uri']) - if r.status_code != 200: + headers = {} + if os.path.exists(path): + timestamp = ceil(os.stat(path).st_mtime) + headers['If-Modified-Since'] = epoch_to_rfc1123(timestamp) + + r = requests.get(node['uri'], headers=headers) + if r.status_code >= 400: logger.warning('Could not fetch remote image: %s [%d]' % (node['uri'], r.status_code)) else: @@ -80,6 +87,11 @@ class ImageDownloader(BaseImageConverter): with open(path, 'wb') as f: f.write(r.content) + last_modified = r.headers.get('last-modified') + if last_modified: + timestamp = rfc1123_to_epoch(last_modified) + os.utime(path, (timestamp, timestamp)) + mimetype = guess_mimetype(path, default='*') node['candidates'].pop('?') node['candidates'][mimetype] = path diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index bb6c58919..8064bc68a 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -19,12 +19,15 @@ import posixpath import traceback import unicodedata from os import path +from time import mktime, strptime from codecs import BOM_UTF8 +from datetime import datetime from collections import deque from six import text_type, binary_type, itervalues from six.moves import range from six.moves.urllib.parse import urlsplit, urlunsplit, quote_plus, parse_qsl, urlencode +from babel.dates import format_datetime from docutils.utils import relative_path from sphinx.errors import PycodeError, SphinxParallelError, ExtensionError @@ -615,3 +618,14 @@ def status_iterator(iterable, summary, color="darkgreen", length=0, verbosity=0, yield item if l > 0: logger.info('') + + +def epoch_to_rfc1123(epoch): + """Convert datetime format epoch to RFC1123.""" + dt = datetime.fromtimestamp(epoch) + fmt = 'EEE, dd LLL yyyy hh:mm:ss' + return format_datetime(dt, fmt, locale='en') + ' GMT' + + +def rfc1123_to_epoch(rfc1123): + return mktime(strptime(rfc1123, '%a, %d %b %Y %H:%M:%S %Z'))