Skip to content

Commit 74e26ae

Browse files
committed
Minor simplifications in FieldStorage
1 parent 45c8453 commit 74e26ae

File tree

2 files changed

+29
-18
lines changed

2 files changed

+29
-18
lines changed

webware/WebUtils/FieldStorage.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
import cgi
99
import os
1010

11-
from collections import defaultdict
12-
from urllib import parse
11+
from urllib.parse import unquote_plus
1312

1413

1514
class FieldStorage(cgi.FieldStorage):
@@ -77,11 +76,11 @@ def __init__(self, fp=None, headers=None, outerboundary=b'',
7776

7877
def add_qs(self, qs):
7978
"""Add all non-existing parameters from the given query string."""
80-
values = defaultdict(list)
8179
# split the query string in the same way as the current Python does it
8280
try:
8381
max_num_fields = self.max_num_fields
8482
except AttributeError:
83+
# parameter did not exist before Python 3.6.7
8584
max_num_fields = None
8685
try:
8786
separator = self.separator
@@ -101,23 +100,27 @@ def add_qs(self, qs):
101100
raise ValueError('Max number of fields exceeded')
102101
# new splitting algorithm that only supports one separator
103102
pairs = qs.split(separator)
103+
if not pairs:
104+
return # shortcut when there are no parameters
105+
if self.list is None:
106+
# This makes sure self.keys() are available, even
107+
# when valid POST data wasn't encountered.
108+
self.list = []
109+
append = self.list.append
110+
existing_names = set(self)
111+
strict_parsing = self.strict_parsing
112+
keep_blank_values = self.keep_blank_values
104113
for name_value in pairs:
105114
nv = name_value.split('=', 1)
106115
if len(nv) != 2:
107-
if self.strict_parsing:
116+
if strict_parsing:
108117
raise ValueError(f'bad query field: {name_value!r}')
118+
# Ignore parameters with no equal sign if not strict parsing
109119
continue
110-
name = parse.unquote(nv[0].replace('+', ' '))
111-
value = parse.unquote(nv[1].replace('+', ' '))
112-
if len(value) or self.keep_blank_values:
113-
values[name].append(value)
114-
if self.list is None:
115-
# This makes sure self.keys() are available, even
116-
# when valid POST data wasn't encountered.
117-
self.list = []
118-
for key in values:
119-
if key not in self:
120-
# Only append values that aren't already the FieldStorage;
121-
# this makes POSTed vars override vars on the query string.
122-
for value in values[key]:
123-
self.list.append(cgi.MiniFieldStorage(key, value))
120+
value = unquote_plus(nv[1])
121+
if value or keep_blank_values:
122+
name = unquote_plus(nv[0])
123+
if name not in existing_names:
124+
# Only append values that aren't already the FieldStorage;
125+
# this makes POSTed vars override vars on the query string.
126+
append(cgi.MiniFieldStorage(name, value))

webware/WebUtils/Tests/TestFieldStorage.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ def testPostRequestWithBody(self):
3737
self.assertEqual(fs.getlist('e'), ['5', '6'])
3838
self.assertEqual(fs.getlist('f'), ['6'])
3939

40+
def testPostRequestWithSpacesInValues(self):
41+
fs = FieldStorage(fp=BytesIO(), environ=dict(
42+
REQUEST_METHOD='POST', QUERY_STRING='a=b%20c+d'))
43+
self.assertEqual(fs.getfirst('a'), 'b c d')
44+
fs = FieldStorage(fp=BytesIO(b'a=b%20c+d'), environ=dict(
45+
REQUEST_METHOD='POST'))
46+
self.assertEqual(fs.getfirst('a'), 'b c d')
47+
4048
def testPostRequestOverrides(self):
4149
fs = FieldStorage(fp=BytesIO(b'b=8&c=9&d=4&e=5&e=6&f=6'), environ=dict(
4250
REQUEST_METHOD='POST', QUERY_STRING='a=1&b=2&b=3&c=3'))

0 commit comments

Comments
 (0)