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

(cherry picked from commit da3d2abe6b)


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

Automerge-Triggered-By: GH:orsenthil
This commit is contained in:
Miss Islington (bot) 2020-12-05 07:26:37 -08:00 committed by GitHub
parent 06002b3f0d
commit b630ca7bc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 8 deletions

View file

@ -1123,12 +1123,7 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
referer = self.headers.get('referer') referer = self.headers.get('referer')
if referer: if referer:
env['HTTP_REFERER'] = referer env['HTTP_REFERER'] = referer
accept = [] accept = self.headers.get_all('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(',')
env['HTTP_ACCEPT'] = ','.join(accept) env['HTTP_ACCEPT'] = ','.join(accept)
ua = self.headers.get('user-agent') ua = self.headers.get('user-agent')
if ua: if ua:

View file

@ -3,7 +3,7 @@
Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>, Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>,
Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest. Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
""" """
from collections import OrderedDict
from http.server import BaseHTTPRequestHandler, HTTPServer, \ from http.server import BaseHTTPRequestHandler, HTTPServer, \
SimpleHTTPRequestHandler, CGIHTTPRequestHandler SimpleHTTPRequestHandler, CGIHTTPRequestHandler
from http import server, HTTPStatus from http import server, HTTPStatus
@ -19,7 +19,7 @@ import shutil
import email.message import email.message
import email.utils import email.utils
import html import html
import http.client import http, http.client
import urllib.parse import urllib.parse
import tempfile import tempfile
import time import time
@ -586,6 +586,15 @@ print()
print(os.environ["%s"]) 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, @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
"This test can't be run reliably as root (issue #13308).") "This test can't be run reliably as root (issue #13308).")
@ -664,6 +673,11 @@ class CGIHTTPServerTestCase(BaseTestCase):
file5.write(cgi_file1 % self.pythonexe) file5.write(cgi_file1 % self.pythonexe)
os.chmod(self.file5_path, 0o777) 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) os.chdir(self.parent_dir)
def tearDown(self): def tearDown(self):
@ -683,6 +697,8 @@ class CGIHTTPServerTestCase(BaseTestCase):
os.remove(self.file4_path) os.remove(self.file4_path)
if self.file5_path: if self.file5_path:
os.remove(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_child_dir)
os.rmdir(self.cgi_dir) os.rmdir(self.cgi_dir)
os.rmdir(self.cgi_dir_in_sub_dir) os.rmdir(self.cgi_dir_in_sub_dir)
@ -816,6 +832,23 @@ class CGIHTTPServerTestCase(BaseTestCase):
finally: finally:
CGIHTTPRequestHandler.cgi_directories.remove('/sub/dir/cgi-bin') 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): class SocketlessRequestHandler(SimpleHTTPRequestHandler):

View file

@ -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.