bpo-29654 : Support If-Modified-Since HTTP header (browser cache) (#298)

Return 304 response if file was not modified.
diff --git a/Lib/http/server.py b/Lib/http/server.py
index 61ddecc..429490b 100644
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -87,6 +87,9 @@
     "SimpleHTTPRequestHandler", "CGIHTTPRequestHandler",
 ]
 
+import argparse
+import copy
+import datetime
 import email.utils
 import html
 import http.client
@@ -101,8 +104,6 @@
 import sys
 import time
 import urllib.parse
-import copy
-import argparse
 
 from http import HTTPStatus
 
@@ -686,12 +687,42 @@
         except OSError:
             self.send_error(HTTPStatus.NOT_FOUND, "File not found")
             return None
+
         try:
+            fs = os.fstat(f.fileno())
+            # Use browser cache if possible
+            if ("If-Modified-Since" in self.headers
+                    and "If-None-Match" not in self.headers):
+                # compare If-Modified-Since and time of last file modification
+                try:
+                    ims = email.utils.parsedate_to_datetime(
+                        self.headers["If-Modified-Since"])
+                except (TypeError, IndexError, OverflowError, ValueError):
+                    # ignore ill-formed values
+                    pass
+                else:
+                    if ims.tzinfo is None:
+                        # obsolete format with no timezone, cf.
+                        # https://tools.ietf.org/html/rfc7231#section-7.1.1.1
+                        ims = ims.replace(tzinfo=datetime.timezone.utc)
+                    if ims.tzinfo is datetime.timezone.utc:
+                        # compare to UTC datetime of last modification
+                        last_modif = datetime.datetime.fromtimestamp(
+                            fs.st_mtime, datetime.timezone.utc)
+                        # remove microseconds, like in If-Modified-Since
+                        last_modif = last_modif.replace(microsecond=0)
+                        
+                        if last_modif <= ims:
+                            self.send_response(HTTPStatus.NOT_MODIFIED)
+                            self.end_headers()
+                            f.close()
+                            return None
+
             self.send_response(HTTPStatus.OK)
             self.send_header("Content-type", ctype)
-            fs = os.fstat(f.fileno())
             self.send_header("Content-Length", str(fs[6]))
-            self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
+            self.send_header("Last-Modified", 
+                self.date_time_string(fs.st_mtime))
             self.end_headers()
             return f
         except: