13
13
14
14
This module defines a number of utilities for use by CGI scripts
15
15
written in Python.
16
+
17
+ The global variable maxlen can be set to an integer indicating the maximum size
18
+ of a POST request. POST requests larger than this size will result in a
19
+ ValueError being raised during parsing. The default value of this variable is 0,
20
+ meaning the request size is unlimited.
16
21
"""
17
22
18
23
# History
41
46
import html
42
47
import locale
43
48
import tempfile
49
+ import warnings
44
50
45
51
__all__ = ["MiniFieldStorage" , "FieldStorage" , "parse" , "parse_multipart" ,
46
52
"parse_header" , "test" , "print_exception" , "print_environ" ,
47
53
"print_form" , "print_directory" , "print_arguments" ,
48
54
"print_environ_usage" ]
49
55
56
+
57
+ warnings ._deprecated (__name__ , remove = (3 ,13 ))
58
+
50
59
# Logging support
51
60
# ===============
52
61
@@ -77,9 +86,11 @@ def initlog(*allargs):
77
86
78
87
"""
79
88
global log , logfile , logfp
89
+ warnings .warn ("cgi.log() is deprecated as of 3.10. Use logging instead" ,
90
+ DeprecationWarning , stacklevel = 2 )
80
91
if logfile and not logfp :
81
92
try :
82
- logfp = open (logfile , "a" )
93
+ logfp = open (logfile , "a" , encoding = "locale" )
83
94
except OSError :
84
95
pass
85
96
if not logfp :
@@ -115,7 +126,8 @@ def closelog():
115
126
# 0 ==> unlimited input
116
127
maxlen = 0
117
128
118
- def parse (fp = None , environ = os .environ , keep_blank_values = 0 , strict_parsing = 0 ):
129
+ def parse (fp = None , environ = os .environ , keep_blank_values = 0 ,
130
+ strict_parsing = 0 , separator = '&' ):
119
131
"""Parse a query in the environment or from a file (default stdin)
120
132
121
133
Arguments, all optional:
@@ -134,6 +146,9 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
134
146
strict_parsing: flag indicating what to do with parsing errors.
135
147
If false (the default), errors are silently ignored.
136
148
If true, errors raise a ValueError exception.
149
+
150
+ separator: str. The symbol to use for separating the query arguments.
151
+ Defaults to &.
137
152
"""
138
153
if fp is None :
139
154
fp = sys .stdin
@@ -154,7 +169,7 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
154
169
if environ ['REQUEST_METHOD' ] == 'POST' :
155
170
ctype , pdict = parse_header (environ ['CONTENT_TYPE' ])
156
171
if ctype == 'multipart/form-data' :
157
- return parse_multipart (fp , pdict )
172
+ return parse_multipart (fp , pdict , separator = separator )
158
173
elif ctype == 'application/x-www-form-urlencoded' :
159
174
clength = int (environ ['CONTENT_LENGTH' ])
160
175
if maxlen and clength > maxlen :
@@ -178,10 +193,10 @@ def parse(fp=None, environ=os.environ, keep_blank_values=0, strict_parsing=0):
178
193
qs = ""
179
194
environ ['QUERY_STRING' ] = qs # XXX Shouldn't, really
180
195
return urllib .parse .parse_qs (qs , keep_blank_values , strict_parsing ,
181
- encoding = encoding )
196
+ encoding = encoding , separator = separator )
182
197
183
198
184
- def parse_multipart (fp , pdict , encoding = "utf-8" , errors = "replace" ):
199
+ def parse_multipart (fp , pdict , encoding = "utf-8" , errors = "replace" , separator = '&' ):
185
200
"""Parse multipart input.
186
201
187
202
Arguments:
@@ -194,15 +209,18 @@ def parse_multipart(fp, pdict, encoding="utf-8", errors="replace"):
194
209
value is a list of values for that field. For non-file fields, the value
195
210
is a list of strings.
196
211
"""
197
- # RFC 2026 , Section 5.1 : The "multipart" boundary delimiters are always
212
+ # RFC 2046 , Section 5.1 : The "multipart" boundary delimiters are always
198
213
# represented as 7bit US-ASCII.
199
214
boundary = pdict ['boundary' ].decode ('ascii' )
200
215
ctype = "multipart/form-data; boundary={}" .format (boundary )
201
216
headers = Message ()
202
217
headers .set_type (ctype )
203
- headers ['Content-Length' ] = pdict ['CONTENT-LENGTH' ]
218
+ try :
219
+ headers ['Content-Length' ] = pdict ['CONTENT-LENGTH' ]
220
+ except KeyError :
221
+ pass
204
222
fs = FieldStorage (fp , headers = headers , encoding = encoding , errors = errors ,
205
- environ = {'REQUEST_METHOD' : 'POST' })
223
+ environ = {'REQUEST_METHOD' : 'POST' }, separator = separator )
206
224
return {k : fs .getlist (k ) for k in fs }
207
225
208
226
def _parseparam (s ):
@@ -312,7 +330,7 @@ class FieldStorage:
312
330
def __init__ (self , fp = None , headers = None , outerboundary = b'' ,
313
331
environ = os .environ , keep_blank_values = 0 , strict_parsing = 0 ,
314
332
limit = None , encoding = 'utf-8' , errors = 'replace' ,
315
- max_num_fields = None ):
333
+ max_num_fields = None , separator = '&' ):
316
334
"""Constructor. Read multipart/* until last part.
317
335
318
336
Arguments, all optional:
@@ -360,6 +378,7 @@ def __init__(self, fp=None, headers=None, outerboundary=b'',
360
378
self .keep_blank_values = keep_blank_values
361
379
self .strict_parsing = strict_parsing
362
380
self .max_num_fields = max_num_fields
381
+ self .separator = separator
363
382
if 'REQUEST_METHOD' in environ :
364
383
method = environ ['REQUEST_METHOD' ].upper ()
365
384
self .qs_on_post = None
@@ -586,7 +605,7 @@ def read_urlencoded(self):
586
605
query = urllib .parse .parse_qsl (
587
606
qs , self .keep_blank_values , self .strict_parsing ,
588
607
encoding = self .encoding , errors = self .errors ,
589
- max_num_fields = self .max_num_fields )
608
+ max_num_fields = self .max_num_fields , separator = self . separator )
590
609
self .list = [MiniFieldStorage (key , value ) for key , value in query ]
591
610
self .skip_lines ()
592
611
@@ -602,7 +621,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing):
602
621
query = urllib .parse .parse_qsl (
603
622
self .qs_on_post , self .keep_blank_values , self .strict_parsing ,
604
623
encoding = self .encoding , errors = self .errors ,
605
- max_num_fields = self .max_num_fields )
624
+ max_num_fields = self .max_num_fields , separator = self . separator )
606
625
self .list .extend (MiniFieldStorage (key , value ) for key , value in query )
607
626
608
627
klass = self .FieldStorageClass or self .__class__
@@ -646,7 +665,7 @@ def read_multi(self, environ, keep_blank_values, strict_parsing):
646
665
else self .limit - self .bytes_read
647
666
part = klass (self .fp , headers , ib , environ , keep_blank_values ,
648
667
strict_parsing , limit ,
649
- self .encoding , self .errors , max_num_fields )
668
+ self .encoding , self .errors , max_num_fields , self . separator )
650
669
651
670
if max_num_fields is not None :
652
671
max_num_fields -= 1
@@ -736,7 +755,8 @@ def read_lines_to_outerboundary(self):
736
755
last_line_lfend = True
737
756
_read = 0
738
757
while 1 :
739
- if self .limit is not None and _read >= self .limit :
758
+
759
+ if self .limit is not None and 0 <= self .limit <= _read :
740
760
break
741
761
line = self .fp .readline (1 << 16 ) # bytes
742
762
self .bytes_read += len (line )
0 commit comments