# -*- coding: iso-8859-1 -*- """ MoinMoin - Data associated with a single Request @copyright: 2001-2003 by Jürgen Hermann @copyright: 2003-2004 by Thomas Waldmann @license: GNU GPL, see COPYING for details. """ import os, time, sys from MoinMoin import config, wikiutil from MoinMoin.util import MoinMoinNoFooter ############################################################################# ### Timing ############################################################################# class Clock: """ Helper class for code profiling we do not use time.clock() as this does not work across threads """ def __init__(self): self.timings = {'total': time.time()} def start(self, timer): self.timings[timer] = time.time() - self.timings.get(timer, 0) def stop(self, timer): self.timings[timer] = time.time() - self.timings[timer] def value(self, timer): return "%.3f" % (self.timings[timer],) def dump(self): outlist = [] for timing in self.timings.items(): outlist.append("%s = %.3fs" % timing) return outlist ############################################################################# ### Request Data ############################################################################# class RequestBase: """ A collection for all data associated with ONE request. """ # Header set to force misbehaved proxies and browsers to keep their # hands off a page # Details: http://support.microsoft.com/support/kb/articles/Q234/0/67.ASP nocache = [ "Pragma: no-cache", "Cache-Control: no-cache", "Expires: -1", ] def __init__(self, properties={}): self.writestack = [] self.clock = Clock() # order is important here! from MoinMoin import user self.user = user.User(self) self.dicts = self.initdicts() from MoinMoin import i18n if config.theme_force: theme_name = config.theme_default else: theme_name = self.user.theme_name try: self.theme = wikiutil.importPlugin('theme', theme_name)(self) except TypeError: theme_name = config.theme_default self.theme = wikiutil.importPlugin('theme', theme_name)(self) self.args = None self.form = None self.logger = None self.pragma = {} self.mode_getpagelinks = 0 self.no_closing_html_code = 0 self.sent_headers = 0 self.user_headers = [] self.__dict__.update(properties) self.i18n = i18n self.lang = i18n.requestLanguage(self) self.getText = lambda text, i18n=self.i18n, request=self, lang=self.lang: i18n.getText(text, request, lang) # XXX Removed call to i18n.adaptcharset() self.opened_logs = 0 # XXX for what do we need that??? self.reset() def _setup_vars_from_std_env(self, env): """ Sets the common Request members by parsing a standard HTTPD environment (as created as environment by most common webservers. To be used by derived classes. @param env: the environment to use """ self.http_accept_language = env.get('HTTP_ACCEPT_LANGUAGE', 'en') self.server_name = env.get('SERVER_NAME', 'localhost') self.server_port = env.get('SERVER_PORT', '80') self.http_host = env.get('HTTP_HOST','localhost') self.http_referer = env.get('HTTP_REFERER', '') self.saved_cookie = env.get('HTTP_COOKIE', '') self.script_name = env.get('SCRIPT_NAME', '') self.path_info = env.get('PATH_INFO', '') self.query_string = env.get('QUERY_STRING', '') self.request_method = env.get('REQUEST_METHOD', None) self.remote_addr = env.get('REMOTE_ADDR', '') self.http_user_agent = env.get('HTTP_USER_AGENT', '') self.is_ssl = env.get('SSL_PROTOCOL', '') != '' \ or env.get('SSL_PROTOCOL_VERSION', '') != '' \ or env.get('HTTPS', 'off') == 'on' self.auth_username = None if config.auth_http_enabled and env.get('AUTH_TYPE','') == 'Basic': self.auth_username = env.get('REMOTE_USER','') ## f=open('/tmp/env.log','a') ## f.write('---ENV\n') ## f.write('script_name = %s\n'%(self.script_name)) ## f.write('path_info = %s\n'%(self.path_info)) ## f.write('server_name = %s\n'%(self.server_name)) ## f.write('server_port = %s\n'%(self.server_port)) ## f.write('http_host = %s\n'%(self.http_host)) ## f.write('------\n') ## f.write('%s\n'%(repr(env))) ## f.write('------\n') ## f.close() def reset(self): """ Reset request state. Called after saving a page, before serving the updated page. Solves some practical problems with request state modified during saving. """ # This is the content language and has nothing to do with # The user interface language. The content language can change # during the rendering of a page by lang macros self.current_lang = config.default_lang self._footer_fragments = {} self._all_pages = None if hasattr(self, "_fmt_hd_counters"): del self._fmt_hd_counters def add2footer(self, key, htmlcode): """ Add a named HTML fragment to the footer, after the default links """ self._footer_fragments[key] = htmlcode def getPragma(self, key, defval=None): """ Query a pragma value (#pragma processing instruction) Keys are not case-sensitive. """ return self.pragma.get(key.lower(), defval) def setPragma(self, key, value): """ Set a pragma value (#pragma processing instruction) Keys are not case-sensitive. """ self.pragma[key.lower()] = value def getPageList(self): """ A cached version of wikiutil.getPageList(). Also, this list is always sorted. """ if self._all_pages is None: self._all_pages = wikiutil.getPageList(config.text_dir) self._all_pages.sort() return self._all_pages def redirect(self, file=None): if file: # redirect output to "file" self.writestack.append(self.write) self.write = file.write else: # restore saved output file self.write = self.writestack.pop() def reset_output(self): """ restore default output method destroy output stack (useful for error messages) """ if self.writestack: self.write = self.writestack[0] self.writestack = [] def write(self, *data): """ Write to output stream. """ raise "NotImplementedError" def read(self, n): """ Read n bytes from input stream. """ raise "NotImplementedError" def flush(self): """ Flush output stream. """ raise "NotImplementedError" def initdicts(self): from MoinMoin import wikidicts dicts = wikidicts.GroupDict() dicts.scandicts() return dicts def isForbidden(self): """ check for web spiders and refuse anything except viewing """ forbidden = 0 if ((self.query_string != '' or self.request_method != 'GET') and self.query_string != 'action=rss_rc'): from MoinMoin.util import web forbidden = web.isSpiderAgent(request=self) if not forbidden and config.hosts_deny: ip = self.remote_addr for host in config.hosts_deny: if ip == host or host[-1] == '.' and ip.startswith(host): forbidden = 1 break return forbidden def setup_args(self, form=None): return {} def _setup_args_from_cgi_form(self, form=None): """ A method to create the args from a standart cgi.FieldStorage to be used be derived classes. @keyword form: a cgi.FieldStorage list. default is to call cgi.FieldStorage(). """ import types, cgi if form is None: form = cgi.FieldStorage() args = {} for key in form.keys(): values = form[key] if not isinstance(values, types.ListType): values = [values] fixedResult = [] for i in values: if isinstance(i, cgi.MiniFieldStorage): fixedResult.append(i.value) elif isinstance(i, cgi.FieldStorage): fixedResult.append(i.value) # multiple uploads to same form field are stupid! if i.filename: args[key+'__filename__']=i.filename args[key] = fixedResult return args def recodePageName(self, pagename): # check for non-URI characters and then handle them according to # http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.2.1 if pagename: try: dummy = unicode(pagename, 'ascii') except UnicodeError: # we have something else than plain ASCII, try # converting from UTF-8 to local charset, or just give # up and use URI value literally and see what happens pagename = self.i18n.recode(pagename, 'utf-8', config.charset) or pagename return pagename # XXX UNICODE - use unicode for pagenames internally? def getBaseURL(self): """ Return a fully qualified URL to this script. """ return self.getQualifiedURL(self.getScriptname()) def getQualifiedURL(self, uri=None): """ Return a full URL starting with schema, servername and port. *uri* -- append this server-rooted uri (must start with a slash) """ if uri and uri[:4] == "http": return uri schema, stdport = (('http', '80'), ('https', '443'))[self.is_ssl] host = self.http_host if not host: host = self.server_name port = self.server_port if port != stdport: host = "%s:%s" % (host, port) result = "%s://%s" % (schema, host) if uri: result = result + uri return result def getUserAgent(self): """ Get the user agent. """ return self.http_user_agent def run(self): _ = self.getText self.clock.start('run') self.open_logs() if self.isForbidden(): self.http_headers([ 'Status: 403 FORBIDDEN', 'Content-Type: text/plain' ]) self.write('You are not allowed to access this!\n') return self.finish() # Imports from MoinMoin.Page import Page if self.query_string == 'action=xmlrpc': from MoinMoin.wikirpc import xmlrpc xmlrpc(self) return self.finish() if self.query_string == 'action=xmlrpc2': from MoinMoin.wikirpc import xmlrpc2 xmlrpc2(self) return self.finish() # parse request data try: self.args = self.setup_args() self.form = self.args path_info = self.getPathinfo() #from pprint import pformat #sys.stderr.write(pformat(self.__dict__)) action = self.form.get('action',[None])[0] pagename = None if len(path_info) and path_info[0] == '/': pagename = wikiutil.unquoteWikiname(path_info[1:]) except: # catch and print any exception self.reset_output() self.http_headers() self.print_exception() return self.finish() try: # possibly jump to page where user left off if not pagename and not action and self.user.remember_last_visit: pagetrail = self.user.getTrail() if pagetrail: self.http_redirect(Page(pagetrail[-1]).url(self)) return self.finish() # handle request from MoinMoin import wikiaction pagename = self.recodePageName(pagename) if self.form.has_key('filepath') and self.form.has_key('noredirect'): # looks like user wants to save a drawing from MoinMoin.action.AttachFile import execute execute(pagename, self) raise MoinMoinNoFooter if action: handler = wikiaction.getHandler(action) if handler: handler(pagename or wikiutil.getSysPage(self, config.page_front_page).page_name, self) else: self.http_headers() self.write("

