Repository: tornadoweb/tornado
Pull request #2778 (2019-11-21 19:59:23)

Update hashing algorithm in StaticFileHandler
Addresses #2776.

Some quick testing shows that SHA1 is somewhat faster than MD5 on
newer versions of Python:

```python
import hashlib
import secrets

data = secrets.token_bytes(1024 * 10000)
```

Using Jupyter's `%%timeit` magic:

```
%%timeit
hasher = hashlib.md5()
hasher.update(data)
hasher.hexdigest()
```
Example output: `12.5 ms ± 345 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)`

```
%%timeit
hasher = hashlib.sha1()
hasher.update(data)
hasher.hexdigest()
```
Example output: `8.94 ms ± 306 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)`


Patch:
diff --git a/.travis.yml b/.travis.yml
index 374bd564..d7ce8e6f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,8 @@ jobs:
     # "provisional feature" rules there are significant differences between patch
     # versions for asyncio and typing.
     - python: 3.5.2
-      env: TOX_ENV=py35-full
+      # Twisted doesn't install on python 3.5.2, so don't run the "full" tests.
+      env: TOX_ENV=py35
     - python: '3.5'
       env: TOX_ENV=py35-full
     - python: '3.6'
diff --git a/tornado/speedups.c b/tornado/speedups.c
index b714268a..525d6603 100644
--- a/tornado/speedups.c
+++ b/tornado/speedups.c
@@ -56,7 +56,6 @@ static PyMethodDef methods[] = {
     {NULL, NULL, 0, NULL}
 };
 
-#if PY_MAJOR_VERSION >= 3
 static struct PyModuleDef speedupsmodule = {
    PyModuleDef_HEAD_INIT,
    "speedups",
@@ -69,9 +68,3 @@ PyMODINIT_FUNC
 PyInit_speedups(void) {
     return PyModule_Create(&speedupsmodule);
 }
-#else  // Python 2.x
-PyMODINIT_FUNC
-initspeedups(void) {
-    Py_InitModule("tornado.speedups", methods);
-}
-#endif
diff --git a/tornado/web.py b/tornado/web.py
index 3fc99fb8..a3a8f61c 100644
--- a/tornado/web.py
+++ b/tornado/web.py
@@ -2822,12 +2822,12 @@ class StaticFileHandler(RequestHandler):
         """Returns a version string for the resource at the given path.
 
         This class method may be overridden by subclasses.  The
-        default implementation is a hash of the file's contents.
+        default implementation is a SHA-512 hash of the file's contents.
 
         .. versionadded:: 3.1
         """
         data = cls.get_content(abspath)
-        hasher = hashlib.md5()
+        hasher = hashlib.sha512()
         if isinstance(data, bytes):
             hasher.update(data)
         else:


Test patch:
diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py
index 7c1322e0..9e6c15bf 100644
--- a/tornado/test/web_test.py
+++ b/tornado/test/web_test.py
@@ -1052,9 +1052,12 @@ class ErrorResponseTest(WebTestCase):
 
 
 class StaticFileTest(WebTestCase):
-    # The expected MD5 hash of robots.txt, used in tests that call
+    # The expected SHA-512 hash of robots.txt, used in tests that call
     # StaticFileHandler.get_version
-    robots_txt_hash = b"f71d20196d4caf35b6a670db8c70b03d"
+    robots_txt_hash = (
+        b"63a36e950e134b5217e33c763e88840c10a07d80e6057d92b9ac97508de7fb1f"
+        b"a6f0e9b7531e169657165ea764e8963399cb6d921ffe6078425aaafe54c04563"
+    )
     static_dir = os.path.join(os.path.dirname(__file__), "static")
 
     def get_handlers(self):