################################################## # SPYCE - Python-based HTML Scripting # Copyright (c) 2002 Rimon Barr. # # Refer to spyce.py # CVS: $Id: request.py 1021 2006-08-04 01:10:53Z ellisj $ ################################################## from spyceModule import spyceModule import spyce, cgi, string, urlparse, spyceUtil, sys __doc__ = """Request module provides access to the browser request information. """ def lowerize(d): """ returns a dict containing the list values of d, mapped to lower-case keys. d may contain keys that differ only in case. """ lowered = {} for key in d: keyL = string.lower(key) lowered[keyL] = lowered.get(keyL, []) + d[key] return lowered def extractValue(hash, key, default, single): """ Extract key's value from dictionary [of lists], if it exists. If single, return value[0]. If key is none, return entire dictionary, or dictionary of first values if single. Else if key is not found, return default. """ if key is None: if single: d = {} for key in hash: d[key] = hash[key][0] return d return hash if key in hash: if single: return hash[key][0] return hash[key] if default == []: default = [] # workaround default-only-evaluated-once "feature" return default def filterDict(request, d, filters): for f in filters: f(request, d) class request(spyceModule): def start(self): "Initialise module variables" self._initted = False if spyce.DEBUG_ERROR: sys.stderr.write('GET variables: %s\n' % self.get()) sys.stderr.write('POST variables: %s\n' % self.post()) def uri(self, component=None): "Return request URI, or URI component" theuri = self._api.getRequest().env()['REQUEST_URI'] if not component: return theuri else: component = string.lower(component) if component == 'scheme': component = 0 elif component == 'location': component = 1 elif component == 'path': component = 2 elif component == 'parameters': component = 3 elif component == 'query': component = 4 elif component == 'fragment': component = 5 else: raise 'unknown uri component' return urlparse.urlparse(theuri)[component] def uri_scheme(self): "Return request URI scheme, ie. http (usually)" return urlparse.urlparse(self.uri())[0] def uri_location(self): "Return request URI scheme, ie. http (usually)" return urlparse.urlparse(self.uri())[1] def uri_path(self): "Return request URI path component" return urlparse.urlparse(self.uri())[2] def method(self): "Return request method: get/post/..." return string.upper(self._api.getRequest().env()['REQUEST_METHOD']) def query(self): "Return request query string" return self._api.getRequest().env()['QUERY_STRING'] def stack(self, i=None): s = self._api.getStack() if i is not None: s = s[i] return s def filename(self, relative=None): "Return original Spyce filename" myfile = self._api.getFilename() if relative is None: return myfile else: return os.path.realpath(os.path.join(os.path.dirname(myfile), relative)) def default(self, value, value2): "Return value, or value2 if value is None" if value is None: return value2 return value def _getInit(self): self._get = cgi.parse_qs(self.query(), 1) def get(self, name=None, default=[], ignoreCase=0, single=False): "Return GET parameter(s) list(s)" self._init() if ignoreCase: if name: name = string.lower(name) return extractValue(self._getL, name, default, single) return extractValue(self._get, name, default, single) def get1(self, name=None, default=None, ignoreCase=0): "Return single GET parameter(s)" return self.get(name, default, ignoreCase, True) def _postInit(self): if hasattr(self._api.getRequest(), 'spycepostinfo'): # stream was already parsed (possibly this is an internal redirect) (self._post, self._file) = self._api.getRequest().spycepostinfo return self._post = {} self._file = {} try: len = int(str(self.env('CONTENT_LENGTH'))) except: len=0 if self.method()=='POST' and len: postfields = cgi.FieldStorage(fp=self._api.getRequest(), environ=self.env(), keep_blank_values=1) for key in postfields.keys(): if type(postfields[key]) == type( [] ): self._post[key] = map(lambda attr: attr.value, postfields[key]) elif not postfields[key].filename: self._post[key] = [postfields[key].value] else: self._file[key] = postfields[key] # save parsed information in request object to prevent reparsing (on redirection) self._api.getRequest().spycepostinfo = (self._post, self._file) def _init(self): if self._initted: return # get raw parameters before filtering # this allows sophisticated filters to take action based on the "big picture" # not just individual key/values self._getInit() self._postInit() filterDict(self, self._get, spyce.getServer().config.param_filters) filterDict(self, self._post, spyce.getServer().config.param_filters) filterDict(self, self._file, spyce.getServer().config.file_filters) # generate lowercase dicts after filtering self._getL = lowerize(self._get) self._postL = lowerize(self._post) self._fileL = {} for key in self._file: self._fileL[string.lower(key)] = self._file[key] self._initted = True def post(self, name=None, default=[], ignoreCase=False, single=False): "Return POST parameter(s) list(s)" self._postInit() if ignoreCase: if name: name = string.lower(name) return extractValue(self._postL, name, default, single) return extractValue(self._post, name, default, single) def post1(self, name=None, default=None, ignoreCase=0): "Return single POST parameter(s)" return self.post(name, default, ignoreCase, True) def file(self, name=None, ignoreCase=0): "Return POSTed file(s)" self._init() if ignoreCase: if name: name = string.lower(name) return spyceUtil.extractValue(self._fileL, name) else: return spyceUtil.extractValue(self._file, name) def env(self, name=None, default=None): "Return other request (CGI) environment variables" return self.default(self._api.getRequest().env(name), default) def getHeader(self, type=None): "Return browser HTTP header(s)" return self._api.getRequest().getHeader(type) # __setitem__ deliberately left out -- # if you really truly want to present a modified view of request parameters # to yourself, use add[File|Param]Filter. def __getitem__(self, key): if type(key) == type(0): spyce.DEBUG('returning raw for %s' % key) return self.getpost().keys()[key] else: v = self.get1(key) if v is not None: return v v = self.post1(key) if v is not None: return v v = self.file(key) spyce.DEBUG('getitem for %s is %s' % (key, v)) if v is not None: return v def __repr__(self): return '' def _multidict(self, *args): args = list(args) args.reverse() dict = {} for d in args: for k in d.keys(): dict[k] = d[k] return dict def getpost(self, name=None, default=None, ignoreCase=0): "Return get() if not None, otherwise post() if not None, otherwise default" if name is None: self._init() return self._multidict(self._get, self._post) else: value = self.get(name, None, ignoreCase) if value is None: value = self.post(name, default, ignoreCase) return value def getpost1(self, name=None, default=None, ignoreCase=0): "Return get1() if not None, otherwise post1() if not None, otherwise default" if name is None: self._init() return self._multidict(self.get1(), self.post1()) else: value = self.get1(name, None, ignoreCase) if value is None: value = self.post1(name, default, ignoreCase) return value def postget(self, name=None, default=None, ignoreCase=0): "Return post() if not None, otherwise get() if not None, otherwise default" if name is None: self._init() return self._multidict(self._post, self._get) else: value = self.post(name, None, ignoreCase) if value is None: value = self.get(name, default, ignoreCase) return value def postget1(self, name=None, default=None, ignoreCase=0): "Return post1() if not None, otherwise get1() if not None, otherwise default" if name is None: self._init() return self._multidict(self.post1(), self.get1()) else: value = self.post1(name, None, ignoreCase) if value is None: value = self.get1(name, default, ignoreCase) return value