" + _("Unknown action")) else: if self.form.has_key('goto'): query = self.form['goto'][0].strip() elif pagename: query = pagename else: query = wikiutil.unquoteWikiname(self.query_string) or \ wikiutil.getSysPage(self, config.page_front_page).page_name if config.allow_extended_names: Page(query).send_page(self, count_hit=1) else: from MoinMoin.parser.wiki import Parser import re word_match = re.match(Parser.word_rule, query) if word_match: word = word_match.group(0) Page(word).send_page(self, count_hit=1) else: self.http_headers() self.write('

' + _("Can't work out query") + ' "

' + query + '
"') # generate page footer # (actions that do not want this footer use raise util.MoinMoinNoFooter to break out # of the default execution path, see the "except MoinMoinNoFooter" below) self.clock.stop('run') self.clock.stop('total') if not self.no_closing_html_code: if (config.show_timings and self.form.get('action', [None])[0] != 'print'): self.write('\n') if 0: # temporarily disabled - do we need that? import socket from MoinMoin import version self.write('' % ( version.revision, socket.gethostname(), self.clock.value('total')) + '') else: self.write('\n\n\n') except MoinMoinNoFooter: pass except: # catch and print any exception saved_exc = sys.exc_info() self.reset_output() self.http_headers() self.write("\n\n") try: from MoinMoin.support import cgitb except: # no cgitb, for whatever reason self.print_exception(*saved_exc) else: try: cgitb.Hook(file=self).handle(saved_exc) # was: cgitb.handler() except: self.print_exception(*saved_exc) self.write("\n\n
\n") self.write("

