comparison mercurial/hgweb/request.py @ 36809:3c15b84ab66c

hgweb: teach WSGI parser about query strings Currently, req.form uses cgi.parse() to populate form data. Depending on the request, form data can come from POST multipart/form-data, application/x-www-form-urlencoded, or the URL query string. Putting all these things into one data structure makes it difficult to reason about how exactly parameters got to the request. It can lead to wonkiness such as pulling parameters from both the URL and POST data. This commit teaches our WSGI request parser about argument data in query strings. We populate fields containing the query string data and only the query string data so it can't be confused with POST data. Differential Revision: https://phab.mercurial-scm.org/D2737
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 08 Mar 2018 11:21:46 -0800
parents 0031e972ded2
children cfb9ef24968c
comparison
equal deleted inserted replaced
36808:0031e972ded2 36809:3c15b84ab66c
76 dispatchparts = attr.ib() 76 dispatchparts = attr.ib()
77 # URL path component (no query string) used for dispatch. 77 # URL path component (no query string) used for dispatch.
78 dispatchpath = attr.ib() 78 dispatchpath = attr.ib()
79 # Raw query string (part after "?" in URL). 79 # Raw query string (part after "?" in URL).
80 querystring = attr.ib() 80 querystring = attr.ib()
81 # List of 2-tuples of query string arguments.
82 querystringlist = attr.ib()
83 # Dict of query string arguments. Values are lists with at least 1 item.
84 querystringdict = attr.ib()
81 85
82 def parserequestfromenv(env): 86 def parserequestfromenv(env):
83 """Parse URL components from environment variables. 87 """Parse URL components from environment variables.
84 88
85 WSGI defines request attributes via environment variables. This function 89 WSGI defines request attributes via environment variables. This function
166 170
167 dispatchpath = '/'.join(dispatchparts) 171 dispatchpath = '/'.join(dispatchparts)
168 172
169 querystring = env.get('QUERY_STRING', '') 173 querystring = env.get('QUERY_STRING', '')
170 174
175 # We store as a list so we have ordering information. We also store as
176 # a dict to facilitate fast lookup.
177 querystringlist = util.urlreq.parseqsl(querystring, keep_blank_values=True)
178
179 querystringdict = {}
180 for k, v in querystringlist:
181 if k in querystringdict:
182 querystringdict[k].append(v)
183 else:
184 querystringdict[k] = [v]
185
171 return parsedrequest(url=fullurl, baseurl=baseurl, 186 return parsedrequest(url=fullurl, baseurl=baseurl,
172 advertisedurl=advertisedfullurl, 187 advertisedurl=advertisedfullurl,
173 advertisedbaseurl=advertisedbaseurl, 188 advertisedbaseurl=advertisedbaseurl,
174 apppath=apppath, 189 apppath=apppath,
175 dispatchparts=dispatchparts, dispatchpath=dispatchpath, 190 dispatchparts=dispatchparts, dispatchpath=dispatchpath,
176 querystring=querystring) 191 querystring=querystring,
192 querystringlist=querystringlist,
193 querystringdict=querystringdict)
177 194
178 class wsgirequest(object): 195 class wsgirequest(object):
179 """Higher-level API for a WSGI request. 196 """Higher-level API for a WSGI request.
180 197
181 WSGI applications are invoked with 2 arguments. They are used to 198 WSGI applications are invoked with 2 arguments. They are used to