Mercurial > p > roundup > code
comparison roundup/cgi/actions.py @ 8580:5cba36e42b8f
chore: refactor replace urlparse with urlsplit and use urllib_
Python docs recommend use of urlsplit() rather than
urlparse(). urlsplit() is a little faster and doesn't try to split the
path into path and params using the rules from an obsolete RFC.
actions.py, demo.py, rest.py, client.py
Replace urlparse() with urlsplit()
actions.py
urlsplit() produces a named tuple with one fewer elements (no
.param). So fixup calls to urlunparse() so they have the proper
number of elements in the tuple.
also merge url filtering for param and path.
demo.py, rest.py:
Replace imports from urlparse/urllib.parse with
roundup.anypy.urllib_ so we use the same interface throughout the
code base.
test/test_cgi.py:
Since actions.py filtering for invali urls not split by path/param,
fix tests for improperly quoted url's.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sun, 19 Apr 2026 22:58:59 -0400 |
| parents | 166cb2632315 |
| children |
comparison
equal
deleted
inserted
replaced
| 8579:d2304f4774ae | 8580:5cba36e42b8f |
|---|---|
| 90 it's correct as it comes in or it's a ValueError. | 90 it's correct as it comes in or it's a ValueError. |
| 91 | 91 |
| 92 Finally paste the whole thing together and return the new url. | 92 Finally paste the whole thing together and return the new url. |
| 93 ''' | 93 ''' |
| 94 | 94 |
| 95 parsed_url_tuple = urllib_.urlparse(url) | 95 parsed_url_tuple = urllib_.urlsplit(url) |
| 96 if self.base: | 96 if self.base: |
| 97 parsed_base_url_tuple = urllib_.urlparse(self.base) | 97 parsed_base_url_tuple = urllib_.urlsplit(self.base) |
| 98 else: | 98 else: |
| 99 raise ValueError(self._("Base url not set. Check configuration.")) | 99 raise ValueError(self._("Base url not set. Check configuration.")) |
| 100 | 100 |
| 101 info = {'url': url, | 101 info = {'url': url, |
| 102 'base_url': self.base, | 102 'base_url': self.base, |
| 104 'base_netloc': parsed_base_url_tuple.netloc, | 104 'base_netloc': parsed_base_url_tuple.netloc, |
| 105 'base_path': parsed_base_url_tuple.path, | 105 'base_path': parsed_base_url_tuple.path, |
| 106 'url_scheme': parsed_url_tuple.scheme, | 106 'url_scheme': parsed_url_tuple.scheme, |
| 107 'url_netloc': parsed_url_tuple.netloc, | 107 'url_netloc': parsed_url_tuple.netloc, |
| 108 'url_path': parsed_url_tuple.path, | 108 'url_path': parsed_url_tuple.path, |
| 109 'url_params': parsed_url_tuple.params, | |
| 110 'url_query': parsed_url_tuple.query, | 109 'url_query': parsed_url_tuple.query, |
| 111 'url_fragment': parsed_url_tuple.fragment} | 110 'url_fragment': parsed_url_tuple.fragment} |
| 112 | 111 |
| 113 if parsed_base_url_tuple.scheme == "https": | 112 if parsed_base_url_tuple.scheme == "https": |
| 114 if parsed_url_tuple.scheme != "https": | 113 if parsed_url_tuple.scheme != "https": |
| 140 | 139 |
| 141 if not allowed_pattern.match(parsed_url_tuple.path): | 140 if not allowed_pattern.match(parsed_url_tuple.path): |
| 142 raise ValueError(self._("Path component (%(url_path)s) in %(url)s " | 141 raise ValueError(self._("Path component (%(url_path)s) in %(url)s " |
| 143 "is not properly escaped") % info) | 142 "is not properly escaped") % info) |
| 144 | 143 |
| 145 if not allowed_pattern.match(parsed_url_tuple.params): | |
| 146 raise ValueError(self._("Params component (%(url_params)s) in %(url)s is not properly escaped") % info) | |
| 147 | |
| 148 if not allowed_pattern.match(parsed_url_tuple.query): | 144 if not allowed_pattern.match(parsed_url_tuple.query): |
| 149 raise ValueError(self._("Query component (%(url_query)s) in %(url)s is not properly escaped") % info) | 145 raise ValueError(self._("Query component (%(url_query)s) in %(url)s is not properly escaped") % info) |
| 150 | 146 |
| 151 if not allowed_pattern.match(parsed_url_tuple.fragment): | 147 if not allowed_pattern.match(parsed_url_tuple.fragment): |
| 152 raise ValueError(self._("Fragment component (%(url_fragment)s) in %(url)s is not properly escaped") % info) | 148 raise ValueError(self._("Fragment component (%(url_fragment)s) in %(url)s is not properly escaped") % info) |
| 153 | 149 |
| 154 return urllib_.urlunparse(parsed_url_tuple) | 150 return urllib_.urlunparse((*parsed_url_tuple[0:3], |
| 151 "", # urlsplit has no .params | |
| 152 *parsed_url_tuple[3:])) | |
| 155 | 153 |
| 156 name = '' | 154 name = '' |
| 157 permissionType = None | 155 permissionType = None |
| 158 | 156 |
| 159 def permission(self): | 157 def permission(self): |
| 1276 # 4. Define a new redirect_url missing the @...message entries. | 1274 # 4. Define a new redirect_url missing the @...message entries. |
| 1277 # This will be redefined if there is a login error to include | 1275 # This will be redefined if there is a login error to include |
| 1278 # a new error message | 1276 # a new error message |
| 1279 | 1277 |
| 1280 clean_url = self.examine_url(self.form['__came_from'].value) | 1278 clean_url = self.examine_url(self.form['__came_from'].value) |
| 1281 redirect_url_tuple = urllib_.urlparse(clean_url) | 1279 redirect_url_tuple = urllib_.urlsplit(clean_url) |
| 1282 # now I have a tuple form for the __came_from url | 1280 # now I have a tuple form for the __came_from url |
| 1283 try: | 1281 try: |
| 1284 query = urllib_.parse_qs(redirect_url_tuple.query) | 1282 query = urllib_.parse_qs(redirect_url_tuple.query) |
| 1285 if "@error_message" in query: | 1283 if "@error_message" in query: |
| 1286 del query["@error_message"] | 1284 del query["@error_message"] |
| 1298 | 1296 |
| 1299 redirect_url = urllib_.urlunparse( | 1297 redirect_url = urllib_.urlunparse( |
| 1300 (redirect_url_tuple.scheme, | 1298 (redirect_url_tuple.scheme, |
| 1301 redirect_url_tuple.netloc, | 1299 redirect_url_tuple.netloc, |
| 1302 redirect_url_tuple.path, | 1300 redirect_url_tuple.path, |
| 1303 redirect_url_tuple.params, | 1301 "", # urlsplit() has no .params |
| 1304 urllib_.urlencode(list(sorted(query.items())), doseq=True), | 1302 urllib_.urlencode(list(sorted(query.items())), doseq=True), |
| 1305 redirect_url_tuple.fragment)) | 1303 redirect_url_tuple.fragment)) |
| 1306 | 1304 |
| 1307 try: | 1305 try: |
| 1308 self.verifyLogin(self.client.user, password) | 1306 self.verifyLogin(self.client.user, password) |
| 1316 query['@error_message'] = err.args | 1314 query['@error_message'] = err.args |
| 1317 redirect_url = urllib_.urlunparse( | 1315 redirect_url = urllib_.urlunparse( |
| 1318 (redirect_url_tuple.scheme, | 1316 (redirect_url_tuple.scheme, |
| 1319 redirect_url_tuple.netloc, | 1317 redirect_url_tuple.netloc, |
| 1320 redirect_url_tuple.path, | 1318 redirect_url_tuple.path, |
| 1321 redirect_url_tuple.params, | 1319 "", # urlsplit() has no .params |
| 1322 urllib_.urlencode(list(sorted(query.items())), doseq=True), | 1320 urllib_.urlencode(list(sorted(query.items())), doseq=True), |
| 1323 redirect_url_tuple.fragment)) | 1321 redirect_url_tuple.fragment)) |
| 1324 raise exceptions.Redirect(redirect_url) | 1322 raise exceptions.Redirect(redirect_url) |
| 1325 # if no __came_from, send back to base url with error | 1323 # if no __came_from, send back to base url with error |
| 1326 return | 1324 return |
| 1339 query['@error_message'] = err.args | 1337 query['@error_message'] = err.args |
| 1340 redirect_url = urllib_.urlunparse( | 1338 redirect_url = urllib_.urlunparse( |
| 1341 (redirect_url_tuple.scheme, | 1339 (redirect_url_tuple.scheme, |
| 1342 redirect_url_tuple.netloc, | 1340 redirect_url_tuple.netloc, |
| 1343 redirect_url_tuple.path, | 1341 redirect_url_tuple.path, |
| 1344 redirect_url_tuple.params, | 1342 "", # urlsplit() has no .params |
| 1345 urllib_.urlencode(list(sorted(query.items())), doseq=True), | 1343 urllib_.urlencode(list(sorted(query.items())), doseq=True), |
| 1346 redirect_url_tuple.fragment)) | 1344 redirect_url_tuple.fragment)) |
| 1347 raise exceptions.Redirect(redirect_url) | 1345 raise exceptions.Redirect(redirect_url) |
| 1348 raise | 1346 raise |
| 1349 | 1347 |
| 1361 query['@ok_message'] = _("Welcome %(username)s!") % { | 1359 query['@ok_message'] = _("Welcome %(username)s!") % { |
| 1362 "username": self.client.user, } | 1360 "username": self.client.user, } |
| 1363 redirect_url = urllib_.urlunparse((redirect_url_tuple.scheme, | 1361 redirect_url = urllib_.urlunparse((redirect_url_tuple.scheme, |
| 1364 redirect_url_tuple.netloc, | 1362 redirect_url_tuple.netloc, |
| 1365 redirect_url_tuple.path, | 1363 redirect_url_tuple.path, |
| 1366 redirect_url_tuple.params, | 1364 "", # urlsplit has no .params |
| 1367 urllib_.urlencode(list(sorted(query.items())), doseq=True), | 1365 urllib_.urlencode(list(sorted(query.items())), doseq=True), |
| 1368 redirect_url_tuple.fragment)) | 1366 redirect_url_tuple.fragment)) |
| 1369 | 1367 |
| 1370 raise exceptions.Redirect(redirect_url) | 1368 raise exceptions.Redirect(redirect_url) |
| 1371 | 1369 |