Additionally, cgitb raised this exception:

\n") self.print_exception() del saved_exc return self.finish() def http_redirect(self, url): """ Redirect to a fully qualified, or server-rooted URL """ if url.find("://") == -1: url = self.getQualifiedURL(url) self.http_headers(["Status: 302", "Location: %s" % url]) def print_exception(self, type=None, value=None, tb=None, limit=None): if type is None: type, value, tb = sys.exc_info() import traceback self.write("

request.print_exception handler

\n") self.write("

Traceback (most recent call last):

\n") list = traceback.format_tb(tb, limit) + \ traceback.format_exception_only(type, value) self.write("
%s%s
\n" % ( wikiutil.escape("".join(list[:-1])), wikiutil.escape(list[-1]),)) del tb def open_logs(self): pass # CGI --------------------------------------------------------------- class RequestCGI(RequestBase): """ specialized on CGI requests """ def __init__(self, properties={}): self._setup_vars_from_std_env(os.environ) #sys.stderr.write("----\n") #for key in os.environ.keys(): # sys.stderr.write(" %s = '%s'\n" % (key, os.environ[key])) RequestBase.__init__(self, properties) # force input/output to binary if sys.platform == "win32": import msvcrt msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) def open_logs(self): # create CGI log file, and one for catching stderr output import cgi if not self.opened_logs: cgi.logfile = os.path.join(config.data_dir, 'cgi.log') sys.stderr = open(os.path.join(config.data_dir, 'error.log'), 'at') self.opened_logs = 1 def setup_args(self, form=None): return self._setup_args_from_cgi_form(form) def read(self, n=None): """ Read from input stream. """ if n is None: return sys.stdin.read() else: return sys.stdin.read(n) def write(self, *data): """ Write to output stream. """ for piece in data: sys.stdout.write(piece) def flush(self): sys.stdout.flush() def finish(self): # flush the output, ignore errors caused by the user closing the socket try: sys.stdout.flush() except IOError, ex: import errno if ex.errno != errno.EPIPE: raise ############################################################################# ### Accessors ############################################################################# def getScriptname(self): """ Return the scriptname part of the URL ("/path/to/my.cgi"). """ name = self.script_name if name == '/': return '' return name def getPathinfo(self): """ Return the remaining part of the URL. """ pathinfo = self.path_info # Fix for bug in IIS/4.0 if os.name == 'nt': scriptname = self.getScriptname() if pathinfo.startswith(scriptname): pathinfo = pathinfo[len(scriptname):] return pathinfo ############################################################################# ### Headers ############################################################################# def setHttpHeader(self, header): self.user_headers.append(header) def http_headers(self, more_headers=[]): if self.sent_headers: #self.write("Headers already sent!!!\n") return self.sent_headers = 1 have_ct = 0 # send http headers for header in more_headers + self.user_headers: if header.lower().startswith("content-type:"): # don't send content-type multiple times! if have_ct: continue have_ct = 1 self.write("%s\r\n" % header) if not have_ct: self.write("Content-type: text/html;charset=%s\r\n" % config.charset) self.write('\r\n') #from pprint import pformat #sys.stderr.write(pformat(more_headers)) #sys.stderr.write(pformat(self.user_headers)) # Twisted ----------------------------------------------------------- class RequestTwisted(RequestBase): """ specialized on Twisted requests """ def __init__(self, twistedRequest, pagename, reactor, properties={}): self.twistd = twistedRequest self.http_accept_language = self.twistd.getHeader('Accept-Language') self.reactor = reactor self.saved_cookie = self.twistd.getHeader('Cookie') self.server_protocol = self.twistd.clientproto self.server_name = self.twistd.getRequestHostname().split(':')[0] self.server_port = str(self.twistd.getHost()[2]) self.is_ssl = self.twistd.isSecure() if self.server_port != ('80', '443')[self.is_ssl]: self.http_host = self.server_name + ':' + self.server_port else: self.http_host = self.server_name self.script_name = "/" + '/'.join(self.twistd.prepath[:-1]) # "" XXX self.path_info = "/" + pagename if self.twistd.postpath: self.path_info += '/' + '/'.join(self.twistd.postpath) self.request_method = self.twistd.method self.remote_host = self.twistd.getClient() self.remote_addr = self.twistd.getClientIP() self.http_user_agent = self.twistd.getHeader('User-Agent') self.request_uri = self.twistd.uri qindex = self.request_uri.find('?') if qindex != -1: self.query_string = self.request_uri[qindex+1:] else: self.query_string = '' self.outputlist = [] self.auth_username = None # TODO, see: self.twistd.user / .password (http auth) RequestBase.__init__(self, properties) #print "request.RequestTwisted.__init__: received_headers=\n" + str(self.twistd.received_headers) def setup_args(self, form=None): return self.twistd.args def read(self, n=None): """ Read from input stream. """ # XXX why is that wrong?: #rd = self.reactor.callFromThread(self.twistd.read) # XXX do we need self.reactor.callFromThread with that? # XXX if yes, why doesnt it work? self.twistd.content.seek(0, 0) if n is None: rd = self.twistd.content.read() else: rd = self.twistd.content.read(n) #print "request.RequestTwisted.read: data=\n" + str(rd) return rd def write(self, *data): """ Write to output stream. """ wd = ''.join(data) # XXX UNICODE - encode to config.charset #wd = u''.join(data).encode(config.charset) #print "request.RequestTwisted.write: data=\n" + wd self.reactor.callFromThread(self.twistd.write, wd) def flush(self): pass # XXX is there a flush in twisted? def finish(self): #print "request.RequestTwisted.finish" self.reactor.callFromThread(self.twistd.finish) def open_logs(self): return # create log file for catching stderr output if not self.opened_logs: sys.stderr = open(os.path.join(config.data_dir, 'error.log'), 'at') self.opened_logs = 1 ############################################################################# ### Accessors ############################################################################# def getScriptname(self): """ Return the scriptname part of the URL ("/path/to/my.cgi"). """ scriptname = self.script_name if scriptname == '/': scriptname = '' return scriptname def getPathinfo(self): """ Return the remaining part of the URL. """ return self.path_info ############################################################################# ### Headers ############################################################################# def setHttpHeader(self, header): self.user_headers.append(header) def __setHttpHeader(self, header): key, value = header.split(':',1) value = value.lstrip() self.twistd.setHeader(key, value) #print "request.RequestTwisted.setHttpHeader: %s" % header def http_headers(self, more_headers=[]): if self.sent_headers: #self.write("Headers already sent!!!\n") return self.sent_headers = 1 have_ct = 0 # set http headers for header in more_headers + self.user_headers: if header.lower().startswith("content-type:"): # don't send content-type multiple times! if have_ct: continue have_ct = 1 self.__setHttpHeader(header) if not have_ct: self.__setHttpHeader("Content-type: text/html;charset=%s" % config.charset) def http_redirect(self, url): """ Redirect to a fully qualified, or server-rooted URL """ if url.count("://") == 0: # no https method?? url = "http://%s:%s%s" % (self.server_name, self.server_port, url) self.twistd.redirect(url) # calling finish here will send the rest of the data to the next # request. leave the finish call to run() #self.twistd.finish() raise MoinMoinNoFooter # CLI ------------------------------------------ class RequestCLI(RequestBase): """ specialized on commandline interface requests """ def __init__(self, pagename='', properties={}): self.http_accept_language = '' self.saved_cookie = '' self.path_info = '/' + pagename self.query_string = '' self.remote_addr = '127.0.0.127' self.is_ssl = 0 self.auth_username = None RequestBase.__init__(self, properties) self.http_user_agent = '' self.outputlist = [] def read(self, n=None): """ Read from input stream. """ if n is None: return sys.stdin.read() else: return sys.stdin.read(n) def write(self, *data): """ Write to output stream. """ for piece in data: sys.stdout.write(piece) def flush(self): sys.stdout.flush() def finish(self): # flush the output, ignore errors caused by the user closing the socket try: sys.stdout.flush() except IOError, ex: import errno if ex.errno != errno.EPIPE: raise def isForbidden(self): """ check for web spiders and refuse anything except viewing """ return 0 ############################################################################# ### Accessors ############################################################################# def getScriptname(self): """ Return the scriptname part of the URL ("/path/to/my.cgi"). """ return '.' def getPathinfo(self): """ Return the remaining part of the URL. """ return self.path_info def getQualifiedURL(self, uri = None): """ Return a full URL starting with schema, servername and port. *uri* -- append this server-rooted uri (must start with a slash) """ return uri def getBaseURL(self): """ Return a fully qualified URL to this script. """ return self.getQualifiedURL(self.getScriptname()) ############################################################################# ### Headers ############################################################################# def setHttpHeader(self, header): pass def http_headers(self, more_headers=[]): pass def http_redirect(self, url): """ Redirect to a fully qualified, or server-rooted URL """ raise Exception("Redirect not supported for command line tools!") # StandAlone Server ------------------------------------------------- class RequestStandAlone(RequestBase): """ specialized on StandAlone Server (httpdmain.py) requests """ def __init__(self, sa, properties={}): """ @param sa: stand alone server object @param properties: ... """ import urllib self.wfile = sa.wfile self.rfile = sa.rfile self.headers = sa.headers self.is_ssl = 0 rest = sa.path i = rest.rfind('?') if i >= 0: rest, query = rest[:i], rest[i+1:] else: query = '' uqrest = urllib.unquote(rest) #HTTP headers self.env = {} for hline in sa.headers.headers: key = sa.headers.isheader(hline) if key: hdr = sa.headers.getheader(key) self.env[key] = hdr #accept = [] #for line in sa.headers.getallmatchingheaders('accept'): # if line[:1] in string.whitespace: # accept.append(line.strip()) # else: # accept = accept + line[7:].split(',') # #env['HTTP_ACCEPT'] = ','.join(accept) co = filter(None, sa.headers.getheaders('cookie')) self.http_accept_language = sa.headers.getheader('Accept-Language') self.server_name = sa.server.server_name self.server_port = str(sa.server.server_port) self.http_host = sa.headers.getheader('host') self.http_referer = sa.headers.getheader('referer') self.saved_cookie = ', '.join(co) or '' self.script_name = '' self.path_info = uqrest self.query_string = query or '' self.request_method = sa.command self.remote_addr = sa.client_address[0] self.http_user_agent = sa.headers.getheader('user-agent') or '' # from standalone script: # XXX AUTH_TYPE # XXX REMOTE_USER # XXX REMOTE_IDENT self.auth_username = None #env['PATH_TRANSLATED'] = uqrest #self.translate_path(uqrest) #host = self.address_string() #if host != self.client_address[0]: # env['REMOTE_HOST'] = host # env['SERVER_PROTOCOL'] = self.protocol_version RequestBase.__init__(self, properties) def open_logs(self): # create error log file for catching stderr output if not self.opened_logs: sys.stderr = open(os.path.join(config.data_dir, 'error.log'), 'at') self.opened_logs = 1 def setup_args(self, form=None): self.env['REQUEST_METHOD'] = self.request_method self.env['QUERY_STRING'] = self.query_string ct = self.headers.getheader('content-type') if ct: self.env['CONTENT_TYPE'] = ct cl = self.headers.getheader('content-length') if cl: self.env['CONTENT_LENGTH'] = cl import cgi #print "env = ", self.env #form = cgi.FieldStorage(self, headers=self.env, environ=self.env) if form is None: form = cgi.FieldStorage(self, environ=self.env) return self._setup_args_from_cgi_form(form) def read(self, n=None): """ Read from input stream. """ if n is None: return self.rfile.read() else: return self.rfile.read(n) def readline (self): L = "" while 1: c = self.read(1) L += c if c == '\n': break return L def write(self, *data): """ Write to output stream. """ for piece in data: self.wfile.write(piece) def flush(self): self.wfile.flush() def finish(self): # flush the output, ignore errors caused by the user closing the socket try: self.wfile.flush() except IOError, ex: import errno if ex.errno != errno.EPIPE: raise ############################################################################# ### Accessors ############################################################################# def getScriptname(self): """ Return the scriptname part of the URL ("/path/to/my.cgi"). """ name = self.script_name if name == '/': return '' return name def getPathinfo(self): """ Return the remaining part of the URL. """ return self.path_info ############################################################################# ### Headers ############################################################################# def setHttpHeader(self, header): self.user_headers.append(header) def http_headers(self, more_headers=[]): if self.sent_headers: #self.write("Headers already sent!!!\n") return self.sent_headers = 1 have_ct = 0 # send http headers for header in more_headers + self.user_headers: if header.lower().startswith("content-type:"): # don't send content-type multiple times! if have_ct: continue have_ct = 1 self.write("%s\r\n" % header) if not have_ct: self.write("Content-type: text/html;charset=%s\r\n" % config.charset) self.write('\r\n') #from pprint import pformat #sys.stderr.write(pformat(more_headers)) #sys.stderr.write(pformat(self.user_headers)) # mod_python/Apache ------------------------------------------------- class RequestModPy(RequestBase): """ specialized on mod_python requests """ def __init__(self, req): """ Saves mod_pythons request and sets basic variables using the req.subprocess_env, cause this provides a standard way to access the values we need here. @param req: the mod_python request instance """ req.add_common_vars() self.mpyreq = req # some mod_python 2.7.X has no get method for table objects, # so we make a real dict out of it first. if not hasattr(req.subprocess_env,'get'): env=dict(req.subprocess_env) else: env=req.subprocess_env self._setup_vars_from_std_env(env) # flags if headers sent out contained content-type or status self._have_ct = 0 self._have_status = 0 RequestBase.__init__(self) def setup_args(self, form=None): """ Sets up args by using mod_python.util.FieldStorage, which is different to cgi.FieldStorage. So we need a seperate method for this. """ import types from mod_python import util if form is None: form = util.FieldStorage(self.mpyreq) args = {} for key in form.keys(): values = form[key] if not isinstance(values, types.ListType): values = [values] fixedResult = [] for i in values: ## mod_python 2.7 might return strings instead ## of Field objects if hasattr(i,'value'): fixedResult.append(i.value) else: fixedResult.append(i) ## if object has a filename attribute, remember it ## with a name hack if hasattr(i,'filename') and i.filename: args[key+'__filename__']=i.filename args[key] = fixedResult return args def run(self, req): """ mod_python calls this with its request object. We don't need it cause its already passed to __init__. So ignore it and just return RequestBase.run. @param req: the mod_python request instance """ return RequestBase.run(self) def read(self, n=None): """ Read from input stream. """ if n is None: return self.mpyreq.read() else: return self.mpyreq.read(n) def write(self, *data): """ Write to output stream. """ for piece in data: self.mpyreq.write(piece) def flush(self): """ We can't flush it, so do nothing. """ pass def finish(self): """ Just return apache.OK. Status is set in req.status. """ # is it possible that we need to return somethig else here? from mod_python import apache return apache.OK ############################################################################# ### Accessors ############################################################################# def getScriptname(self): """ Return the scriptname part of the URL ('/path/to/my.cgi'). """ name = self.script_name if name == '/': return '' return name def getPathinfo(self): """ Return the remaining part of the URL. """ return self.path_info ############################################################################# ### Headers ############################################################################# def setHttpHeader(self, header): """ Filters out content-type and status to set them directly in the mod_python request. Rest is put into the headers_out member of the mod_python request. @param header: string, containing valid HTTP header. """ key, value = header.split(':',1) value = value.lstrip() if key.lower() == 'content-type': # save content-type for http_headers if not self._have_ct: # we only use the first content-type! self.mpyreq.content_type = value self._have_ct = 1 elif key.lower() == 'status': # save status for finish try: self.mpyreq.status = int(value.split(' ',1)[0]) except: pass else: self._have_status = 1 else: # this is a header we sent out self.mpyreq.headers_out[key]=value def http_headers(self, more_headers=[]): """ Sends out headers and possibly sets default content-type and status. @keyword more_headers: list of strings, defaults to [] """ for header in more_headers: self.setHttpHeader(header) # if we don't had an content-type header, set text/html if self._have_ct == 0: self.mpyreq.content_type = "text/html;charset=%s" % config.charset # if we don't had a status header, set 200 if self._have_status == 0: self.mpyreq.status = 200 # this is for mod_python 2.7.X, for 3.X it's a NOP self.mpyreq.send_http_header() # FastCGI ----------------------------------------------------------- class RequestFastCGI(RequestBase): """ specialized on FastCGI requests """ def __init__(self, fcgRequest, env, form, properties={}): """ Initializes variables from FastCGI environment and saves FastCGI request and form for further use. @param fcgRequest: the FastCGI request instance. @param env: environment passed by FastCGI. @param form: FieldStorage passed by FastCGI. """ self.fcgreq = fcgRequest self.fcgenv = env self.fcgform = form self._setup_vars_from_std_env(env) RequestBase.__init__(self, properties) def setup_args(self, form=None): """ Use the FastCGI form to setup arguments. """ if form is None: form = self.fcgform return self._setup_args_from_cgi_form(form) def read(self, n=None): """ Read from input stream. """ if n is None: return self.fcgreq.stdin.read() else: return self.fcgreq.stdin.read(n) def write(self, *data): """ Write to output stream. """ self.fcgreq.out.write("".join(data)) def flush(self): """ Flush output stream. """ self.fcgreq.flush_out() def finish(self): """ Call finish method of FastCGI request to finish handling of this request. """ self.fcgreq.finish() ############################################################################# ### Accessors ############################################################################# def getScriptname(self): """ Return the scriptname part of the URL ('/path/to/my.cgi'). """ name = self.script_name if name == '/': return '' return name def getPathinfo(self): """ Return the remaining part of the URL. """ pathinfo = self.path_info # Fix for bug in IIS/4.0 if os.name == 'nt': scriptname = self.getScriptname() if pathinfo.startswith(scriptname): pathinfo = pathinfo[len(scriptname):] return pathinfo ############################################################################# ### Headers ############################################################################# def setHttpHeader(self, header): """ Save header for later send. """ self.user_headers.append(header) def http_headers(self, more_headers=[]): """ Send out HTTP headers. Possibly set a default content-type. """ if self.sent_headers: #self.write("Headers already sent!!!\n") return self.sent_headers = 1 have_ct = 0 # send http headers for header in more_headers + self.user_headers: if header.lower().startswith("content-type:"): # don't send content-type multiple times! if have_ct: continue have_ct = 1 self.write("%s\r\n" % header) if not have_ct: self.write("Content-type: text/html;charset=%s\r\n" % config.charset) self.write('\r\n') #from pprint import pformat #sys.stderr.write(pformat(more_headers)) #sys.stderr.write(pformat(self.user_headers)) package test0574; public class X { public static void main(String[] args) { } }