blob: 960029818b9fd15d43ef3f30024b2686f0b540c7 [file] [log] [blame]
# -*- coding: iso-8859-1 -*-
"""
MoinMoin - Data associated with a single Request
@copyright: 2001-2003 by JΓΌrgen Hermann <jh@web.de>
@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("<p>" + _("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('<p>' + _("Can't work out query") + ' "<pre>' + query + '</pre>"')
# 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('<ul id="timings">\n')
for t in self.clock.dump():
self.write('<li>%s</li>\n' % t)
self.write('</ul>\n')
if 0: # temporarily disabled - do we need that?
import socket
from MoinMoin import version
self.write('<!-- MoinMoin %s on %s served this page in %s secs -->' % (
version.revision, socket.gethostname(), self.clock.value('total')) +
'</body></html>')
else:
self.write('</body>\n</html>\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<!-- ERROR REPORT FOLLOWS -->\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<hr>\n")
self.write("<p><strong>Additionally, cgitb raised this exception:</strong></p>\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("<h2>request.print_exception handler</h2>\n")
self.write("<h3>Traceback (most recent call last):</h3>\n")
list = traceback.format_tb(tb, limit) + \
traceback.format_exception_only(type, value)
self.write("<pre>%s<strong>%s</strong></pre>\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 test0577;
public class X {
public static void main(String[] args) {
}
}