[Python-checkins] [3.9] bpo-5054: CGIHTTPRequestHandler.run_cgi() HTTP_ACCEPT improperly parsed (GH-23638) (GH-23657)

miss-islington webhook-mailer at python.org
Sat Dec 5 10:26:45 EST 2020


https://github.com/python/cpython/commit/b630ca7bc13ba9bdf95cd7dce0ac8e1578fb53a0
commit: b630ca7bc13ba9bdf95cd7dce0ac8e1578fb53a0
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2020-12-05T07:26:37-08:00
summary:

[3.9] bpo-5054: CGIHTTPRequestHandler.run_cgi() HTTP_ACCEPT improperly parsed (GH-23638) (GH-23657)



(cherry picked from commit da3d2abe6be9fcf18cac12ec5d7d9f1180d94b5e)


Co-authored-by: Senthil Kumaran <senthil at uthcode.com>

Automerge-Triggered-By: GH:orsenthil

files:
A Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst
M Lib/http/server.py
M Lib/test/test_httpservers.py

diff --git a/Lib/http/server.py b/Lib/http/server.py
index fa204fbc15e3d..def05f46be4f9 100644
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -1123,12 +1123,7 @@ def run_cgi(self):
         referer = self.headers.get('referer')
         if referer:
             env['HTTP_REFERER'] = referer
-        accept = []
-        for line in self.headers.getallmatchingheaders('accept'):
-            if line[:1] in "\t\n\r ":
-                accept.append(line.strip())
-            else:
-                accept = accept + line[7:].split(',')
+        accept = self.headers.get_all('accept', ())
         env['HTTP_ACCEPT'] = ','.join(accept)
         ua = self.headers.get('user-agent')
         if ua:
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
index c442f5571a868..8df0b5251f1ae 100644
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -3,7 +3,7 @@
 Written by Cody A.W. Somerville <cody-somerville at ubuntu.com>,
 Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
 """
-
+from collections import OrderedDict
 from http.server import BaseHTTPRequestHandler, HTTPServer, \
      SimpleHTTPRequestHandler, CGIHTTPRequestHandler
 from http import server, HTTPStatus
@@ -19,7 +19,7 @@
 import email.message
 import email.utils
 import html
-import http.client
+import http, http.client
 import urllib.parse
 import tempfile
 import time
@@ -586,6 +586,15 @@ def test_html_escape_filename(self):
 print(os.environ["%s"])
 """
 
+cgi_file6 = """\
+#!%s
+import os
+
+print("Content-type: text/plain")
+print()
+print(repr(os.environ))
+"""
+
 
 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
         "This test can't be run reliably as root (issue #13308).")
@@ -664,6 +673,11 @@ def setUp(self):
             file5.write(cgi_file1 % self.pythonexe)
         os.chmod(self.file5_path, 0o777)
 
+        self.file6_path = os.path.join(self.cgi_dir, 'file6.py')
+        with open(self.file6_path, 'w', encoding='utf-8') as file6:
+            file6.write(cgi_file6 % self.pythonexe)
+        os.chmod(self.file6_path, 0o777)
+
         os.chdir(self.parent_dir)
 
     def tearDown(self):
@@ -683,6 +697,8 @@ def tearDown(self):
                 os.remove(self.file4_path)
             if self.file5_path:
                 os.remove(self.file5_path)
+            if self.file6_path:
+                os.remove(self.file6_path)
             os.rmdir(self.cgi_child_dir)
             os.rmdir(self.cgi_dir)
             os.rmdir(self.cgi_dir_in_sub_dir)
@@ -816,6 +832,23 @@ def test_cgi_path_in_sub_directories(self):
         finally:
             CGIHTTPRequestHandler.cgi_directories.remove('/sub/dir/cgi-bin')
 
+    def test_accept(self):
+        browser_accept = \
+                    'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
+        tests = (
+            ((('Accept', browser_accept),), browser_accept),
+            ((), ''),
+            # Hack case to get two values for the one header
+            ((('Accept', 'text/html'), ('ACCEPT', 'text/plain')),
+               'text/html,text/plain'),
+        )
+        for headers, expected in tests:
+            headers = OrderedDict(headers)
+            with self.subTest(headers):
+                res = self.request('/cgi-bin/file6.py', 'GET', headers=headers)
+                self.assertEqual(http.HTTPStatus.OK, res.status)
+                expected = f"'HTTP_ACCEPT': {expected!r}"
+                self.assertIn(expected.encode('ascii'), res.read())
 
 
 class SocketlessRequestHandler(SimpleHTTPRequestHandler):
diff --git a/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst b/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst
new file mode 100644
index 0000000000000..ad8163c7c1d20
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-12-04-03-51-12.bpo-5054.53StYZ.rst
@@ -0,0 +1,5 @@
+CGIHTTPRequestHandler.run_cgi() HTTP_ACCEPT improperly parsed. Replace the
+special purpose getallmatchingheaders with generic get_all method and add
+relevant tests.
+
+Original Patch by Martin Panter. Modified by Senthil Kumaran.



More information about the Python-checkins mailing list