diff --git a/devtools/fakeweb b/devtools/fakeweb index 39142800..9c595dff 100755 --- a/devtools/fakeweb +++ b/devtools/fakeweb @@ -111,6 +111,7 @@ def application(environ, start_response): # provide some needed info environ['SCRIPT_FILENAME'] = wsgi_publisher.__file__ environ['REQUEST_URI'] = get_url(environ) + environ['REQUEST_SCHEME'] = environ['wsgi.url_scheme'] set_config(environ) if FIRST: pprint.pprint(environ) diff --git a/www/kojiweb/wsgi_publisher.py b/www/kojiweb/wsgi_publisher.py index 8f5de4b3..82e69314 100644 --- a/www/kojiweb/wsgi_publisher.py +++ b/www/kojiweb/wsgi_publisher.py @@ -19,7 +19,6 @@ # Authors: # Mike McLean -import cgi import inspect import logging import os.path @@ -241,29 +240,14 @@ class Dispatcher(object): func = self.handler_index.get(method) if not func: raise URLNotFound - # parse form args - data = {} - fs = cgi.FieldStorage(fp=environ['wsgi.input'], - environ=environ.copy(), - keep_blank_values=True) - for field in fs.list: - if field.filename: - val = field - else: - val = field.value - data.setdefault(field.name, []).append(val) - # replace singleton lists with single values - # XXX - this is a bad practice, but for now we strive to emulate mod_python.publisher - for arg in data: - val = data[arg] - if isinstance(val, list) and len(val) == 1: - data[arg] = val[0] + # parse url args + fs = kojiweb.util.FieldStorageCompat(environ) environ['koji.form'] = fs args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \ inspect.getfullargspec(func) if not varkw: # remove any unexpected args - data = dslice(data, args, strict=False) + data = dslice(fs.data, args, strict=False) # TODO (warning in header or something?) return func, data diff --git a/www/lib/kojiweb/util.py b/www/lib/kojiweb/util.py index 5adbbfd6..7aa03665 100644 --- a/www/lib/kojiweb/util.py +++ b/www/lib/kojiweb/util.py @@ -26,10 +26,11 @@ import re import ssl import stat import urllib -# a bunch of exception classes that explainError needs -from socket import error as socket_error -from xml.parsers.expat import ExpatError +from collections.abc import Mapping from functools import wraps +from socket import error as socket_error +from urllib.parse import parse_qs +from xml.parsers.expat import ExpatError import Cheetah.Template @@ -206,6 +207,55 @@ def _getValidTokens(environ): return tokens +class FieldStorageCompat(Mapping): + """Emulate the parts of cgi.FieldStorage that we need""" + + def __init__(self, environ): + data = parse_qs(environ.get('QUERY_STRING', ''), strict_parsing=True, + keep_blank_values=True) + # replace singleton lists with single values + for arg in data: + val = data[arg] + if isinstance(val, list) and len(val) == 1: + data[arg] = val[0] + self.data = data + + # we need getitem, iter, and len for the Mapping inheritance to work + + def __getitem__(self, key): + return FieldCompat(self.data[key]) + + def __iter__(self): + iter(self.data) + + def __len__(self): + return len(self.data) + + def getfirst(self, name, default=None): + """Get first value from list entries""" + value = self.data.get(name, default) + if isinstance(value, (list, tuple)): + return value[0] + else: + return value + + def getlist(self, name): + """Get value, wrap in list if not already""" + if name not in self.data: + return [] + value = self.data[name] + if isinstance(value, (list, tuple)): + return value + else: + return [value] + + +class FieldCompat: + + def __init__(self, value): + self.value = value + + def toggleOrder(template, sortKey, orderVar='order'): """ If orderVar equals 'sortKey', return '-sortKey', else