mod_python-3.3.1/0000755000175000017500000000000010557377762012041 5ustar jimjimmod_python-3.3.1/test/0000755000175000017500000000000010557377762013020 5ustar jimjimmod_python-3.3.1/test/testconf.py.in0000644000175000017500000000073610345122535015607 0ustar jimjim# $Id: testconf.py.in 354172 2005-12-05 20:38:53Z nlehuen $ # This file is autogenerated by ./configure # Path to the Apache executable HTTPD="@HTTPD@" # Path to the current directory TESTHOME="@TEST_SERVER_ROOT@" # Path to the Apache modules directory LIBEXECDIR="@LIBEXECDIR@" # Path to the mod_python.so file, should be in the apache modules directory. MOD_PYTHON_SO="@MOD_PYTHON_SO@" # makes emacs go into python mode ### Local Variables: ### mode:python ### End: mod_python-3.3.1/test/httpdconf.py0000644000175000017500000002213410420420503015330 0ustar jimjim # # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License. You # may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # $Id: httpdconf.py 394455 2006-04-16 10:49:39Z grahamd $ # # Config maker, a la HTMLGen. This could grow into something useful. # class Directive: def __init__(self, name, val, flipslash=1): self.name = name self.val = val self.indent = 0 self.flipslash = flipslash def __str__(self): i = " " * self.indent s = i + '%s %s\n' % (self.name, self.val) if self.flipslash: s = s.replace("\\", "/") return s class Container: def __init__(self, *args): self.args = list(args) self.indent = 0 def append(self, value): self.args.append(value) def __str__(self): i = " " * self.indent s = "\n" for arg in self.args: s += i + "%s" % str(arg) return s class ContainerTag: def __init__(self, tag, attr, args, flipslash=1): self.tag = tag self.attr = attr self.args = args self.indent = 0 self.flipslash = flipslash def __str__(self): i = " " * self.indent s = i + "<%s %s>\n" % (self.tag, self.attr) if self.flipslash: s = s.replace("\\", "/") for arg in self.args: arg.indent = self.indent + 2 s += i + "%s" % str(arg) s += i + "\n" % self.tag return s class AddHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AddOutputFilter(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AddType(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthBasicAuthoritative(Directive): # New in Apache 2.2 def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthBasicProvider(Directive): # New in Apache 2.2 def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthType(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class AuthName(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class CustomLog(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Directory(ContainerTag): def __init__(self, dir, *args): ContainerTag.__init__(self, self.__class__.__name__, dir, args) class DirectoryIndex(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class DocumentRoot(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ErrorLog(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Files(ContainerTag): def __init__(self, dir, *args): ContainerTag.__init__(self, self.__class__.__name__, dir, args) class IfModule(ContainerTag): def __init__(self, dir, *args): ContainerTag.__init__(self, self.__class__.__name__, dir, args) class KeepAliveTimeout(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Listen(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class LoadModule(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class LogLevel(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class LogFormat(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val, flipslash=0) class LockFile(Directive): def __init__(self, val): import sys if sys.platform!='win32': Directive.__init__(self, self.__class__.__name__, val) else: Directive.__init__(self, '#'+self.__class__.__name__, val) class MaxClients(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxRequestsPerChild(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxSpareServers(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxSpareThreads(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MaxThreadsPerChild(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class MinSpareThreads(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class NumServers(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Options(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PidFile(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonAuthenHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonAuthzHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonConnectionHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonDebug(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonAccessHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonPostReadRequestHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonTransHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonFixupHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonImport(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonPath(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val, flipslash=0) class PythonOutputFilter(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonOption(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Require(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class SetHandler(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerAdmin(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerName(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerPath(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ServerRoot(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class StartServers(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class StartThreads(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class ThreadsPerChild(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class Timeout(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class TypesConfig(Directive): def __init__(self, val): Directive.__init__(self, self.__class__.__name__, val) class PythonInterpPerDirectory(Directive): def __init__(self, val='Off'): Directive.__init__(self, self.__class__.__name__, val) class PythonInterpPerDirective(Directive): def __init__(self, val='Off'): Directive.__init__(self, self.__class__.__name__, val) class VirtualHost(ContainerTag): def __init__(self, addr, *args): ContainerTag.__init__(self, self.__class__.__name__, addr, args) mod_python-3.3.1/test/htdocs/0000755000175000017500000000000010557377762014304 5ustar jimjimmod_python-3.3.1/test/htdocs/subdir/0000755000175000017500000000000010557377762015574 5ustar jimjimmod_python-3.3.1/test/htdocs/subdir/dummy.txt0000644000175000017500000000000010525773132017440 0ustar jimjimmod_python-3.3.1/test/htdocs/psp_parser.psp0000644000175000017500000000167310334714347017200 0ustar jimjim<%-- $Id: psp_parser.psp 332353 2005-11-10 19:00:55Z jgallacher $ --%> # format of this file # Comment lines are ignored (python or psp). # Lines beginning with test will be included, which # includes lines generated by python code. # Blank lines are ignored. # # The test format is "test:expected_result:test_string$" # where the string '$' is a token to indicate the end of the test line. # The '$' character was chosen as it's unlikely to be in the output of # the parser. # In processing the expected_result, the '-' character will be replace # by the '\' character. # The following substitutions will also be made in the expect_result # LF linefeed character # CR carriage-return character # TB tab character # BEGIN$ test:-n:\n$ test:-r:\r$ test:-t:\t$ test:-r-n:\r\n$ <% req.write("test:-n:\\n$") %> <% test_str='single_quotes' %> test:'single_quotes':'<%= test_str %>'$ <% test_str='double_quotes' %> test:"double_quotes":"<%= test_str %>"$ mod_python-3.3.1/test/htdocs/psptest.psp0000644000175000017500000000015310151454154016506 0ustar jimjim<%-- $Id: psptest.psp 106619 2004-11-25 22:10:52Z nd $ --%> <% if 1: req.write("t") %>est<%=" "+"ok"%> mod_python-3.3.1/test/htdocs/ssi.shtml0000644000175000017500000000014210427774570016142 0ustar jimjim mod_python-3.3.1/test/htdocs/psptest_main.psp0000644000175000017500000000012410462651642017516 0ustar jimjimokay <% psp.set_error_page('psptest_fail.psp') session['dummy'] = 1 raise 'fail' %> mod_python-3.3.1/test/htdocs/dummymodule.py0000644000175000017500000000036610415545552017207 0ustar jimjimfrom mod_python import apache apache.log_error("dummymodule / %s" % apache.interpreter) def function(): apache.log_error("dummymodule::function / %s" % apache.interpreter) apache.main_server.get_options()["dummymodule::function"] = "1" mod_python-3.3.1/test/htdocs/cgitest.py0000644000175000017500000000015110151454154016272 0ustar jimjim # $Id: cgitest.py 106619 2004-11-25 22:10:52Z nd $ print "Content-type: text/plain\n" print "test ok" mod_python-3.3.1/test/htdocs/tests.py0000644000175000017500000013555110525760314016012 0ustar jimjim # # # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License. You # may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # # $Id: tests.py 474119 2006-11-13 03:04:44Z grahamd $ # # mod_python tests from __future__ import generators from mod_python.python22 import * from mod_python import apache import unittest import re import time import os import cStringIO # This is used for mod_python.publisher security tests _SECRET_PASSWORD = 'root' __ANSWER = 42 class SimpleTestCase(unittest.TestCase): def __init__(self, methodName, req): unittest.TestCase.__init__(self, methodName) self.req = req def test_apache_log_error(self): s = self.req.server c = self.req.connection apache.log_error("Testing apache.log_error():", apache.APLOG_INFO, s) apache.log_error("xEMERGx", apache.APLOG_EMERG, s) apache.log_error("xALERTx", apache.APLOG_ALERT, s) apache.log_error("xCRITx", apache.APLOG_CRIT, s) apache.log_error("xERRx", apache.APLOG_ERR, s) apache.log_error("xWARNINGx", apache.APLOG_WARNING, s) apache.log_error("xNOTICEx", apache.APLOG_NOTICE, s) apache.log_error("xINFOx", apache.APLOG_INFO, s) apache.log_error("xDEBUGx", apache.APLOG_DEBUG, s) s.log_error("xEMERGx", apache.APLOG_EMERG) s.log_error("xALERTx", apache.APLOG_ALERT) s.log_error("xCRITx", apache.APLOG_CRIT) s.log_error("xERRx", apache.APLOG_ERR) s.log_error("xWARNINGx", apache.APLOG_WARNING) s.log_error("xNOTICEx", apache.APLOG_NOTICE) s.log_error("xINFOx", apache.APLOG_INFO) s.log_error("xDEBUGx", apache.APLOG_DEBUG) c.log_error("xEMERGx", apache.APLOG_EMERG) c.log_error("xALERTx", apache.APLOG_ALERT) c.log_error("xCRITx", apache.APLOG_CRIT) c.log_error("xERRx", apache.APLOG_ERR) c.log_error("xWARNINGx", apache.APLOG_WARNING) c.log_error("xNOTICEx", apache.APLOG_NOTICE) c.log_error("xINFOx", apache.APLOG_INFO) c.log_error("xDEBUGx", apache.APLOG_DEBUG) # see what's in the log now f = open("%s/logs/error_log" % apache.server_root()) # for some reason re doesn't like \n, why? import string log = "".join(map(string.strip, f.readlines())) f.close() if not re.search("xEMERGx.*xALERTx.*xCRITx.*xERRx.*xWARNINGx.*xNOTICEx.*xINFOx.*xDEBUGx.*xEMERGx.*xALERTx.*xCRITx.*xERRx.*xWARNINGx.*xNOTICEx.*xINFOx.*xDEBUGx.*xEMERGx.*xALERTx.*xCRITx.*xERRx.*xWARNINGx.*xNOTICEx.*xINFOx.*xDEBUGx", log): self.fail("Could not find test messages in error_log") def test_apache_table(self): log = self.req.log_error log("Testing table object.") # tests borrowed from Python test suite for dict _test_table() # inheritance log(" inheritance") class mytable(apache.table): def __str__(self): return "str() from mytable" mt = mytable({'a':'b'}) # add() log(" table.add()") a = apache.table({'a':'b'}) a.add('a', 'c') if a['a'] != ['b', 'c']: self.fail('table.add() broken: a["a"] is %s' % `a["a"]`) log("Table test DONE.") def test_req_add_common_vars(self): self.req.log_error("Testing req.add_common_vars().") a = len(self.req.subprocess_env) self.req.add_common_vars() b = len(self.req.subprocess_env) if a >= b: self.fail("req.subprocess_env() is same size before and after") def test_req_members(self): # just run through request members making sure # they make sense req = self.req log = req.log_error log("Examining request memebers:") log(" req.connection: %s" % `req.connection`) s = str(type(req.connection)) if s != "": self.fail("strange req.connection type %s" % `s`) log(" req.server: '%s'" % `req.server`) s = str(type(req.server)) if s != "": self.fail("strange req.server type %s" % `s`) for x in ((req.next, "next"), (req.prev, "prev"), (req.main, "main")): val, name = x log(" req.%s: '%s'" % (name, `val`)) if val: self.fail("strange, req.%s should be None, not %s" % (name, `val`)) log(" req.the_request: '%s'" % req.the_request) if not re.match(r"GET /.* HTTP/1\.", req.the_request): self.fail("strange req.the_request %s" % `req.the_request`) for x in ((req.assbackwards, "assbackwards"), (req.proxyreq, "proxyreq"), (req.header_only, "header_only")): val, name = x log(" req.%s: %s" % (name, `val`)) if val: self.fail("%s should be 0" % name) log(" req.protocol: %s" % `req.protocol`) if not req.protocol == req.the_request.split()[-1]: self.fail("req.protocol doesn't match req.the_request") log(" req.proto_num: %s" % `req.proto_num`) if req.proto_num != 1000 + int(req.protocol[-1]): self.fail("req.proto_num doesn't match req.protocol") log(" req.hostname: %s" % `req.hostname`) if req.hostname != "test_internal": self.fail("req.hostname isn't 'test_internal'") log(" req.request_time: %s" % `req.request_time`) if (time.time() - req.request_time) > 10: self.fail("req.request_time suggests request started more than 10 secs ago") log(" req.status_line: %s" % `req.status_line`) if req.status_line: self.fail("req.status_line should be None at this point") log(" req.status: %s" % `req.status`) if req.status != 200: self.fail("req.status should be 200") req.status = req.status # make sure its writable log(" req.method: %s" % `req.method`) if req.method != "GET": self.fail("req.method should be 'GET'") log(" req.method_number: %s" % `req.method_number`) if req.method_number != 0: self.fail("req.method_number should be 0") log(" req.allowed: %s" % `req.allowed`) if req.allowed != 0: self.fail("req.allowed should be 0") log(" req.allowed_xmethods: %s" % `req.allowed_xmethods`) if req.allowed_xmethods != (): self.fail("req.allowed_xmethods should be an empty tuple") log(" req.allowed_methods: %s" % `req.allowed_methods`) if req.allowed_methods != (): self.fail("req.allowed_methods should be an empty tuple") log(" req.sent_bodyct: %s" % `req.sent_bodyct`) if req.sent_bodyct != 0: self.fail("req.sent_bodyct should be 0") log(" req.bytes_sent: %s" % `req.bytes_sent`) save = req.bytes_sent log(" writing 4 bytes...") req.write("1234") log(" req.bytes_sent: %s" % `req.bytes_sent`) if req.bytes_sent - save != 4: self.fail("req.bytes_sent should have incremented by 4, but didn't") log(" req.mtime: %s" % `req.mtime`) if req.mtime != 0: self.fail("req.mtime should be 0") log(" req.chunked: %s" % `req.chunked`) if req.chunked != 1: self.fail("req.chunked should be 1") log(" req.range: %s" % `req.range`) if req.range: self.fail("req.range should be None") log(" req.clength: %s" % `req.clength`) log(" calling req.set_content_length(15)...") req.set_content_length(15) log(" req.clength: %s" % `req.clength`) if req.clength != 15: self.fail("req.clength should be 15") log(" req.remaining: %s" % `req.remaining`) if req.remaining != 0: self.fail("req.remaining should be 0") log(" req.read_length: %s" % `req.read_length`) if req.read_length != 0: self.fail("req.read_length should be 0") log(" req.read_body: %s" % `req.read_body`) if req.read_body != 0: self.fail("req.read_body should be 0") log(" req.read_chunked: %s" % `req.read_chunked`) if req.read_chunked != 0: self.fail("req.read_chunked should be 0") log(" req.expecting_100: %s" % `req.expecting_100`) if req.expecting_100 != 0: self.fail("req.expecting_100 should be 0") log(" req.headers_in: %s" % `req.headers_in`) if req.headers_in["Host"][:13].lower() != "test_internal": self.fail("The 'Host' header should begin with 'test_internal'") log(" req.headers_out: %s" % `req.headers_out`) if ((not req.headers_out.has_key("content-length")) or req.headers_out["content-length"] != "15"): self.fail("req.headers_out['content-length'] should be 15") log(" req.subprocess_env: %s" % `req.subprocess_env`) if req.subprocess_env["SERVER_SOFTWARE"].find("Python") == -1: self.fail("req.subprocess_env['SERVER_SOFTWARE'] should contain 'Python'") log(" req.notes: %s" % `req.notes`) log(" doing req.notes['testing'] = '123' ...") req.notes['testing'] = '123' log(" req.notes: %s" % `req.notes`) if req.notes["testing"] != '123': self.fail("req.notes['testing'] should be '123'") log(" req.phase: %s" % `req.phase`) if req.phase != "PythonHandler": self.fail("req.phase should be 'PythonHandler'") log(" req.interpreter: %s" % `req.interpreter`) if req.interpreter != apache.interpreter: self.fail("req.interpreter should be same as apache.interpreter" % `apache.interpreter`) if req.interpreter != req.server.server_hostname: self.fail("req.interpreter should be same as req.server.server_hostname: %s" % `req.server.server_hostname`) log(" req.content_type: %s" % `req.content_type`) log(" doing req.content_type = 'test/123' ...") req.content_type = 'test/123' log(" req.content_type: %s" % `req.content_type`) if req.content_type != 'test/123' or not req._content_type_set: self.fail("req.content_type should be 'test/123' and req._content_type_set 1") log(" req.handler: %s" % `req.handler`) if req.handler != "mod_python": self.fail("req.handler should be 'mod_python'") log(" req.content_encoding: %s" % `req.content_encoding`) if req.content_encoding: self.fail("req.content_encoding should be None") log(" req.content_languages: %s" % `req.content_languages`) if req.content_languages != (): self.fail("req.content_languages should be an empty tuple") log(" req.vlist_validator: %s" % `req.vlist_validator`) if req.vlist_validator: self.fail("req.vlist_validator should be None") log(" req.user: %s" % `req.user`) if req.user: self.fail("req.user should be None") log(" req.ap_auth_type: %s" % `req.ap_auth_type`) if req.ap_auth_type: self.fail("req.ap_auth_type should be None") log(" req.no_cache: %s" % `req.no_cache`) if req.no_cache != 0: self.fail("req.no_cache should be 0") log(" req.no_local_copy: %s" % `req.no_local_copy`) if req.no_local_copy != 0: self.fail("req.no_local_copy should be 0") log(" req.unparsed_uri: %s" % `req.unparsed_uri`) if req.unparsed_uri != "/tests.py": self.fail("req.unparsed_uri should be '/tests.py'") log(" req.uri: %s" % `req.uri`) if req.uri != "/tests.py": self.fail("req.uri should be '/tests.py'") log(" req.filename: %s" % `req.filename`) if req.filename != req.document_root() + req.uri: self.fail("req.filename should be req.document_root() + req.uri, but it isn't") log(" req.canonical_filename: %s" % `req.canonical_filename`) if not req.canonical_filename: self.fail("req.canonical_filename should not be blank") log(" req.path_info: %s" % `req.path_info`) if req.path_info != '': self.fail("req.path_info should be ''") log(" req.args: %s" % `req.args`) if req.args: self.fail("req.args should be None") log(" req.finfo: %s" % `req.finfo`) if req.finfo[apache.FINFO_FNAME] and (req.finfo[apache.FINFO_FNAME] != req.canonical_filename): self.fail("req.finfo[apache.FINFO_FNAME] should be the (canonical) filename") log(" req.parsed_uri: %s" % `req.parsed_uri`) if req.parsed_uri[apache.URI_PATH] != '/tests.py': self.fail("req.parsed_uri[apache.URI_PATH] should be '/tests.py'") log(" req.used_path_info: %s" % `req.used_path_info`) if req.used_path_info != 2: self.fail("req.used_path_info should be 2") # XXX really? :-) log(" req.eos_sent: %s" % `req.eos_sent`) if req.eos_sent: self.fail("req.eos_sent says we sent EOS, but we didn't") def test_req_get_config(self): req = self.req log = req.log_error log("req.get_config(): %s" % `req.get_config()`) if req.get_config()["PythonDebug"] != "1": self.fail("get_config return should show PythonDebug 1") log("req.get_options(): %s" % `req.get_options()`) for option in apache.main_server.get_options().keys(): del req.get_options()[option] if req.get_options() != apache.table({"testing":"123"}): self.fail("get_options() should contain 'testing':'123', contains %s"%req.get_options().items()) def test_req_get_remote_host(self): # simulating this test for real is too complex... req = self.req log = req.log_error log("req.get_get_remote_host(): %s" % `req.get_remote_host(apache.REMOTE_HOST)`) log("req.get_get_remote_host(): %s" % `req.get_remote_host()`) if (req.get_remote_host(apache.REMOTE_HOST) != None) or \ (req.get_remote_host() != "127.0.0.1"): self.fail("remote host test failed") def test_server_members(self): req = self.req log = req.log_error server = req.server log("Examining server memebers:") log(" server.defn_name: %s" % `server.defn_name`) if server.defn_name[-9:] != "test.conf": self.fail("server.defn_name does not end in 'test.conf'") log(" server.defn_line_number: %s" % `server.defn_line_number`) if server.defn_line_number == 0: self.fail("server.defn_line_number should not be 0") log(" server.server_admin: %s" % `server.server_admin`) if server.server_admin != "serveradmin@somewhere.com": self.fail("server.server_admin must be 'serveradmin@somewhere.com'") log(" server.server_hostname: %s" % `server.server_hostname`) if server.server_hostname != "test_internal": self.fail("server.server_hostname must be 'test_internal'") log(" server.port: %s" % `server.port`) # hmm it really is 0... #if server.port == 0: # self.fail("server.port should not be 0") log(" server.error_fname: %s" % `server.error_fname`) if server.error_fname != "logs/error_log": self.fail("server.error_fname should be 'logs/error_log'") log(" server.loglevel: %s" % `server.loglevel`) if server.loglevel != 7: self.fail("server.loglevel should be 7") log(" server.is_virtual: %s" % `server.is_virtual`) if server.is_virtual != 1: self.fail("server.is_virtual should be 1") log(" server.timeout: %s" % `server.timeout`) if not server.timeout in (5.0, 300.0): self.fail("server.timeout should be 5.0 or 300.0") log(" server.keep_alive_timeout: %s" % `server.keep_alive_timeout`) if server.keep_alive_timeout != 15.0: self.fail("server.keep_alive_timeout should be 15.0") log(" server.keep_alive_max: %s" % `server.keep_alive_max`) if server.keep_alive_max != 100: self.fail("server.keep_alive_max should be 100") log(" server.keep_alive: %s" % `server.keep_alive`) if server.keep_alive != 1: self.fail("server.keep_alive should be 1") log(" server.path: %s" % `server.path`) if server.path != "some/path": self.fail("server.path should be 'some/path'") log(" server.pathlen: %s" % `server.pathlen`) if server.pathlen != len('some/path'): self.fail("server.pathlen should be %d" % len('some/path')) log(" server.limit_req_line: %s" % `server.limit_req_line`) if server.limit_req_line != 8190: self.fail("server.limit_req_line should be 8190") log(" server.limit_req_fieldsize: %s" % `server.limit_req_fieldsize`) if server.limit_req_fieldsize != 8190: self.fail("server.limit_req_fieldsize should be 8190") log(" server.limit_req_fields: %s" % `server.limit_req_fields`) if server.limit_req_fields != 100: self.fail("server.limit_req_fields should be 100") log(" server.names: %s" % `server.names`) if server.names != (): self.fail("server.names should be an empty tuple") log(" server.wild_names: %s" % `server.wild_names`) if server.wild_names != (): self.fail("server.wild_names should be an empty tuple") def test_connection_members(self): req = self.req log = req.log_error conn = req.connection try: import socket localip = socket.gethostbyname("localhost") except: localip = "127.0.0.1" log("Examining connection memebers:") log(" connection.base_server: %s" % `conn.base_server`) if type(conn.base_server) is not type(req.server): self.fail("conn.base_server should be same type as req.server") log(" connection.local_addr: %s" % `conn.local_addr`) if not conn.local_addr[0] in ("127.0.0.1", "0.0.0.0", localip): self.fail("conn.local_addr[0] should be '127.0.0.1' or '0.0.0.0'") log(" connection.remote_addr: %s" % `conn.remote_addr`) if not conn.remote_addr[0] in ("127.0.0.1", "0.0.0.0", localip): self.fail("conn.remote_addr[0] should be '127.0.0.1' or '0.0.0.0'") log(" connection.remote_ip: %s" % `conn.remote_ip`) if not conn.remote_ip in ("127.0.0.1", localip): self.fail("conn.remote_ip should be '127.0.0.1'") log(" connection.remote_host: %s" % `conn.remote_host`) if conn.remote_host is not None: self.fail("conn.remote_host should be None") log(" connection.remote_logname: %s" % `conn.remote_logname`) if conn.remote_logname is not None: self.fail("conn.remote_logname should be None") log(" connection.aborted: %s" % `conn.aborted`) if conn.aborted != 0: self.fail("conn.aborted should be 0") log(" connection.keepalive: %s" % `conn.keepalive`) if conn.keepalive != 2: self.fail("conn.keepalive should be 2") log(" connection.double_reverse: %s" % `conn.double_reverse`) if conn.double_reverse != 0: self.fail("conn.double_reverse should be 0") log(" connection.keepalives: %s" % `conn.keepalives`) if conn.keepalives != 1: self.fail("conn.keepalives should be 1") log(" connection.local_ip: %s" % `conn.local_ip`) if not conn.local_ip in ("127.0.0.1", localip): self.fail("conn.local_ip should be '127.0.0.1'") log(" connection.local_host: %s" % `conn.local_host`) if conn.local_host is not None: self.fail("conn.local_host should be None") log(" connection.id: %s" % `conn.id`) if conn.id > 100: self.fail("conn.id should not be this high") log(" connection.notes: %s" % `conn.notes`) if `conn.notes` != '{}': self.fail("conn.notes should be {}") def make_suite(req): mpTestSuite = unittest.TestSuite() mpTestSuite.addTest(SimpleTestCase("test_apache_log_error", req)) mpTestSuite.addTest(SimpleTestCase("test_apache_table", req)) mpTestSuite.addTest(SimpleTestCase("test_req_add_common_vars", req)) mpTestSuite.addTest(SimpleTestCase("test_req_members", req)) mpTestSuite.addTest(SimpleTestCase("test_req_get_config", req)) mpTestSuite.addTest(SimpleTestCase("test_req_get_remote_host", req)) mpTestSuite.addTest(SimpleTestCase("test_server_members", req)) mpTestSuite.addTest(SimpleTestCase("test_connection_members", req)) return mpTestSuite def handler(req): out = cStringIO.StringIO() tr = unittest.TextTestRunner(out) result = tr.run(make_suite(req)) req.log_error(out.getvalue()) if result.wasSuccessful(): req.write("test ok") else: req.write("test failed") return apache.OK def simple_handler(req): # for req_add_handler() if (req.secret_message == "foo"): req.write("test ok") return apache.OK def req_add_handler(req): req.secret_message = "foo" req.add_handler("PythonHandler", "tests::simple_handler") req.add_handler("PythonHandler", simple_handler) return apache.OK def req_add_bad_handler(req): # bad_handler does not exist so adding it should # should raise an AttributeError exception req.log_error("req_add_bad_handler") req.add_handler("PythonHandler", "tests::bad_handler") req.write("test ok") return apache.OK def req_add_empty_handler_string(req): # Adding an empty string as a handler should should # should raise an exception req.log_error("req_add_empty_handler_string") req.add_handler("PythonHandler", "") req.write("no exception") return apache.OK def req_add_handler_empty_phase(req): req.log_error("req_add_handler_empty_phase") req.log_error("phase=%s" % req.phase) req.log_error("interpreter=%s" % req.interpreter) req.log_error("directory=%s" % req.hlist.directory) if req.phase != "PythonHandler": directory = os.path.dirname(__file__) req.add_handler("PythonHandler", "tests::req_add_handler_empty_phase", directory) else: req.write("test ok") return apache.OK def accesshandler_add_handler_to_empty_hl(req): # Prior to version 3.2.6, adding a python handler # to and empty handler list would cause a segfault req.secret_message = "foo" req.log_error("accesshandler_add_handler_to_empty_hl") req.add_handler("PythonHandler", "tests::simple_handler") return apache.OK def test_req_add_handler_directory(req): # dir1 will not have a trailing slash and on Win32 # will use back slashes and not forward slashes. dir1 = os.path.dirname(__file__) if req.phase == "PythonFixupHandler": req.add_handler("PythonHandler", "tests::test_req_add_handler_directory", dir1) else: # dir2 should only use forward slashes and # should have a trailing forward slash added by # call to req.add_handler(). When dir1 and dir2 # are normalised for current operating system, # they should be equivalent. dir2 = req.hlist.directory if dir2[-1] != '/' or dir2.count('\\') != 0: req.write('test failed') else: dir1 = os.path.normpath(dir1) dir2 = os.path.normpath(dir2) if dir2 != dir1: req.write('test failed') else: req.write('test ok') return apache.OK def req_allow_methods(req): req.allow_methods(["PYTHONIZE"]) return apache.HTTP_METHOD_NOT_ALLOWED def req_get_basic_auth_pw(req): pw = req.get_basic_auth_pw() if req.user != "spam" or pw != "eggs": req.write("test failed") else: req.write("test ok") return apache.OK def req_auth_type(req): if req.phase == "PythonAuthenHandler": if req.auth_type() != "dummy": req.log_error("auth_type check failed") req.write("test failed") return apache.DONE if req.auth_name() != "blah": req.log_error("auth_name check failed") req.write("test failed") return apache.DONE req.user = "dummy" req.ap_auth_type = req.auth_type() elif req.phase == "PythonAuthzHandler": if req.ap_auth_type != "dummy": req.log_error("ap_auth_type check failed") req.write("test failed") return apache.DONE if req.user != "dummy": req.log_error("user check failed") req.write("test failed") return apache.DONE else: if req.ap_auth_type != "dummy": req.log_error("ap_auth_type check failed") req.write("test failed") return apache.DONE if req.user != "dummy": req.log_error("user check failed") req.write("test failed") return apache.DONE req.write("test ok") return apache.OK def req_requires(req): if req.requires() == ('valid-user',): req.write("test ok") return apache.DONE req.write("test failed") return apache.DONE def req_document_root(req): req.write(req.document_root()) return apache.OK def req_internal_redirect(req): req.internal_redirect("/test.int") return apache.OK def req_internal_redirect_int(req): # used by req_internal_redirect req.prev.write("test ") req.write("ok") return apache.OK def req_construct_url(req): url = req.construct_url("/index.html") if not re.match("^http://test_req_construct_url:[0-9]+/index.html$",url): req.write("test failed") else: req.write("test ok") return apache.OK def req_read(req): s = req.read() req.write(s) return apache.OK def req_readline(req): s = req.readline() while s: req.write(s) s = req.readline() return apache.OK def req_readlines(req): if 'SizeHint' in req.headers_in: lines = req.readlines(int(req.headers_in['SizeHint'])) else: lines = req.readlines() req.write("".join(lines)) return apache.OK def req_discard_request_body(req): s = req.read(10) if s != '1234567890': req.log_error('read() #1 returned %s' % `s`) req.write('test failed') return apache.OK status = req.discard_request_body() if status != apache.OK: req.log_error('discard_request_body() returned %d' % status) return status s = req.read() if s: req.log_error('read() #2 returned %s' % `s`) req.write('test failed') return apache.OK req.write('test ok') return apache.OK def req_register_cleanup(req): req.cleanup_data = "req_register_cleanup test ok" req.register_cleanup(cleanup, req) req.write("registered cleanup that will write to log") return apache.OK def cleanup(data): # for req_register_cleanup above data.log_error(data.cleanup_data) def server_cleanup(data): # for srv_register_cleanup and apache_register_cleanup below apache.log_error(data) def req_headers_out(req): req.headers_out["X-Test-Header"] = "test ok" req.write("test ok") return apache.OK def req_headers_out_access(req): return apache.OK def req_sendfile(req): import tempfile fname = tempfile.mktemp("txt") f = open(fname, "w") f.write(" test ok "); f.close() req.sendfile(fname, 2, 7) # os.remove(fname) return apache.OK def req_sendfile2(req): import tempfile fname = tempfile.mktemp("txt") f = open(fname, "w") f.write("0123456789"*100); f.close() req.sendfile(fname) # os.remove(fname) return apache.OK def req_sendfile3(req): """Check if sendfile handles symlinks properly. This is only valid on posix systems. """ import tempfile # note mktemp is deprecated in python 2.3. Should use mkstemp instead. fname = tempfile.mktemp("txt") f = open(fname, "w") f.write("0123456789"*100); f.close() fname_symlink = '%s.lnk' % fname os.symlink(fname, fname_symlink) req.sendfile(fname_symlink) os.remove(fname_symlink) os.remove(fname) return apache.OK def req_handler(req): if req.phase == "PythonFixupHandler": req.handler = "mod_python" req.handler = None req.handler = "mod_python" req.add_handler("PythonHandler","tests::req_handler") return apache.OK elif req.phase == "PythonHandler": req.write('test ok') return apache.OK else: req.write('test failed') return apache.OK def req_no_cache(req): req.no_cache = 1 req.write('test ok') return apache.OK def req_update_mtime(req): assert(req.mtime == 0.0) req.update_mtime(100.0) assert(req.mtime == 100.0) req.set_etag() req.set_last_modified() req.write('test ok') return apache.OK def util_redirect(req): from mod_python import util if req.main: # Sub request for ErrorDocument. req.write("test failed") return apache.DONE else: if req.phase == "PythonFixupHandler": util.redirect(req,location="/dummy",text="test ok") else: req.write('test failed') return apache.OK def req_server_get_config(req): if req.server.get_config().get("PythonDebug","0") != "1" or \ req.get_config().get("PythonDebug","0") != "0": req.write('test failed') else: req.write('test ok') return apache.OK def req_server_get_options(req): try: server_options = apache.main_server.get_options() assert(server_options.get("global","0") == "0") assert(server_options.get("override","0") == "0") server_options = req.connection.base_server.get_options() assert(server_options.get("global","0") == "0") assert(server_options.get("override","0") == "0") server_options = req.server.get_options() assert(server_options["global"] == "1") assert(server_options["override"] == "1") request_options = req.get_options() assert(request_options["global"] == "1") assert(request_options["override"] == "2") assert(request_options["local"] == "1") except: req.write('test failed') else: req.write('test ok') return apache.OK def fileupload(req): from mod_python import util import md5 fields = util.FieldStorage(req) f = fields.getfirst('testfile') req.write(md5.new(f.file.read()).hexdigest()) return apache.OK def srv_register_cleanup(req): req.server.register_cleanup(req, server_cleanup, "srv_register_cleanup test ok") req.write("registered server cleanup that will write to log") return apache.OK def apache_register_cleanup(req): apache.register_cleanup(server_cleanup, "apache_register_cleanup test ok") req.write("registered server cleanup that will write to log") return apache.OK def apache_exists_config_define(req): if apache.exists_config_define('FOOBAR'): req.write('FOOBAR') else: req.write('NO_FOOBAR') return apache.OK def util_fieldstorage(req): from mod_python import util req.write(`util.FieldStorage(req).list`) return apache.OK def postreadrequest(req): req.log_error('postreadrequest') req.add_common_vars() req.subprocess_env['TEST1'] = "'" req.subprocess_env['TEST2'] = '"' req.log_error('subprocess_env = %s' % req.subprocess_env) req.log_error('subprocess_env.values() = %s' % req.subprocess_env.values()) for value in req.subprocess_env.itervalues(): req.log_error('VALUE = %s' % value) for item in req.subprocess_env.iteritems(): req.log_error('ITEM = %s' % (item,)) req.log_error('SCRIPT_FILENAME = %s' % req.subprocess_env.get('SCRIPT_FILENAME')) req.log_error('SCRIPT_FILENAME = %s' % req.subprocess_env['SCRIPT_FILENAME']) req.write("test ok") return apache.DONE def trans(req): req.filename = req.document_root()+"/tests.py" return apache.OK def import_test(req): import sys, os directory = os.path.dirname(__file__) assert(map(os.path.normpath, sys.path).count(directory) == 1) if sys.modules.has_key("dummymodule"): if not apache.main_server.get_options().has_key("dummymodule::function"): req.log_error("dummymodule::function not executed") req.write("test failed") else: req.write("test ok") else: req.log_error("dummymodule not found in sys.modules") req.write("test failed") return apache.OK def outputfilter1(filter): s = filter.read() while s: filter.write(s.upper()) s = filter.read() if s is None: filter.close() return apache.OK def outputfilter2(filter): s = filter.read() while s: for c in s: filter.write(2*c) s = filter.read() if s is None: filter.close() return apache.OK def simplehandler(req): if req.phase != "PythonHandler": req.write("test failed") return apache.OK req.write("test ok") if req.phase != "PythonHandler": req.write("test failed") return apache.OK return apache.OK def req_add_output_filter(req): req.add_output_filter("MP_TEST_FILTER") req.write("test ok") return apache.OK def req_register_output_filter(req): req.register_output_filter("MP_TEST_FILTER1","tests::outputfilter1") req.register_output_filter("MP_TEST_FILTER2",outputfilter2) req.add_output_filter("MP_TEST_FILTER1") req.add_output_filter("MP_TEST_FILTER2") req.write("test ok") return apache.OK def connectionhandler(conn): # read whatever s = conn.readline().strip() while s: s = conn.readline().strip() # fake an HTTP response conn.write("HTTP/1.1 200 OK\r\n") conn.write("Content-Length: 7\r\n\r\n") conn.write("test ok") return apache.OK def pipe_ext(req): # this is called by publisher return "pipe ext" def Cookie_Cookie(req): from mod_python import Cookie cookies = Cookie.get_cookies(req) for k in cookies: Cookie.add_cookie(req, cookies[k]) req.write("test ok") return apache.OK def Cookie_MarshalCookie(req): from mod_python import Cookie cookies = Cookie.get_cookies(req, Cookie.MarshalCookie, secret="secret") for k in cookies: Cookie.add_cookie(req, cookies[k]) req.write("test ok") return apache.OK def global_lock(req): import _apache _apache._global_lock(req.server, 1) time.sleep(1) _apache._global_unlock(req.server, 1) req.write("test ok") return apache.OK def Session_Session(req): from mod_python import Session, Cookie s = Session.Session(req) if s.is_new(): s.save() cookies = Cookie.get_cookies(req) if cookies.has_key(Session.COOKIE_NAME) and s.is_new(): req.write(str(cookies[Session.COOKIE_NAME])) else: req.write("test ok") return apache.OK def files_directive(req): req.write(str(req.hlist.directory)) return apache.OK none_handler = None def server_return_1(req): raise apache.SERVER_RETURN, apache.OK def server_return_2(req): req.write("test ok") return apache.OK def phase_status_1(req): apache.log_error("phase_status_1") req.phases = [1] return apache.DECLINED def phase_status_2(req): apache.log_error("phase_status_2") req.phases.append(2) req.user = "bogus" req.ap_auth_type = "bogus" return apache.OK def phase_status_3(req): apache.log_error("phase_status_3") req.phases.append(3) return apache.OK def phase_status_4(req): apache.log_error("phase_status_4") #req.phases.append(4) return apache.OK def phase_status_5(req): apache.log_error("phase_status_5") req.phases.append(5) return apache.DECLINED def phase_status_6(req): apache.log_error("phase_status_6") req.phases.append(6) return apache.OK def phase_status_7(req): apache.log_error("phase_status_7") req.phases.append(7) return apache.OK def phase_status_8(req): apache.log_error("phase_status_8") apache.log_error("phases = %s" % req.phases) if req.phases != [1, 2, 5, 6, 7]: req.write("test failed") else: req.write("test ok") return apache.OK def test_sys_argv(req): import sys req.write(repr(sys.argv)) return apache.OK def PythonOption_items(req): options = req.get_options().items() # The tests may using PythonOption mod_python.* in the test configuration # We need to remove those particular options so they don't interfer # with this test result. options = [ o for o in options if not o[0].startswith('mod_python') ] options.sort() req.write(str(options)) return apache.OK def interpreter(req): if req.phase == "PythonFixupHandler": if req.filename[-1] != '/' and os.path.isdir(req.filename): req.write(req.interpreter) return apache.DONE return apache.OK else: req.write(req.interpreter) return apache.DONE def index(req): return "test ok, interpreter=%s" % req.interpreter def test_publisher(req): return "test ok, interpreter=%s" % req.interpreter def test_publisher_auth_nested(req): def __auth__(req, user, password): test_globals = test_publisher req.notes["auth_called"] = "1" return user == "spam" and password == "eggs" def __access__(req, user): req.notes["access_called"] = "1" return 1 assert(int(req.notes.get("auth_called",0))) assert(int(req.notes.get("access_called",0))) return "test ok, interpreter=%s" % req.interpreter class _test_publisher_auth_method_nested: def method(self, req): def __auth__(req, user, password): test_globals = test_publisher req.notes["auth_called"] = "1" return user == "spam" and password == "eggs" def __access__(req, user): req.notes["access_called"] = "1" return 1 assert(int(req.notes.get("auth_called",0))) assert(int(req.notes.get("access_called",0))) return "test ok, interpreter=%s" % req.interpreter test_publisher_auth_method_nested = _test_publisher_auth_method_nested() class OldStyleClassTest: def __init__(self): pass def __call__(self, req): return "test callable old-style instance ok" def traverse(self, req): return "test traversable old-style instance ok" old_instance = OldStyleClassTest() test_dict = {1:1, 2:2, 3:3} test_dict_keys = test_dict.keys def test_dict_iteration(req): return test_dict_keys() def test_generator(req): c = 0 while c < 10: yield c c += 1 def server_side_include(req): req.ssi_globals = { "data": "test" } return apache.OK class InstanceTest(object): def __call__(self, req): return "test callable instance ok" def traverse(self, req): return "test traversable instance ok" instance = InstanceTest() # Hierarchy traversal tests class Mapping(object): def __init__(self,name): self.name = name def __call__(self,req): return "Called %s"%self.name hierarchy_root = Mapping("root"); hierarchy_root.page1 = Mapping("page1") hierarchy_root.page1.subpage1 = Mapping("subpage1") hierarchy_root.page2 = Mapping("page2") class Mapping2: pass hierarchy_root_2 = Mapping2() hierarchy_root_2.__call__ = index hierarchy_root_2.page1 = index hierarchy_root_2.page2 = index def _test_table(): log = apache.log_error log(" starting _test_table") d = apache.table() if d.keys() != []: raise TestFailed, '{}.keys()' if d.has_key('a') != 0: raise TestFailed, '{}.has_key(\'a\')' if ('a' in d) != 0: raise TestFailed, "'a' in {}" if ('a' not in d) != 1: raise TestFailed, "'a' not in {}" if len(d) != 0: raise TestFailed, 'len({})' d = {'a': 1, 'b': 2} if len(d) != 2: raise TestFailed, 'len(dict)' k = d.keys() k.sort() if k != ['a', 'b']: raise TestFailed, 'dict keys()' if d.has_key('a') and d.has_key('b') and not d.has_key('c'): pass else: raise TestFailed, 'dict keys()' if 'a' in d and 'b' in d and 'c' not in d: pass else: raise TestFailed, 'dict keys() # in/not in version' if d['a'] != 1 or d['b'] != 2: raise TestFailed, 'dict item' d['c'] = 3 d['a'] = 4 if d['c'] != 3 or d['a'] != 4: raise TestFailed, 'dict item assignment' del d['b'] if d != {'a': 4, 'c': 3}: raise TestFailed, 'dict item deletion' # dict.clear() log(" table.clear()") d = apache.table() d['1'] = '1' d['2'] = '2' d['3'] = '3' d.clear() if d != apache.table(): raise TestFailed, 'dict clear' # dict.update() log(" table.update()") d.update({'1':'100'}) d.update({'2':'20'}) d.update({'1':'1', '2':'2', '3':'3'}) if d != apache.table({'1':'1', '2':'2', '3':'3'}): raise TestFailed, 'dict update' d.clear() try: d.update(None) except AttributeError: pass else: raise TestFailed, 'dict.update(None), AttributeError expected' class SimpleUserDict: def __init__(self): self.d = {1:1, 2:2, 3:3} def keys(self): return self.d.keys() def __getitem__(self, i): return self.d[i] d.update(SimpleUserDict()) if d != apache.table({1:1, 2:2, 3:3}): raise TestFailed, 'dict.update(instance)' d.clear() class FailingUserDict: def keys(self): raise ValueError try: d.update(FailingUserDict()) except ValueError: pass else: raise TestFailed, 'dict.keys() expected ValueError' class FailingUserDict: def keys(self): class BogonIter: def __iter__(self): raise ValueError return BogonIter() try: d.update(FailingUserDict()) except ValueError: pass else: raise TestFailed, 'iter(dict.keys()) expected ValueError' class FailingUserDict: def keys(self): class BogonIter: def __init__(self): self.i = 1 def __iter__(self): return self def next(self): if self.i: self.i = 0 return 'a' raise ValueError return BogonIter() def __getitem__(self, key): return key try: d.update(FailingUserDict()) except ValueError: pass else: raise TestFailed, 'iter(dict.keys()).next() expected ValueError' class FailingUserDict: def keys(self): class BogonIter: def __init__(self): self.i = ord('a') def __iter__(self): return self def next(self): if self.i <= ord('z'): rtn = chr(self.i) self.i += 1 return rtn raise StopIteration return BogonIter() def __getitem__(self, key): raise ValueError try: d.update(FailingUserDict()) except ValueError: pass else: raise TestFailed, 'dict.update(), __getitem__ expected ValueError' # dict.copy() log(" table.copy()") d = {1:1, 2:2, 3:3} if d.copy() != {1:1, 2:2, 3:3}: raise TestFailed, 'dict copy' if apache.table().copy() != apache.table(): raise TestFailed, 'empty dict copy' # dict.get() log(" table.get()") d = apache.table() if d.get('c') is not None: raise TestFailed, 'missing {} get, no 2nd arg' if d.get('c', '3') != '3': raise TestFailed, 'missing {} get, w/ 2nd arg' d = apache.table({'a' : '1', 'b' : '2'}) if d.get('c') is not None: raise TestFailed, 'missing dict get, no 2nd arg' if d.get('c', '3') != '3': raise TestFailed, 'missing dict get, w/ 2nd arg' if d.get('a') != '1': raise TestFailed, 'present dict get, no 2nd arg' if d.get('a', '3') != '1': raise TestFailed, 'present dict get, w/ 2nd arg' # dict.setdefault() log(" table.setdefault()") d = apache.table() d.setdefault('key0') if d.setdefault('key0') is not "": raise TestFailed, 'missing {} setdefault, no 2nd arg' if d.setdefault('key0') is not "": raise TestFailed, 'present {} setdefault, no 2nd arg' # dict.popitem() log(" table.popitem()") for copymode in -1, +1: # -1: b has same structure as a # +1: b is a.copy() for log2size in range(12): size = 2**log2size a = apache.table() b = apache.table() for i in range(size): a[`i`] = str(i) if copymode < 0: b[`i`] = str(i) if copymode > 0: b = a.copy() for i in range(size): ka, va = ta = a.popitem() if va != ka: raise TestFailed, "a.popitem: %s" % str(ta) kb, vb = tb = b.popitem() if vb != kb: raise TestFailed, "b.popitem: %s" % str(tb) if copymode < 0 and ta != tb: raise TestFailed, "a.popitem != b.popitem: %s, %s" % ( str(ta), str(tb)) if a: raise TestFailed, 'a not empty after popitems: %s' % str(a) if b: raise TestFailed, 'b not empty after popitems: %s' % str(b) # iteration (just make sure we can iterate without a segfault) d = apache.table({'a' : '1', 'b' : '2', 'c' : '3'}) log(" for k in table") for k in d: pass log(" _test_table test finished") mod_python-3.3.1/test/htdocs/index.py0000644000175000017500000000160110376731517015752 0ustar jimjim # # # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License. You # may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # # $Id: index.py 379638 2006-02-22 00:41:51Z jgallacher $ # # mod_python tests from mod_python import apache import unittest import re import time import os import cStringIO def index(req): return "test 1 ok, interpreter=%s" % req.interpreter def foobar(req): return "test 2 ok, interpreter=%s" % req.interpreter mod_python-3.3.1/test/htdocs/psptest_fail.psp0000644000175000017500000000004010462651642017502 0ustar jimjimfail <% session['dummy'] = 1 %> mod_python-3.3.1/test/Makefile.in0000644000175000017500000000157410404341634015050 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # $Id: Makefile.in 384881 2006-03-10 18:21:16Z jgallacher $ # PYTHON_BIN=@PYTHON_BIN@ check: $(PYTHON_BIN) test.py clean: rm -f *.pyc *.pyo cd conf && rm -f test.conf cd htdocs && rm -f *pyc *pyo rm -rf logs rm -rf tmp distclean: clean rm -f Makefile testconf.py mod_python-3.3.1/test/conf/0000755000175000017500000000000010557377762013745 5ustar jimjimmod_python-3.3.1/test/conf/mime.types0000644000175000017500000003013510151454154015741 0ustar jimjim# This is a comment. I love comments. # This file controls what Internet media types are sent to the client for # given file extension(s). Sending the correct media type to the client # is important so they know how to handle the content of the file. # Extra types can either be added here or by using an AddType directive # in your config files. For more information about Internet media types, # please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type # registry is at . # MIME type Extension application/EDI-Consent application/EDI-X12 application/EDIFACT application/activemessage application/andrew-inset ez application/applefile application/atomicmail application/batch-SMTP application/beep+xml application/cals-1840 application/commonground application/cybercash application/dca-rft application/dec-dx application/dvcs application/eshop application/http application/hyperstudio application/iges application/index application/index.cmd application/index.obj application/index.response application/index.vnd application/iotp application/ipp application/isup application/font-tdpfr application/mac-binhex40 hqx application/mac-compactpro cpt application/macwriteii application/marc application/mathematica application/mathematica-old application/msword doc application/news-message-id application/news-transmission application/ocsp-request application/ocsp-response application/octet-stream bin dms lha lzh exe class so dll application/oda oda application/parityfec application/pdf pdf application/pgp-encrypted application/pgp-keys application/pgp-signature application/pkcs10 application/pkcs7-mime application/pkcs7-signature application/pkix-cert application/pkix-crl application/pkixcmp application/postscript ai eps ps application/prs.alvestrand.titrax-sheet application/prs.cww application/prs.nprend application/qsig application/remote-printing application/riscos application/rtf application/sdp application/set-payment application/set-payment-initiation application/set-registration application/set-registration-initiation application/sgml application/sgml-open-catalog application/sieve application/slate application/smil smi smil application/timestamp-query application/timestamp-reply application/vemmi application/vnd.3M.Post-it-Notes application/vnd.FloGraphIt application/vnd.accpac.simply.aso application/vnd.accpac.simply.imp application/vnd.acucobol application/vnd.aether.imp application/vnd.anser-web-certificate-issue-initiation application/vnd.anser-web-funds-transfer-initiation application/vnd.audiograph application/vnd.businessobjects application/vnd.bmi application/vnd.canon-cpdl application/vnd.canon-lips application/vnd.claymore application/vnd.commerce-battelle application/vnd.commonspace application/vnd.comsocaller application/vnd.contact.cmsg application/vnd.cosmocaller application/vnd.cups-postscript application/vnd.cups-raster application/vnd.cups-raw application/vnd.ctc-posml application/vnd.cybank application/vnd.dna application/vnd.dpgraph application/vnd.dxr application/vnd.ecdis-update application/vnd.ecowin.chart application/vnd.ecowin.filerequest application/vnd.ecowin.fileupdate application/vnd.ecowin.series application/vnd.ecowin.seriesrequest application/vnd.ecowin.seriesupdate application/vnd.enliven application/vnd.epson.esf application/vnd.epson.msf application/vnd.epson.quickanime application/vnd.epson.salt application/vnd.epson.ssf application/vnd.ericsson.quickcall application/vnd.eudora.data application/vnd.fdf application/vnd.ffsns application/vnd.framemaker application/vnd.fsc.weblaunch application/vnd.fujitsu.oasys application/vnd.fujitsu.oasys2 application/vnd.fujitsu.oasys3 application/vnd.fujitsu.oasysgp application/vnd.fujitsu.oasysprs application/vnd.fujixerox.ddd application/vnd.fujixerox.docuworks application/vnd.fujixerox.docuworks.binder application/vnd.fut-misnet application/vnd.grafeq application/vnd.groove-account application/vnd.groove-identity-message application/vnd.groove-injector application/vnd.groove-tool-message application/vnd.groove-tool-template application/vnd.groove-vcard application/vnd.hhe.lesson-player application/vnd.hp-HPGL application/vnd.hp-PCL application/vnd.hp-PCLXL application/vnd.hp-hpid application/vnd.hp-hps application/vnd.httphone application/vnd.hzn-3d-crossword application/vnd.ibm.afplinedata application/vnd.ibm.MiniPay application/vnd.ibm.modcap application/vnd.informix-visionary application/vnd.intercon.formnet application/vnd.intertrust.digibox application/vnd.intertrust.nncp application/vnd.intu.qbo application/vnd.intu.qfx application/vnd.irepository.package+xml application/vnd.is-xpr application/vnd.japannet-directory-service application/vnd.japannet-jpnstore-wakeup application/vnd.japannet-payment-wakeup application/vnd.japannet-registration application/vnd.japannet-registration-wakeup application/vnd.japannet-setstore-wakeup application/vnd.japannet-verification application/vnd.japannet-verification-wakeup application/vnd.koan application/vnd.lotus-1-2-3 application/vnd.lotus-approach application/vnd.lotus-freelance application/vnd.lotus-notes application/vnd.lotus-organizer application/vnd.lotus-screencam application/vnd.lotus-wordpro application/vnd.mcd application/vnd.mediastation.cdkey application/vnd.meridian-slingshot application/vnd.mif mif application/vnd.minisoft-hp3000-save application/vnd.mitsubishi.misty-guard.trustweb application/vnd.mobius.daf application/vnd.mobius.dis application/vnd.mobius.msl application/vnd.mobius.plc application/vnd.mobius.txf application/vnd.motorola.flexsuite application/vnd.motorola.flexsuite.adsi application/vnd.motorola.flexsuite.fis application/vnd.motorola.flexsuite.gotap application/vnd.motorola.flexsuite.kmr application/vnd.motorola.flexsuite.ttc application/vnd.motorola.flexsuite.wem application/vnd.mozilla.xul+xml application/vnd.ms-artgalry application/vnd.ms-asf application/vnd.ms-excel xls application/vnd.ms-lrm application/vnd.ms-powerpoint ppt application/vnd.ms-project application/vnd.ms-tnef application/vnd.ms-works application/vnd.mseq application/vnd.msign application/vnd.music-niff application/vnd.musician application/vnd.netfpx application/vnd.noblenet-directory application/vnd.noblenet-sealer application/vnd.noblenet-web application/vnd.novadigm.EDM application/vnd.novadigm.EDX application/vnd.novadigm.EXT application/vnd.osa.netdeploy application/vnd.palm application/vnd.pg.format application/vnd.pg.osasli application/vnd.powerbuilder6 application/vnd.powerbuilder6-s application/vnd.powerbuilder7 application/vnd.powerbuilder7-s application/vnd.powerbuilder75 application/vnd.powerbuilder75-s application/vnd.previewsystems.box application/vnd.publishare-delta-tree application/vnd.pvi.ptid1 application/vnd.pwg-xhtml-print+xml application/vnd.rapid application/vnd.s3sms application/vnd.seemail application/vnd.shana.informed.formdata application/vnd.shana.informed.formtemplate application/vnd.shana.informed.interchange application/vnd.shana.informed.package application/vnd.sss-cod application/vnd.sss-dtf application/vnd.sss-ntf application/vnd.street-stream application/vnd.svd application/vnd.swiftview-ics application/vnd.triscape.mxs application/vnd.trueapp application/vnd.truedoc application/vnd.tve-trigger application/vnd.ufdl application/vnd.uplanet.alert application/vnd.uplanet.alert-wbxml application/vnd.uplanet.bearer-choice-wbxml application/vnd.uplanet.bearer-choice application/vnd.uplanet.cacheop application/vnd.uplanet.cacheop-wbxml application/vnd.uplanet.channel application/vnd.uplanet.channel-wbxml application/vnd.uplanet.list application/vnd.uplanet.list-wbxml application/vnd.uplanet.listcmd application/vnd.uplanet.listcmd-wbxml application/vnd.uplanet.signal application/vnd.vcx application/vnd.vectorworks application/vnd.vidsoft.vidconference application/vnd.visio application/vnd.vividence.scriptfile application/vnd.wap.sic application/vnd.wap.slc application/vnd.wap.wbxml wbxml application/vnd.wap.wmlc wmlc application/vnd.wap.wmlscriptc wmlsc application/vnd.webturbo application/vnd.wrq-hp3000-labelled application/vnd.wt.stf application/vnd.xara application/vnd.xfdl application/vnd.yellowriver-custom-menu application/whoispp-query application/whoispp-response application/wita application/wordperfect5.1 application/x-bcpio bcpio application/x-cdlink vcd application/x-chess-pgn pgn application/x-compress application/x-cpio cpio application/x-csh csh application/x-director dcr dir dxr application/x-dvi dvi application/x-futuresplash spl application/x-gtar gtar application/x-gzip application/x-hdf hdf application/x-javascript js application/x-koan skp skd skt skm application/x-latex latex application/x-netcdf nc cdf application/x-sh sh application/x-shar shar application/x-shockwave-flash swf application/x-stuffit sit application/x-sv4cpio sv4cpio application/x-sv4crc sv4crc application/x-tar tar application/x-tcl tcl application/x-tex tex application/x-texinfo texinfo texi application/x-troff t tr roff application/x-troff-man man application/x-troff-me me application/x-troff-ms ms application/x-ustar ustar application/x-wais-source src application/x400-bp application/xhtml+xml xhtml xht application/xml application/xml-dtd application/xml-external-parsed-entity application/zip zip audio/32kadpcm audio/basic au snd audio/g.722.1 audio/l16 audio/midi mid midi kar audio/mp4a-latm audio/mpa-robust audio/mpeg mpga mp2 mp3 audio/parityfec audio/prs.sid audio/telephone-event audio/tone audio/vnd.cisco.nse audio/vnd.cns.anp1 audio/vnd.cns.inf1 audio/vnd.digital-winds audio/vnd.everad.plj audio/vnd.lucent.voice audio/vnd.nortel.vbk audio/vnd.nuera.ecelp4800 audio/vnd.nuera.ecelp7470 audio/vnd.nuera.ecelp9600 audio/vnd.octel.sbc audio/vnd.qcelp audio/vnd.rhetorex.32kadpcm audio/vnd.vmx.cvsd audio/x-aiff aif aiff aifc audio/x-mpegurl m3u audio/x-pn-realaudio ram rm audio/x-pn-realaudio-plugin rpm audio/x-realaudio ra audio/x-wav wav chemical/x-pdb pdb chemical/x-xyz xyz image/bmp bmp image/cgm image/g3fax image/gif gif image/ief ief image/jpeg jpeg jpg jpe image/naplps image/png png image/prs.btif image/prs.pti image/tiff tiff tif image/vnd.cns.inf2 image/vnd.djvu djvu djv image/vnd.dwg image/vnd.dxf image/vnd.fastbidsheet image/vnd.fpx image/vnd.fst image/vnd.fujixerox.edmics-mmr image/vnd.fujixerox.edmics-rlc image/vnd.mix image/vnd.net-fpx image/vnd.svf image/vnd.wap.wbmp wbmp image/vnd.xiff image/x-cmu-raster ras image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm image/x-portable-pixmap ppm image/x-rgb rgb image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd message/delivery-status message/disposition-notification message/external-body message/http message/news message/partial message/rfc822 message/s-http model/iges igs iges model/mesh msh mesh silo model/vnd.dwf model/vnd.flatland.3dml model/vnd.gdl model/vnd.gs-gdl model/vnd.gtw model/vnd.mts model/vnd.vtu model/vrml wrl vrml multipart/alternative multipart/appledouble multipart/byteranges multipart/digest multipart/encrypted multipart/form-data multipart/header-set multipart/mixed multipart/parallel multipart/related multipart/report multipart/signed multipart/voice-message text/calendar text/css css text/directory text/enriched text/html html htm text/parityfec text/plain asc txt text/prs.lines.tag text/rfc822-headers text/richtext rtx text/rtf rtf text/sgml sgml sgm text/tab-separated-values tsv text/t140 text/uri-list text/vnd.DMClientScript text/vnd.IPTC.NITF text/vnd.IPTC.NewsML text/vnd.abc text/vnd.curl text/vnd.flatland.3dml text/vnd.fly text/vnd.fmi.flexstor text/vnd.in3d.3dml text/vnd.in3d.spot text/vnd.latex-z text/vnd.motorola.reflex text/vnd.ms-mediapackage text/vnd.wap.si text/vnd.wap.sl text/vnd.wap.wml wml text/vnd.wap.wmlscript wmls text/x-setext etx text/xml xml xsl text/xml-external-parsed-entity video/mp4v-es video/mpeg mpeg mpg mpe video/parityfec video/pointer video/quicktime qt mov video/vnd.fvt video/vnd.motorola.video video/vnd.motorola.videop video/vnd.mpegurl mxu video/vnd.mts video/vnd.nokia.interleaved-multimedia video/vnd.vivo video/x-msvideo avi video/x-sgi-movie movie x-conference/x-cooltalk ice mod_python-3.3.1/test/test.py0000644000175000017500000032160310524724230014332 0ustar jimjim # # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you # may not use this file except in compliance with the License. You # may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. See the License for the specific language governing # permissions and limitations under the License. # # $Id: test.py 473093 2006-11-09 22:15:52Z jgallacher $ # """ Writing Tests Writing mod_python tests can be a tricky task. This module attempts to lay out a framework for making the testing process consistent and quick to implement. All tests are based on Python Unit Test framework, it's a good idea to study the docs for the unittest module before going any further. To write a test, first decide in which of the 3 following categories it falls: o Simple tests that do not require any special server configuration and can be conducted along with other similar tests all in one request. o Per-Request tests. These tests require a whole separate request (or several requests) for a complete test. o Per-Instance tests. These require restarting the instance of http and running it in a particular way, perhaps with a special config to complete the test. An example might be load testing, or checking for memory leaks. There are two modules involved in testing - the one you're looking at now (test.py), which is responsible for setting up the http config running it and initiating requests, AND htdocs/tests.py (sorry for boring names), which is where all mod_python handlers reside. To write a Simple test: o Look at tests.SimpleTestCase class and the test methods in it, then write your own following the example. o Look at the tests.make_suite function, and make sure your test is added to the suite in there. o Keep in mind that the only way for Simple tests to communicate with the outside world is via the error log, do not be shy about writing to it. To write a Per-Request test: Most, if not all per-request tests require special server configuration as part of the fixture. To avoid having to restart the server with a different config (which would, btw, effectively turn this into a per- instance test), we separate configs by placing them in separate virtual hosts. This will become clearer if you follow the code. o Look at test.PerRequestCase class. o Note that for every test there are two methods defined: the test method itself, plus a method with the same name ending with "_conf". The _conf methods are supposed to return the virtual host config necessary for this test. As tests are instantiated, the configs are appended to a class variable (meaning its shared across all instances) appendConfig, then before the suite is run, the httpd config is built and httpd started. Each test will know to query its own virtual host. This way all tests can be conducted using a single instance of httpd. o Note how the _config methods generate the config - they use the httpdconf module to generate an object whose string representation is the config part, simlar to the way HTMLgen produces html. You do not have to do it this way, but it makes for cleaner code. o Every Per-Request test must also have a corresponding handler in the tests module. The convention is name everything based on the subject of the test, e.g. the test of req.document_root() will have a test method in PerRequestCase class called test_req_documet_root, a config method PerRequestCase.test_req_document_root_conf, the VirtualHost name will be test_req_document_root, and the handler in tests.py will be called req_document_root. o Note that you cannot use urllib if you have to specify a custom host: header, which is required for this whole thing to work. There is a convenience method, vhost_get, which takes the host name as the first argument, and optionally path as the second (though that is almost never needed). If vhost_get does not suffice, use httplib. Note the very useful skip_host=1 argument. o Remember to have your test added to the suite in PerInstanceTestCase.testPerRequestTests To write a Per-Instance test: o Look at test.PerInstanceTestCase class. o You have to start httpd in your test, but no need to stop it, it will be stopped for you in tearDown() o Add the test to the suite in test.suite() method """ import sys import os ### Testing the testconf module try: import testconf except: print ( "Cannot find the testconf module. Either you didn't " "launch the configure script, or you're running this script " "in a Win32 environment. You have to copy testconf.py.in to " "testconf.py and change the variables HTTPD, TESTHOME, MOD_PYTHON_SO " "and LIBEXECDIR according to their description in the file.\n" ) sys.exit() else: def testpath(variable,isfile): value = getattr(testconf,variable,'') if isfile: if os.path.isfile(value): return True else: if os.path.isdir(value): return True print 'Bad value for testconf.%s : %s'%( variable, value ) return False good = testpath('HTTPD',True) good = testpath('TESTHOME',False) and good good = testpath('LIBEXECDIR',False) and good good = testpath('MOD_PYTHON_SO',True) and good if not good: print "Please check your testconf.py file" sys.exit() del testpath del good from httpdconf import * import unittest import commands import urllib import httplib import shutil import time import socket import tempfile import base64 import random import md5 from cStringIO import StringIO HTTPD = testconf.HTTPD TESTHOME = testconf.TESTHOME MOD_PYTHON_SO = testconf.MOD_PYTHON_SO LIBEXECDIR = testconf.LIBEXECDIR SERVER_ROOT = TESTHOME CONFIG = os.path.join(TESTHOME, "conf", "test.conf") DOCUMENT_ROOT = os.path.join(TESTHOME, "htdocs") TMP_DIR = os.path.join(TESTHOME, "tmp") PORT = 0 # this is set in fundUnusedPort() # readBlockSize is required for the test_fileupload_* tests. # We can't import mod_python.util.readBlockSize from a cmd line # interpreter, so we'll hard code it here. # If util.readBlockSize changes, it MUST be changed here as well. # Maybe we should set up a separate test to query the server to # get the correct readBlockSize? # readBlockSize = 65368 def findUnusedPort(): # bind to port 0 which makes the OS find the next # unused port. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(("127.0.0.1", 0)) port = s.getsockname()[1] s.close() return port def get_ab_path(): """ Find the location of the ab (apache benchmark) program """ for name in ['ab', 'ab2', 'ab.exe', 'ab2.exe']: path = os.path.join(os.path.split(HTTPD)[0], name) if os.path.exists(path): return quoteIfSpace(path) return None def quoteIfSpace(s): # Windows doesn't like quotes when there are # no spaces, but needs them otherwise if s.find(" ") != -1: s = '"%s"' % s return s def get_apache_version(): print "Checking Apache version...." httpd = quoteIfSpace(HTTPD) cmd = '%s -v' % (httpd) (stdin,stdout) = os.popen2(cmd) version_str = None for line in stdout: if line.startswith('Server version'): version_str = line.strip() break if version_str: version_str = version_str.split('/')[1] major,minor,patch = version_str.split('.',3) version = '%s.%s' % (major,minor) else: print "Can't determine Apache version. Assuming 2.0" version = '2.0' print version return version APACHE_VERSION = get_apache_version() class HttpdCtrl: # a mixin providing ways to control httpd def checkFiles(self): modules = os.path.join(SERVER_ROOT, "modules") if not os.path.exists(modules): os.mkdir(modules) logs = os.path.join(SERVER_ROOT, "logs") if os.path.exists(logs): shutil.rmtree(logs) os.mkdir(logs) # place if os.path.exists(TMP_DIR): shutil.rmtree(TMP_DIR) os.mkdir(TMP_DIR) def makeConfig(self, append=""): # create config files, etc print " Creating config...." self.checkFiles() global PORT PORT = findUnusedPort() print " listen port:", PORT # where other modules might be modpath = LIBEXECDIR s = Container( IfModule("prefork.c", StartServers("3"), MaxSpareServers("1")), IfModule("worker.c", StartServers("2"), MaxClients("6"), MinSpareThreads("1"), MaxSpareThreads("1"), ThreadsPerChild("3"), MaxRequestsPerChild("0")), IfModule("perchild.c", NumServers("2"), StartThreads("2"), MaxSpareThreads("1"), MaxThreadsPerChild("2")), IfModule("mpm_winnt.c", ThreadsPerChild("5"), MaxRequestsPerChild("0")), IfModule("!mod_mime.c", LoadModule("mime_module %s" % quoteIfSpace(os.path.join(modpath, "mod_mime.so")))), IfModule("!mod_log_config.c", LoadModule("log_config_module %s" % quoteIfSpace(os.path.join(modpath, "mod_log_config.so")))), IfModule("!mod_dir.c", LoadModule("dir_module %s" % quoteIfSpace(os.path.join(modpath, "mod_dir.so")))), IfModule("!mod_include.c", LoadModule("include_module %s" % quoteIfSpace(os.path.join(modpath, "mod_include.so")))), ServerRoot(SERVER_ROOT), ErrorLog("logs/error_log"), LogLevel("debug"), LogFormat(r'"%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined'), CustomLog("logs/access_log combined"), LockFile("logs/accept.lock"), TypesConfig("conf/mime.types"), PidFile("logs/httpd.pid"), ServerName("127.0.0.1"), Listen(PORT), PythonOption('mod_python.mutex_directory %s' % TMP_DIR), PythonOption('PythonOptionTest sample_value'), # PythonOption('mod_python.legacy.importer *'), DocumentRoot(DOCUMENT_ROOT), LoadModule("python_module %s" % quoteIfSpace(MOD_PYTHON_SO))) if APACHE_VERSION == '2.2': # mod_auth has been split into mod_auth_basic and some other modules s.append(IfModule("!mod_auth_basic.c", LoadModule("auth_basic_module %s" % quoteIfSpace(os.path.join(modpath, "mod_auth_basic.so"))))) # Default KeepAliveTimeout is 5 for apache 2.2, but 15 in apache 2.0 # Explicitly set the value so it's the same as 2.0 s.append(KeepAliveTimeout("15")) else: s.append(IfModule("!mod_auth.c", LoadModule("auth_module %s" % quoteIfSpace(os.path.join(modpath, "mod_auth.so"))))) s.append("\n# --APPENDED-- \n\n"+append) f = open(CONFIG, "w") f.write(str(s)) f.close() def startHttpd(self,extra=''): print " Starting Apache...." httpd = quoteIfSpace(HTTPD) config = quoteIfSpace(CONFIG) cmd = '%s %s -k start -f %s' % (httpd, extra, config) print " ", cmd os.system(cmd) time.sleep(1) self.httpd_running = 1 def stopHttpd(self): print " Stopping Apache..." httpd = quoteIfSpace(HTTPD) config = quoteIfSpace(CONFIG) cmd = '%s -k stop -f %s' % (httpd, config) print " ", cmd os.system(cmd) time.sleep(1) # Wait for apache to stop by checking for the existence of pid the # file. If pid file still exists after 20 seconds raise an error. # This check is here to facilitate testing on the qemu emulator. # Qemu will run about 1/10 the native speed, so 1 second may # not be long enough for apache to shut down. count = 0 pid_file = os.path.join(os.getcwd(), 'logs/httpd.pid') while os.path.exists(pid_file): time.sleep(1) count += 1 if count > 20: # give up - apache refuses to die - or died a horrible # death and never removed the pid_file. raise RuntimeError, " Trouble stopping apache" self.httpd_running = 0 class PerRequestTestCase(unittest.TestCase): appendConfig = "\nNameVirtualHost *\n\n" def __init__(self, methodName="runTest"): unittest.TestCase.__init__(self, methodName) # add to config try: confMeth = getattr(self, methodName+"_conf") self.__class__.appendConfig += confMeth() + "\n" except AttributeError: pass def vhost_get(self, vhost, path="/tests.py"): # allows to specify a custom host: header conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", path, skip_host=1) conn.putheader("Host", "%s:%s" % (vhost, PORT)) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() return rsp def vhost_post_multipart_form_data(self, vhost, path="/tests.py",variables={}, files={}): # variables is a { name : value } dict # files is a { name : (filename, content) } dict # build the POST entity entity = StringIO() # This is the MIME boundary boundary = "============="+''.join( [ random.choice('0123456789') for x in range(10) ] )+'==' # A part for each variable for name, value in variables.iteritems(): entity.write('--') entity.write(boundary) entity.write('\r\n') entity.write('Content-Type: text/plain\r\n') entity.write('Content-Disposition: form-data;\r\n name="%s"\r\n'%name) entity.write('\r\n') entity.write(str(value)) entity.write('\r\n') # A part for each file for name, filespec in files.iteritems(): filename, content = filespec # if content is readable, read it try: content = content.read() except: pass entity.write('--') entity.write(boundary) entity.write('\r\n') entity.write('Content-Type: application/octet-stream\r\n') entity.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n'%(name,filename)) entity.write('\r\n') entity.write(content) entity.write('\r\n') # The final boundary entity.write('--') entity.write(boundary) entity.write('--\r\n') entity = entity.getvalue() conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) # conn.set_debuglevel(1000) conn.putrequest("POST", path, skip_host=1) conn.putheader("Host", "%s:%s" % (vhost, PORT)) conn.putheader("Content-Type", 'multipart/form-data; boundary="%s"'%boundary) conn.putheader("Content-Length", '%s'%(len(entity))) conn.endheaders() start = time.time() conn.send(entity) response = conn.getresponse() rsp = response.read() conn.close() print ' --> Send + process + receive took %.3f s'%(time.time()-start) return rsp ### Tests begin here def test_req_document_root_conf(self): c = VirtualHost("*", ServerName("test_req_document_root"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_document_root"), PythonDebug("On"))) return str(c) def test_req_document_root(self): print "\n * Testing req.document_root()" rsp = self.vhost_get("test_req_document_root") if rsp.upper() != DOCUMENT_ROOT.replace("\\", "/").upper(): self.fail(`rsp`) def test_req_add_handler_conf(self): c = VirtualHost("*", ServerName("test_req_add_handler"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_add_handler"), PythonDebug("On"))) return str(c) def test_req_add_handler(self): print "\n * Testing req.add_handler()" rsp = self.vhost_get("test_req_add_handler") if (rsp != 2*"test ok"): self.fail(`rsp`) def test_req_add_bad_handler_conf(self): c = VirtualHost("*", ServerName("test_req_add_bad_handler"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_add_bad_handler"), PythonDebug("On"))) return str(c) def test_req_add_bad_handler(self): # adding a non-existent handler with req.add_handler should raise # an exception. print """\n * Testing req.add_handler("PythonHandler", "bad_handler")""" rsp = self.vhost_get("test_req_add_bad_handler") # look for evidence of the exception in the error log time.sleep(1) f = open(os.path.join(SERVER_ROOT, "logs/error_log")) log = f.read() f.close() if log.find("contains no 'bad_handler'") == -1: self.fail("""Could not find "contains no 'bad_handler'" in error_log""") def test_req_add_empty_handler_string_conf(self): c = VirtualHost("*", ServerName("test_req_add_empty_handler_string"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_add_empty_handler_string"), PythonDebug("On"))) return str(c) def test_req_add_empty_handler_string(self): # Adding an empty string as the handler in req.add_handler # should raise an exception print """\n * Testing req.add_handler("PythonHandler","")""" rsp = self.vhost_get("test_req_add_empty_handler_string") if (rsp == "no exception"): self.fail("Expected an exception") def test_req_add_handler_empty_phase_conf(self): c = VirtualHost("*", ServerName("test_req_add_handler_empty_phase"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonInterpPerDirective("On"), PythonFixupHandler("tests::req_add_handler_empty_phase"), PythonDebug("On"))) return str(c) def test_req_add_handler_empty_phase(self): # Adding handler to content phase when no handler already # exists for that phase. print """\n * Testing req.add_handler() for empty phase""" rsp = self.vhost_get("test_req_add_handler_empty_phase") if (rsp != "test ok"): self.fail(`rsp`) def test_req_add_handler_directory_conf(self): c = VirtualHost("*", ServerName("test_req_add_handler_directory"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonInterpPerDirective("On"), PythonFixupHandler("tests::test_req_add_handler_directory"), PythonDebug("On"))) return str(c) def test_req_add_handler_directory(self): # Checking that directory is canonicalized and trailing # slash is added. print """\n * Testing req.add_handler() directory""" rsp = self.vhost_get("test_req_add_handler_directory") if (rsp != "test ok"): self.fail(`rsp`) def test_accesshandler_add_handler_to_empty_hl_conf(self): # Note that there is no PythonHandler specified in the the VirtualHost # config. We want to see if req.add_handler will work when the # handler list is empty. #PythonHandler("tests::req_add_empty_handler_string"), c = VirtualHost("*", ServerName("test_accesshandler_add_handler_to_empty_hl"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonAccessHandler("tests::accesshandler_add_handler_to_empty_hl"), PythonDebug("On"))) return str(c) def test_accesshandler_add_handler_to_empty_hl(self): print """\n * Testing req.add_handler() when handler list is empty""" rsp = self.vhost_get("test_accesshandler_add_handler_to_empty_hl") if (rsp != "test ok"): self.fail(`rsp`) def test_req_allow_methods_conf(self): c = VirtualHost("*", ServerName("test_req_allow_methods"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_allow_methods"), PythonDebug("On"))) return str(c) def test_req_allow_methods(self): print "\n * Testing req.allow_methods()" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_req_allow_methods", PORT)) conn.endheaders() response = conn.getresponse() server_hdr = response.getheader("Allow", "") conn.close() self.failUnless(server_hdr.find("PYTHONIZE") > -1, "req.allow_methods() didn't work") def test_req_get_basic_auth_pw_conf(self): c = VirtualHost("*", ServerName("test_req_get_basic_auth_pw"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), AuthName("blah"), AuthType("basic"), PythonHandler("tests::req_get_basic_auth_pw"), PythonDebug("On"))) return str(c) def test_req_get_basic_auth_pw(self): print "\n * Testing req.get_basic_auth_pw()" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_req_get_basic_auth_pw", PORT)) auth = base64.encodestring("spam:eggs").strip() conn.putheader("Authorization", "Basic %s" % auth) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok"): self.fail(`rsp`) def test_req_auth_type_conf(self): c = VirtualHost("*", ServerName("test_req_auth_type"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), AuthName("blah"), AuthType("dummy"), Require("valid-user"), PythonAuthenHandler("tests::req_auth_type"), PythonAuthzHandler("tests::req_auth_type"), PythonHandler("tests::req_auth_type"), PythonDebug("On"))) return str(c) def test_req_auth_type(self): print "\n * Testing req.auth_type()" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_req_auth_type", PORT)) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok"): self.fail(`rsp`) def test_req_requires_conf(self): c = VirtualHost("*", ServerName("test_req_requires"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), AuthName("blah"), AuthType("dummy"), Require("valid-user"), PythonAuthenHandler("tests::req_requires"), PythonDebug("On"))) return str(c) def test_req_requires(self): print "\n * Testing req.requires()" rsp = self.vhost_get("test_req_requires") conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_req_requires", PORT)) auth = base64.encodestring("spam:eggs").strip() conn.putheader("Authorization", "Basic %s" % auth) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok"): self.fail(`rsp`) def test_req_internal_redirect_conf(self): c = VirtualHost("*", ServerName("test_req_internal_redirect"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_internal_redirect | .py"), PythonHandler("tests::req_internal_redirect_int | .int"), PythonDebug("On"))) return str(c) def test_req_internal_redirect(self): print "\n * Testing req.internal_redirect()" rsp = self.vhost_get("test_req_internal_redirect") if rsp != "test ok": self.fail("internal_redirect") def test_req_construct_url_conf(self): c = VirtualHost("*", ServerName("test_req_construct_url"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_construct_url"), PythonDebug("On"))) return str(c) def test_req_construct_url(self): print "\n * Testing req.construct_url()" rsp = self.vhost_get("test_req_construct_url") if rsp != "test ok": self.fail("construct_url") def test_req_read_conf(self): c = str(Timeout("5")) + \ str(VirtualHost("*", ServerName("test_req_read"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_read"), PythonDebug("On")))) return c def test_req_read(self): print "\n * Testing req.read()" params = '1234567890'*10000 print " writing %d bytes..." % len(params) conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("POST", "/tests.py", skip_host=1) conn.putheader("Host", "test_req_read:%s" % PORT) conn.putheader("Content-Length", len(params)) conn.endheaders() conn.send(params) response = conn.getresponse() rsp = response.read() conn.close() print " response size: %d\n" % len(rsp) if (rsp != params): self.fail(`rsp`) print " read/write ok, now lets try causing a timeout (should be 5 secs)" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("POST", "/tests.py", skip_host=1) conn.putheader("Host", "test_req_read:%s" % PORT) conn.putheader("Content-Length", 10) conn.endheaders() conn.send("123456789") response = conn.getresponse() rsp = response.read() conn.close() if rsp.find("IOError") < 0: self.fail("timeout test failed") def test_req_readline_conf(self): c = VirtualHost("*", ServerName("test_req_readline"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_readline"), PythonDebug("On"))) return str(c) def test_req_readline(self): print "\n * Testing req.readline()" params = ('1234567890'*3000+'\n')*4 print " writing %d bytes..." % len(params) conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("POST", "/tests.py", skip_host=1) conn.putheader("Host", "test_req_readline:%s" % PORT) conn.putheader("Content-Length", len(params)) conn.endheaders() conn.send(params) response = conn.getresponse() rsp = response.read() conn.close() print " response size: %d\n" % len(rsp) if (rsp != params): self.fail(`rsp`) def test_req_readlines_conf(self): c = VirtualHost("*", ServerName("test_req_readlines"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_readlines"), PythonDebug("On"))) return str(c) def test_req_readlines(self): print "\n * Testing req.readlines()" params = ('1234567890'*3000+'\n')*4 print " writing %d bytes..." % len(params) conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("POST", "/tests.py", skip_host=1) conn.putheader("Host", "test_req_readlines:%s" % PORT) conn.putheader("Content-Length", len(params)) conn.endheaders() conn.send(params) response = conn.getresponse() rsp = response.read() conn.close() print " response size: %d\n" % len(rsp) if (rsp != params): self.fail(`rsp`) print "\n * Testing req.readlines(size_hint=30000)" params = ('1234567890'*3000+'\n')*4 print " writing %d bytes..." % len(params) conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("POST", "/tests.py", skip_host=1) conn.putheader("Host", "test_req_readlines:%s" % PORT) conn.putheader("Content-Length", len(params)) conn.putheader("SizeHint", 30000) conn.endheaders() conn.send(params) response = conn.getresponse() rsp = response.read() conn.close() print " response size: %d\n" % len(rsp) if (rsp != ('1234567890'*3000+'\n')): self.fail(`rsp`) print "\n * Testing req.readlines(size_hint=32000)" params = ('1234567890'*3000+'\n')*4 print " writing %d bytes..." % len(params) conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("POST", "/tests.py", skip_host=1) conn.putheader("Host", "test_req_readlines:%s" % PORT) conn.putheader("Content-Length", len(params)) conn.putheader("SizeHint", 32000) conn.endheaders() conn.send(params) response = conn.getresponse() rsp = response.read() conn.close() print " response size: %d\n" % len(rsp) if (rsp != (('1234567890'*3000+'\n')*2)): self.fail(`rsp`) def test_req_discard_request_body_conf(self): c = str(Timeout("5")) + \ str(VirtualHost("*", ServerName("test_req_discard_request_body"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_discard_request_body"), PythonDebug("On")))) return c def test_req_discard_request_body(self): print "\n * Testing req.discard_request_body()" params = '1234567890'*2 print " writing %d bytes..." % len(params) conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "test_req_discard_request_body:%s" % PORT) conn.putheader("Content-Length", len(params)) conn.endheaders() conn.send(params) response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok"): self.fail(`rsp`) def test_req_register_cleanup_conf(self): c = VirtualHost("*", ServerName("test_req_register_cleanup"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_register_cleanup"), PythonDebug("On"))) return str(c) def test_req_register_cleanup(self): print "\n * Testing req.register_cleanup()" rsp = self.vhost_get("test_req_register_cleanup") # see what's in the log now time.sleep(1) f = open(os.path.join(SERVER_ROOT, "logs/error_log")) log = f.read() f.close() if log.find("req_register_cleanup test ok") == -1: self.fail("Could not find test message in error_log") def test_req_headers_out_conf(self): c = VirtualHost("*", ServerName("test_req_headers_out"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_headers_out"), PythonDebug("On"))) return str(c) def test_req_headers_out(self): print "\n * Testing req.headers_out" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/test.py", skip_host=1) conn.putheader("Host", "test_req_headers_out:%s" % PORT) conn.endheaders() response = conn.getresponse() h = response.getheader("x-test-header", None) response.read() conn.close() if h is None: self.fail("Could not find x-test-header") if h != "test ok": self.fail("x-test-header is there, but does not contain 'test ok'") def test_req_sendfile_conf(self): c = VirtualHost("*", ServerName("test_req_sendfile"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_sendfile"), PythonDebug("On"))) return str(c) def test_req_sendfile(self): print "\n * Testing req.sendfile() with offset and length" rsp = self.vhost_get("test_req_sendfile") if (rsp != "test ok"): self.fail(`rsp`) def test_req_sendfile2_conf(self): c = VirtualHost("*", ServerName("test_req_sendfile2"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_sendfile2"), PythonDebug("On"))) return str(c) def test_req_sendfile2(self): print "\n * Testing req.sendfile() without offset and length" rsp = self.vhost_get("test_req_sendfile2") if (rsp != "0123456789"*100): self.fail(`rsp`) def test_req_sendfile3_conf(self): c = VirtualHost("*", ServerName("test_req_sendfile3"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_sendfile3"), PythonDebug("On"))) return str(c) def test_req_sendfile3(self): if os.name == 'posix': print "\n * Testing req.sendfile() for a file which is a symbolic link" rsp = self.vhost_get("test_req_sendfile3") if (rsp != "0123456789"*100): self.fail(`rsp`) else: print "\n * Skipping req.sendfile() for a file which is a symbolic link" def test_req_handler_conf(self): c = VirtualHost("*", ServerName("test_req_handler"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, PythonFixupHandler("tests::req_handler"), PythonDebug("On"))) return str(c) def test_req_handler(self): print "\n * Testing req.handler" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_req_handler", PORT)) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok"): self.fail(`rsp`) def test_req_no_cache_conf(self): c = VirtualHost("*", ServerName("test_req_no_cache"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_no_cache"), PythonDebug("On"))) return str(c) def test_req_no_cache(self): print "\n * Testing req.no_cache" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_req_no_cache", PORT)) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if response.getheader("expires", None) is None: self.fail(`response.getheader("expires", None)`) if (rsp != "test ok"): self.fail(`rsp`) def test_req_update_mtime_conf(self): c = VirtualHost("*", ServerName("test_req_update_mtime"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_update_mtime"), PythonDebug("On"))) return str(c) def test_req_update_mtime(self): print "\n * Testing req.update_mtime" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_req_update_mtime", PORT)) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if response.getheader("etag", None) is None: self.fail(`response.getheader("etag", None)`) if response.getheader("last-modified", None) is None: self.fail(`response.getheader("last-modified", None)`) if (rsp != "test ok"): self.fail(`rsp`) def test_util_redirect_conf(self): c = VirtualHost("*", ServerName("test_util_redirect"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, PythonFixupHandler("tests::util_redirect"), PythonHandler("tests::util_redirect"), PythonDebug("On"))) return str(c) def test_util_redirect(self): print "\n * Testing util.redirect()" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_util_redirect", PORT)) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if response.status != 302: self.fail('did not receive 302 status response') if response.getheader("location", None) != "/dummy": self.fail('did not receive correct location for redirection') if rsp != "test ok": self.fail(`rsp`) def test_req_server_get_config_conf(self): c = VirtualHost("*", ServerName("test_req_server_get_config"), DocumentRoot(DOCUMENT_ROOT), PythonDebug("On"), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_server_get_config"), PythonDebug("Off"))) return str(c) def test_req_server_get_config(self): print "\n * Testing req.server.get_config()" rsp = self.vhost_get("test_req_server_get_config") if (rsp != "test ok"): self.fail(`rsp`) def test_req_server_get_options_conf(self): c = VirtualHost("*", ServerName("test_req_server_get_options"), DocumentRoot(DOCUMENT_ROOT), PythonDebug("Off"), PythonOption("global 1"), PythonOption("override 1"), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::req_server_get_options"), PythonOption("local 1"), PythonOption("override 2"), PythonDebug("On"))) return str(c) def test_req_server_get_options(self): print "\n * Testing req.server.get_options()" rsp = self.vhost_get("test_req_server_get_options") if (rsp != "test ok"): self.fail(`rsp`) def test_fileupload_conf(self): c = VirtualHost("*", ServerName("test_fileupload"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::fileupload"), PythonDebug("On"))) return str(c) def test_fileupload(self): print "\n * Testing 1 MB file upload support" content = ''.join( [ chr(random.randrange(256)) for x in xrange(1024*1024) ] ) digest = md5.new(content).hexdigest() rsp = self.vhost_post_multipart_form_data( "test_fileupload", variables={'test':'abcd'}, files={'testfile':('test.txt',content)}, ) if (rsp != digest): self.fail('1 MB file upload failed, its contents were corrupted (%s)'%rsp) def test_fileupload_embedded_cr_conf(self): c = VirtualHost("*", ServerName("test_fileupload"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::fileupload"), PythonDebug("On"))) return str(c) def test_fileupload_embedded_cr(self): # Strange things can happen if there is a '\r' character at position # readBlockSize of a line being read by FieldStorage.read_to_boundary # where the line length is > readBlockSize. # This test will expose this problem. print "\n * Testing file upload with \\r char in a line at position == readBlockSize" content = ( 'a'*100 + '\r\n' + 'b'*(readBlockSize-1) + '\r' # trick ! + 'ccc' + 'd'*100 + '\r\n' ) digest = md5.new(content).hexdigest() rsp = self.vhost_post_multipart_form_data( "test_fileupload", variables={'test':'abcd'}, files={'testfile':('test.txt',content)}, ) if (rsp != digest): self.fail('file upload embedded \\r test failed, its contents were corrupted (%s)'%rsp) # The UNIX-HATERS handbook illustrates this problem. Once we've done some additional # investigation to make sure that our synthetic file used above is correct, # we can likely remove this conditional test. Also, there is no way to be sure # that ugh.pdf will always be the same in the future so the test may not be valid # over the long term. try: ugh = file('ugh.pdf','rb') content = ugh.read() ugh.close() except: print " * Skipping the test for The UNIX-HATERS handbook file upload." print " To make this test, you need to download ugh.pdf from" print " http://research.microsoft.com/~daniel/uhh-download.html" print " into this script's directory." else: print " * Testing The UNIX-HATERS handbook file upload support" digest = md5.new(content).hexdigest() rsp = self.vhost_post_multipart_form_data( "test_fileupload", variables={'test':'abcd'}, files={'testfile':('ugh.pdf',content)}, ) if (rsp != digest): self.fail('The UNIX-HATERS handbook file upload failed, its contents was corrupted (%s)'%rsp) def test_fileupload_split_boundary_conf(self): c = VirtualHost("*", ServerName("test_fileupload"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::fileupload"), PythonDebug("On"))) return str(c) def test_fileupload_split_boundary(self): # This test is similar to test_fileupload_embedded_cr, but it is possible to # write an implementation of FieldStorage.read_to_boundary that will pass # that test but fail this one. # # Strange things can happen if the last line in the file being uploaded # has length == readBlockSize -1. The boundary string marking the end of the # file (eg. '\r\n--myboundary') will be split between the leading '\r' and the # '\n'. Some implementations of read_to_boundary we've tried assume that this # '\r' character is part of the file, instead of the boundary string. The '\r' # will be appended to the uploaded file, leading to a corrupted file. print "\n * Testing file upload where length of last line == readBlockSize - 1" content = ( 'a'*100 + '\r\n' + 'b'*(readBlockSize-1) # trick ! ) digest = md5.new(content).hexdigest() rsp = self.vhost_post_multipart_form_data( "test_fileupload", variables={'test':'abcd'}, files={'testfile':('test.txt',content)}, ) if (rsp != digest): self.fail('file upload long line test failed, its contents were corrupted (%s)'%rsp) print " * Testing file upload where length of last line == readBlockSize - 1 with an extra \\r" content = ( 'a'*100 + '\r\n' + 'b'*(readBlockSize-1) + '\r' # second trick ! ) digest = md5.new(content).hexdigest() rsp = self.vhost_post_multipart_form_data( "test_fileupload", variables={'test':'abcd'}, files={'testfile':('test.txt',content)}, ) if (rsp != digest): self.fail('file upload long line test failed, its contents were corrupted (%s)'%rsp) def test_sys_argv_conf(self): c = VirtualHost("*", ServerName("test_sys_argv"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::test_sys_argv"), PythonDebug("On"))) return str(c) def test_sys_argv(self): print "\n * Testing sys.argv definition" rsp = self.vhost_get("test_sys_argv") if (rsp != "['mod_python']"): self.fail(`rsp`) def test_PythonOption_conf(self): c = VirtualHost("*", ServerName("test_PythonOption"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::PythonOption_items"), PythonDebug("On"))) return str(c) def test_PythonOption(self): print "\n * Testing PythonOption" rsp = self.vhost_get("test_PythonOption") if (rsp != "[('PythonOptionTest', 'sample_value')]"): self.fail(`rsp`) def test_PythonOption_override_conf(self): c = VirtualHost("*", ServerName("test_PythonOption_override"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::PythonOption_items"), PythonOption('PythonOptionTest "new_value"'), PythonOption('PythonOptionTest2 "new_value2"'), PythonDebug("On"))) return str(c) def test_PythonOption_override(self): print "\n * Testing PythonOption override" rsp = self.vhost_get("test_PythonOption_override") if (rsp != "[('PythonOptionTest', 'new_value'), ('PythonOptionTest2', 'new_value2')]"): self.fail(`rsp`) def test_PythonOption_remove_conf(self): c = VirtualHost("*", ServerName("test_PythonOption_remove"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::PythonOption_items"), PythonOption('PythonOptionTest ""'), PythonOption('PythonOptionTest2 "new_value2"'), PythonDebug("On"))) return str(c) def test_PythonOption_remove(self): print "\n * Testing PythonOption remove" rsp = self.vhost_get("test_PythonOption_remove") if (rsp != "[('PythonOptionTest2', 'new_value2')]"): self.fail(`rsp`) def test_PythonOption_remove2_conf(self): c = VirtualHost("*", ServerName("test_PythonOption_remove2"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::PythonOption_items"), PythonOption('PythonOptionTest'), PythonOption('PythonOptionTest2 "new_value2"'), PythonOption('PythonOptionTest3 new_value3'), PythonDebug("On"))) return str(c) def test_PythonOption_remove2(self): print "\n * Testing PythonOption remove2" rsp = self.vhost_get("test_PythonOption_remove2") if (rsp != "[('PythonOptionTest2', 'new_value2'), ('PythonOptionTest3', 'new_value3')]"): self.fail(`rsp`) def test_interpreter_per_directive_conf(self): c = VirtualHost("*", ServerName("test_interpreter_per_directive"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, PythonInterpPerDirective('On'), SetHandler("mod_python"), PythonHandler("tests::interpreter"), PythonDebug("On"))) return str(c) def test_interpreter_per_directive(self): print "\n * Testing interpreter per directive" interpreter_name = (DOCUMENT_ROOT.replace('\\', '/')+'/').upper() rsp = self.vhost_get("test_interpreter_per_directive").upper() if (rsp != interpreter_name): self.fail(`rsp`) rsp = self.vhost_get("test_interpreter_per_directive", '/subdir/foo.py').upper() if (rsp != interpreter_name): self.fail(`rsp`) rsp = self.vhost_get("test_interpreter_per_directive", '/subdir/').upper() if (rsp != interpreter_name): self.fail(`rsp`) def test_interpreter_per_directory_conf(self): c = VirtualHost("*", ServerName("test_interpreter_per_directory"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, PythonInterpPerDirectory('On'), SetHandler("mod_python"), PythonFixupHandler("tests::interpreter"), PythonHandler("tests::interpreter"), PythonDebug("On")), ) return str(c) def test_interpreter_per_directory(self): print "\n * Testing interpreter per directory" interpreter_name = (DOCUMENT_ROOT.replace('\\', '/')+'/').upper() rsp = self.vhost_get("test_interpreter_per_directory").upper() if (rsp != interpreter_name): self.fail(`rsp`) rsp = self.vhost_get("test_interpreter_per_directory", '/subdir/foo.py').upper() if (rsp != interpreter_name+'SUBDIR/'): self.fail(`rsp`) rsp = self.vhost_get("test_interpreter_per_directory", '/subdir/').upper() if (rsp != interpreter_name+'SUBDIR/'): self.fail(`rsp`) rsp = self.vhost_get("test_interpreter_per_directory", '/subdir').upper() if (rsp != interpreter_name+'SUBDIR/'): self.fail(`rsp`) def test_util_fieldstorage_conf(self): c = VirtualHost("*", ServerName("test_util_fieldstorage"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::util_fieldstorage"), PythonDebug("On"))) return str(c) def test_util_fieldstorage(self): print "\n * Testing util_fieldstorage()" params = urllib.urlencode([('spam', 1), ('spam', 2), ('eggs', 3), ('bacon', 4)]) headers = {"Host": "test_util_fieldstorage", "Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.request("POST", "/tests.py", params, headers) response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "[Field('spam', '1'), Field('spam', '2'), Field('eggs', '3'), Field('bacon', '4')]"): self.fail(`rsp`) def test_postreadrequest_conf(self): c = VirtualHost("*", ServerName("test_postreadrequest"), DocumentRoot(DOCUMENT_ROOT), SetHandler("mod_python"), PythonPath("[r'%s']+sys.path" % DOCUMENT_ROOT), PythonPostReadRequestHandler("tests::postreadrequest"), PythonDebug("On")) return str(c) def test_postreadrequest(self): print "\n * Testing PostReadRequestHandler" rsp = self.vhost_get("test_postreadrequest") if (rsp != "test ok"): self.fail(`rsp`) def test_trans_conf(self): c = VirtualHost("*", ServerName("test_trans"), DocumentRoot(DOCUMENT_ROOT), SetHandler("mod_python"), PythonPath("[r'%s']+sys.path" % DOCUMENT_ROOT), PythonTransHandler("tests::trans"), PythonDebug("On")) return str(c) def test_trans(self): print "\n * Testing TransHandler" rsp = self.vhost_get("test_trans") if (rsp[0:2] != " #"): # first line in tests.py self.fail(`rsp`) def test_import_conf(self): # configure apache to import it at startup c = Container(PythonPath("[r'%s']+sys.path" % DOCUMENT_ROOT), PythonImport("dummymodule test_import"), PythonImport("dummymodule::function test_import"), VirtualHost("*", ServerName("test_import"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::import_test"), PythonDebug("On")))) return str(c) def test_import(self): print "\n * Testing PythonImport" rsp = self.vhost_get("test_import") if (rsp != "test ok"): self.fail(`rsp`) def test_outputfilter_conf(self): c = VirtualHost("*", ServerName("test_outputfilter"), DocumentRoot(DOCUMENT_ROOT), SetHandler("mod_python"), PythonPath("[r'%s']+sys.path" % DOCUMENT_ROOT), PythonHandler("tests::simplehandler"), PythonOutputFilter("tests::outputfilter1 MP_TEST_FILTER"), PythonDebug("On"), AddOutputFilter("MP_TEST_FILTER .py")) return str(c) def test_outputfilter(self): print "\n * Testing PythonOutputFilter" rsp = self.vhost_get("test_outputfilter") if (rsp != "TEST OK"): self.fail(`rsp`) def test_req_add_output_filter_conf(self): c = VirtualHost("*", ServerName("test_req_add_output_filter"), DocumentRoot(DOCUMENT_ROOT), SetHandler("mod_python"), PythonPath("[r'%s']+sys.path" % DOCUMENT_ROOT), PythonHandler("tests::req_add_output_filter"), PythonOutputFilter("tests::outputfilter1 MP_TEST_FILTER"), PythonDebug("On")) return str(c) def test_req_add_output_filter(self): print "\n * Testing req.add_output_filter" rsp = self.vhost_get("test_req_add_output_filter") if (rsp != "TEST OK"): self.fail(`rsp`) def test_req_register_output_filter_conf(self): c = VirtualHost("*", ServerName("test_req_register_output_filter"), DocumentRoot(DOCUMENT_ROOT), SetHandler("mod_python"), PythonPath("[r'%s']+sys.path" % DOCUMENT_ROOT), PythonHandler("tests::req_register_output_filter"), PythonDebug("On")) return str(c) def test_req_register_output_filter(self): print "\n * Testing req.register_output_filter" rsp = self.vhost_get("test_req_register_output_filter") if (rsp != "TTEESSTT OOKK"): self.fail(`rsp`) def test_connectionhandler_conf(self): try: localip = socket.gethostbyname("localhost") except: localip = "127.0.0.1" self.conport = findUnusedPort() c = str(Listen("%d" % self.conport)) + \ str(VirtualHost("%s:%d" % (localip, self.conport), SetHandler("mod_python"), PythonPath("[r'%s']+sys.path" % DOCUMENT_ROOT), PythonConnectionHandler("tests::connectionhandler"))) return c def test_connectionhandler(self): print "\n * Testing PythonConnectionHandler" url = "http://127.0.0.1:%s/tests.py" % self.conport f = urllib.urlopen(url) rsp = f.read() f.close() if (rsp != "test ok"): self.fail(`rsp`) def test_internal_conf(self): c = VirtualHost("*", ServerName("test_internal"), ServerAdmin("serveradmin@somewhere.com"), ErrorLog("logs/error_log"), ServerPath("some/path"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests"), PythonOption("testing 123"), PythonDebug("On"))) return str(c) def test_internal(self): print "\n * Testing internally (status messages go to error_log)" rsp = self.vhost_get("test_internal") if (rsp[-7:] != "test ok"): self.fail("Some tests failed, see error_log") def test_pipe_ext_conf(self): c = VirtualHost("*", ServerName("test_pipe_ext"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher | .py"), PythonHandler("tests::simplehandler"), PythonDebug("On"))) return str(c) def test_pipe_ext(self): print "\n * Testing | .ext syntax" rsp = self.vhost_get("test_pipe_ext", path="/tests.py/pipe_ext") if (rsp[-8:] != "pipe ext"): self.fail(`rsp`) rsp = self.vhost_get("test_pipe_ext", path="/tests/anything") if (rsp[-7:] != "test ok"): self.fail(`rsp`) def test_cgihandler_conf(self): c = VirtualHost("*", ServerName("test_cgihandler"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.cgihandler"), PythonDebug("On"))) return str(c) def test_cgihandler(self): print "\n * Testing mod_python.cgihandler" rsp = self.vhost_get("test_cgihandler", path="/cgitest.py") if (rsp[-8:] != "test ok\n"): self.fail(`rsp`) def test_psphandler_conf(self): c = VirtualHost("*", ServerName("test_psphandler"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.psp"), PythonDebug("On"))) return str(c) def test_psphandler(self): print "\n * Testing mod_python.psp" rsp = self.vhost_get("test_psphandler", path="/psptest.psp") if (rsp[-8:] != "test ok\n"): self.fail(`rsp`) def test_psp_parser_conf(self): c = VirtualHost("*", ServerName("test_psp_parser"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.psp"), PythonDebug("On"))) return str(c) def test_psp_parser(self): print "\n * Testing mod_python.psp parser" # lines in psp_parser.psp should look like: # test::$ # # For example: # test:n:\n$ # test:t:\t$ rsp = self.vhost_get("test_psp_parser", path="/psp_parser.psp") lines = [ line.strip() for line in rsp.split('$') if line ] failures = [] for line in lines: parts = line.split(':', 2) if len(parts) < 3: continue t, test_case, test_string = parts[0:3] if not t.strip().startswith('test'): continue expected_result = test_case # do the substitutions in expected_result for ss, rs in [('-', '\\'),('CR', '\r'), ('LF', '\n'), ('TB', '\t')]: expected_result = expected_result.replace(ss, rs) if expected_result != test_string: print ' FAIL', failures.append(test_case) else: print ' PASS', print 'expect{%s} got{%s}' % (expected_result, test_string) if failures: msg = 'psp_parser parse errors for: %s' % (', '.join(failures)) self.fail(msg) def test_psp_error_conf(self): c = VirtualHost("*", ServerName("test_psp_error"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.psp"), PythonOption('mod_python.session.database_directory "%s"' % TMP_DIR), PythonDebug("On"))) return str(c) def test_psp_error(self): print "\n * Testing mod_python.psp error page" rsp = self.vhost_get("test_psp_error", path="/psptest_main.psp") if (rsp.strip().split() != ["okay","fail"]): self.fail(`rsp`) def test_Cookie_Cookie_conf(self): c = VirtualHost("*", ServerName("test_Cookie_Cookie"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::Cookie_Cookie"), PythonDebug("On"))) return str(c) def test_Cookie_Cookie(self): print "\n * Testing Cookie.Cookie" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/testz.py", skip_host=1) # this is three cookies, nastily formatted conn.putheader("Host", "test_Cookie_Cookie:%s" % PORT) conn.putheader("Cookie", "spam=foo; path=blah;;eggs=bar;") conn.putheader("Cookie", "bar=foo") conn.endheaders() response = conn.getresponse() setcookie = response.getheader("set-cookie", None) rsp = response.read() conn.close() if rsp != "test ok" or setcookie != 'path=blah, eggs=bar, bar=foo, spam=foo': print `rsp` print `setcookie` self.fail("cookie parsing failed") def test_Cookie_MarshalCookie_conf(self): c = VirtualHost("*", ServerName("test_Cookie_MarshalCookie"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::Cookie_Cookie"), PythonDebug("On"))) return str(c) def test_Cookie_MarshalCookie(self): print "\n * Testing Cookie.MarshalCookie" mc = "eggs=d049b2b61adb6a1d895646719a3dc30bcwQAAABzcGFt" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/testz.py", skip_host=1) conn.putheader("Host", "test_Cookie_MarshalCookie:%s" % PORT) conn.putheader("Cookie", mc) conn.endheaders() response = conn.getresponse() setcookie = response.getheader("set-cookie", None) rsp = response.read() conn.close() if rsp != "test ok" or setcookie != mc: print `rsp` self.fail("marshalled cookie parsing failed") # and now a long MarshalledCookie test ! mc = ('test=859690207856ec75fc641a7566894e40c1QAAAB0' 'aGlzIGlzIGEgdmVyeSBsb25nIHZhbHVlLCBsb25nIGxvb' 'mcgbG9uZyBsb25nIGxvbmcgc28gbG9uZyBidXQgd2UnbG' 'wgZmluaXNoIGl0IHNvb24=') conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/testz.py", skip_host=1) conn.putheader("Host", "test_Cookie_MarshalCookie:%s" % PORT) conn.putheader("Cookie", mc) conn.endheaders() response = conn.getresponse() setcookie = response.getheader("set-cookie", None) rsp = response.read() conn.close() if rsp != "test ok" or setcookie != mc: print `rsp` self.fail("long marshalled cookie parsing failed") def test_Session_Session_conf(self): c = VirtualHost("*", ServerName("test_Session_Session"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::Session_Session"), PythonOption('mod_python.session.database_directory "%s"' % TMP_DIR), PythonOption('mod_python.session.application_path "/path"'), PythonOption('mod_python.session.application_domain "test_Session_Session"'), PythonDebug("On"))) return str(c) def test_Session_Session(self): print "\n * Testing Session.Session" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "test_Session_Session:%s" % PORT) conn.endheaders() response = conn.getresponse() setcookie = response.getheader("set-cookie", None) rsp = response.read() conn.close() if rsp != "test ok" or setcookie == None: self.fail("session did not set a cookie") parts = setcookie.split('; ') fields = {} for part in parts: key, value = part.split('=') fields[key] = value if not fields.has_key('path') or fields['path'] != '/path': self.fail("session did not contain expected 'path'") if not fields.has_key('domain') or fields['domain'] != 'test_Session_Session': self.fail("session did not contain expected 'domain'") conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "test_Session_Session:%s" % PORT) conn.putheader("Cookie", setcookie) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if rsp != "test ok": self.fail("session did not accept our cookie") def test_Session_illegal_sid_conf(self): c = VirtualHost("*", ServerName("test_Session_Session"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::Session_Session"), PythonOption('mod_python.session.database_directory "%s"' % TMP_DIR), PythonDebug("On"))) return str(c) def test_Session_illegal_sid(self): print "\n * Testing Session with illegal session id value" bad_cookie = 'pysid=/path/traversal/attack/bad; path=/' conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "test_Session_Session:%s" % PORT) conn.putheader("Cookie", bad_cookie) conn.endheaders() response = conn.getresponse() setcookie = response.getheader("set-cookie", None) status = response.status conn.close() if status != 200 or not setcookie: self.fail("session id with illegal characters not replaced") bad_cookie = 'pysid=%s; path=/' % ('abcdef'*64) conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "test_Session_Session:%s" % PORT) conn.putheader("Cookie", bad_cookie) conn.endheaders() response = conn.getresponse() setcookie = response.getheader("set-cookie", None) status = response.status conn.close() if status != 200 or not setcookie: self.fail("session id which is too long not replaced") def test_files_directive_conf(self): c = VirtualHost("*", ServerName("test_files_directive"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, Files("*.py", SetHandler("mod_python"), PythonHandler("tests::files_directive"), PythonDebug("On")))) return str(c) def test_files_directive(self): directory = (DOCUMENT_ROOT.replace('\\', '/')+'/').upper() print "\n * Testing Files directive" rsp = self.vhost_get("test_files_directive", path="/tests.py").upper() if rsp != directory: self.fail(`rsp`) def test_none_handler_conf(self): c = VirtualHost("*", ServerName("test_none_handler"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::none_handler"), PythonDebug("On"))) return str(c) def test_none_handler(self): print "\n * Testing None handler" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py", skip_host=1) conn.putheader("Host", "test_none_handler:%s" % PORT) conn.endheaders() response = conn.getresponse() status = response.status rsp = response.read() conn.close() if status != 500: print status, rsp self.fail("none handler should generate error") def test_server_return_conf(self): c = VirtualHost("*", ServerName("test_server_return"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::server_return_1"), PythonHandler("tests::server_return_2"), PythonDebug("On"))) return str(c) def test_server_return(self): print "\n * Testing SERVER_RETURN" rsp = self.vhost_get("test_server_return") if (rsp != "test ok"): self.fail(`rsp`) def test_phase_status_conf(self): c = VirtualHost("*", ServerName("test_phase_status"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), AuthType("bogus"), AuthName("bogus"), Require("valid-user"), PythonAuthenHandler("tests::phase_status_1"), PythonAuthenHandler("tests::phase_status_2"), PythonAuthenHandler("tests::phase_status_3"), PythonAuthzHandler("tests::phase_status_4"), PythonFixupHandler("tests::phase_status_5"), PythonFixupHandler("tests::phase_status_6"), PythonFixupHandler("tests::phase_status_7"), PythonHandler("tests::phase_status_8"), PythonDebug("On"))) return str(c) def test_phase_status(self): print "\n * Testing phase status" rsp = self.vhost_get("test_phase_status") if (rsp != "test ok"): self.fail(`rsp`) def test_publisher_conf(self): c = VirtualHost("*", ServerName("test_publisher"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher(self): print "\n * Testing mod_python.publisher" rsp = self.vhost_get("test_publisher", path="/tests.py") if (rsp != "test ok, interpreter=test_publisher"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/tests.py/index") if (rsp != "test ok, interpreter=test_publisher"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/tests.py/test_publisher") if (rsp != "test ok, interpreter=test_publisher"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/") if (rsp != "test 1 ok, interpreter=test_publisher"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/foobar") if (rsp != "test 2 ok, interpreter=test_publisher"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/tests") if (rsp != "test ok, interpreter=test_publisher"): self.fail(`rsp`) def test_publisher_auth_nested_conf(self): c = VirtualHost("*", ServerName("test_publisher_auth_nested"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_auth_nested(self): print "\n * Testing mod_python.publisher auth nested" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py/test_publisher_auth_nested", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_publisher_auth_nested", PORT)) auth = base64.encodestring("spam:eggs").strip() conn.putheader("Authorization", "Basic %s" % auth) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok, interpreter=test_publisher_auth_nested"): self.fail(`rsp`) def test_publisher_auth_method_nested_conf(self): c = VirtualHost("*", ServerName("test_publisher_auth_method_nested"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_auth_method_nested(self): print "\n * Testing mod_python.publisher auth method nested" conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py/test_publisher_auth_method_nested/method", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_publisher_auth_method_nested", PORT)) auth = base64.encodestring("spam:eggs").strip() conn.putheader("Authorization", "Basic %s" % auth) conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok, interpreter=test_publisher_auth_method_nested"): self.fail(`rsp`) def test_publisher_auth_digest_conf(self): c = VirtualHost("*", ServerName("test_publisher_auth_digest"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_auth_digest(self): print "\n * Testing mod_python.publisher auth digest compatability" # The contents of the authorization header is not relevant, # as long as it looks valid. conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", "/tests.py/test_publisher", skip_host=1) conn.putheader("Host", "%s:%s" % ("test_publisher_auth_digest", PORT)) conn.putheader("Authorization", 'Digest username="Mufasa", realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", qop=auth, nc=00000001, cnonce="0a4f113b", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41"') conn.endheaders() response = conn.getresponse() rsp = response.read() conn.close() if (rsp != "test ok, interpreter=test_publisher_auth_digest"): self.fail(`rsp`) def test_publisher_security_conf(self): c = VirtualHost("*", ServerName("test_publisher"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_security(self): print "\n * Testing mod_python.publisher security" def get_status(path): conn = httplib.HTTPConnection("127.0.0.1:%s" % PORT) conn.putrequest("GET", path, skip_host=1) conn.putheader("Host", "test_publisher:%s" % PORT) conn.endheaders() response = conn.getresponse() status, response = response.status, response.read() conn.close() return status, response status, response = get_status("/tests.py/_SECRET_PASSWORD") if status != 403: self.fail('Vulnerability : underscore prefixed attribute (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/__ANSWER") if status != 403: self.fail('Vulnerability : underscore prefixed attribute (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/re") if status != 403: self.fail('Vulnerability : module published (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/OldStyleClassTest") if status != 403: self.fail('Vulnerability : old style class published (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/InstanceTest") if status != 403: self.fail('Vulnerability : new style class published (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/index/func_code") if status != 403: self.fail('Vulnerability : function traversal (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/old_instance/traverse/func_code") if status != 403: self.fail('Vulnerability : old-style method traversal (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/instance/traverse/func_code") if status != 403: self.fail('Vulnerability : new-style method traversal (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/test_dict/keys") if status != 403: self.fail('Vulnerability : built-in type traversal (%i)\n%s' % (status, response)) status, response = get_status("/tests.py/test_dict_keys") if status != 403: self.fail('Vulnerability : built-in type publishing (%i)\n%s' % (status, response)) def test_publisher_iterator_conf(self): c = VirtualHost("*", ServerName("test_publisher"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_iterator(self): print "\n * Testing mod_python.publisher iterators" rsp = self.vhost_get("test_publisher", path="/tests.py/test_dict_iteration") if (rsp != "123"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/tests.py/test_generator") if (rsp != "0123456789"): self.fail(`rsp`) def test_publisher_hierarchy_conf(self): c = VirtualHost("*", ServerName("test_publisher_hierarchy"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_hierarchy(self): print "\n * Testing mod_python.publisher hierarchy" rsp = self.vhost_get("test_publisher_hierarchy", path="/tests.py/hierarchy_root") if (rsp != "Called root"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher_hierarchy", path="/tests.py/hierarchy_root_2") if (rsp != "test ok, interpreter=test_publisher_hierarchy"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher_hierarchy", path="/tests.py/hierarchy_root/page1") if (rsp != "Called page1"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher_hierarchy", path="/tests.py/hierarchy_root_2/page1") if (rsp != "test ok, interpreter=test_publisher_hierarchy"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher_hierarchy", path="/tests.py/hierarchy_root/page1/subpage1") if (rsp != "Called subpage1"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher_hierarchy", path="/tests.py/hierarchy_root/page2") if (rsp != "Called page2"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher_hierarchy", path="/tests.py/hierarchy_root_2/page2") if (rsp != "test ok, interpreter=test_publisher_hierarchy"): self.fail(`rsp`) def test_publisher_old_style_instance_conf(self): c = VirtualHost("*", ServerName("test_publisher"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_old_style_instance(self): print "\n * Testing mod_python.publisher old-style instance publishing" rsp = self.vhost_get("test_publisher", path="/tests.py/old_instance") if (rsp != "test callable old-style instance ok"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/tests.py/old_instance/traverse") if (rsp != "test traversable old-style instance ok"): self.fail(`rsp`) def test_publisher_instance_conf(self): c = VirtualHost("*", ServerName("test_publisher"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_instance(self): print "\n * Testing mod_python.publisher instance publishing" rsp = self.vhost_get("test_publisher", path="/tests.py/instance") if (rsp != "test callable instance ok"): self.fail(`rsp`) rsp = self.vhost_get("test_publisher", path="/tests.py/instance/traverse") if (rsp != "test traversable instance ok"): self.fail(`rsp`) def test_publisher_cache_conf(self): c = VirtualHost("*", ServerName("test_publisher"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("mod_python.publisher"), PythonDebug("On"))) return str(c) def test_publisher_cache(self): ## It is not possible to get reliable results with this test # for mpm-prefork and worker, and in fact it may not be possible # to get consistent results. # Therefore this test is currently disabled in the # testPerRequestTests setup. print "\n * Testing mod_python.publisher cache" def write_published(): published = file('htdocs/temp.py','wb') published.write('import time\n') published.write('LOAD_TIME = time.time()\n') published.write('def index(req):\n') published.write(' return "OK %f"%LOAD_TIME\n') published.close() write_published() try: rsp = self.vhost_get("test_publisher", path="/temp.py") if not rsp.startswith('OK '): self.fail(`rsp`) rsp2 = self.vhost_get("test_publisher", path="/temp.py") if rsp != rsp2: self.fail( "The publisher cache has reloaded a published module" " even though it wasn't modified !" ) # We wait three seconds to be sure we won't be annoyed # by any lack of resolution of the stat().st_mtime member. time.sleep(3) write_published() rsp2 = self.vhost_get("test_publisher", path="/temp.py") if rsp == rsp2: self.fail( "The publisher cache has not reloaded a published module" " even though it was modified !" ) rsp = self.vhost_get("test_publisher", path="/temp.py") if rsp != rsp2: self.fail( "The publisher cache has reloaded a published module" " even though it wasn't modified !" ) finally: os.remove('htdocs/temp.py') def test_server_side_include_conf(self): c = VirtualHost("*", ServerName("test_server_side_include"), DocumentRoot(DOCUMENT_ROOT), Directory(DOCUMENT_ROOT, Options("+Includes"), AddType("text/html .shtml"), AddOutputFilter("INCLUDES .shtml"), PythonFixupHandler("tests::server_side_include"), PythonDebug("On"))) return str(c) def test_server_side_include(self): print "\n * Testing server side include" rsp = self.vhost_get("test_server_side_include", path="/ssi.shtml") rsp = rsp.strip() if (rsp != "test ok"): self.fail(`rsp`) class PerInstanceTestCase(unittest.TestCase, HttpdCtrl): # this is a test case which requires a complete # restart of httpd (e.g. we're using a fancy config) def tearDown(self): if self.httpd_running: self.stopHttpd() def testLoadModule(self): print "\n* Testing LoadModule" self.makeConfig() self.startHttpd() f = urllib.urlopen("http://127.0.0.1:%s/" % PORT) server_hdr = f.info()["Server"] f.close() self.failUnless(server_hdr.find("Python") > -1, "%s does not appear to load, Server header does not contain Python" % MOD_PYTHON_SO) def test_global_lock(self): print "\n * Testing _global_lock" c = Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::global_lock"), PythonDebug("On")) self.makeConfig(str(c)) self.startHttpd() f = urllib.urlopen("http://127.0.0.1:%s/tests.py" % PORT) rsp = f.read() f.close() if (rsp != "test ok"): self.fail(`rsp`) # if the mutex works, this test will take at least 5 secs ab = get_ab_path() if not ab: print " Can't find ab. Skipping _global_lock test" return t1 = time.time() print " ", time.ctime() if os.name == "nt": cmd = '%s -c 5 -n 5 http://127.0.0.1:%s/tests.py > NUL:' \ % (ab, PORT) else: cmd = '%s -c 5 -n 5 http://127.0.0.1:%s/tests.py > /dev/null' \ % (ab, PORT) print " ", cmd os.system(cmd) print " ", time.ctime() t2 = time.time() if (t2 - t1) < 5: self.fail("global_lock is broken (too quick)") def testPerRequestTests(self): print "\n* Running the per-request test suite..." perRequestSuite = unittest.TestSuite() perRequestSuite.addTest(PerRequestTestCase("test_req_document_root")) perRequestSuite.addTest(PerRequestTestCase("test_req_add_handler")) perRequestSuite.addTest(PerRequestTestCase("test_req_add_bad_handler")) perRequestSuite.addTest(PerRequestTestCase("test_req_add_empty_handler_string")) perRequestSuite.addTest(PerRequestTestCase("test_req_add_handler_empty_phase")) perRequestSuite.addTest(PerRequestTestCase("test_req_add_handler_directory")) perRequestSuite.addTest(PerRequestTestCase("test_accesshandler_add_handler_to_empty_hl")) perRequestSuite.addTest(PerRequestTestCase("test_req_allow_methods")) perRequestSuite.addTest(PerRequestTestCase("test_req_get_basic_auth_pw")) perRequestSuite.addTest(PerRequestTestCase("test_req_auth_type")) perRequestSuite.addTest(PerRequestTestCase("test_req_requires")) perRequestSuite.addTest(PerRequestTestCase("test_req_internal_redirect")) perRequestSuite.addTest(PerRequestTestCase("test_req_construct_url")) perRequestSuite.addTest(PerRequestTestCase("test_req_read")) perRequestSuite.addTest(PerRequestTestCase("test_req_readline")) perRequestSuite.addTest(PerRequestTestCase("test_req_readlines")) perRequestSuite.addTest(PerRequestTestCase("test_req_discard_request_body")) perRequestSuite.addTest(PerRequestTestCase("test_req_register_cleanup")) perRequestSuite.addTest(PerRequestTestCase("test_req_headers_out")) perRequestSuite.addTest(PerRequestTestCase("test_req_sendfile")) perRequestSuite.addTest(PerRequestTestCase("test_req_sendfile2")) perRequestSuite.addTest(PerRequestTestCase("test_req_sendfile3")) perRequestSuite.addTest(PerRequestTestCase("test_req_handler")) perRequestSuite.addTest(PerRequestTestCase("test_req_no_cache")) perRequestSuite.addTest(PerRequestTestCase("test_req_update_mtime")) perRequestSuite.addTest(PerRequestTestCase("test_util_redirect")) perRequestSuite.addTest(PerRequestTestCase("test_req_server_get_config")) perRequestSuite.addTest(PerRequestTestCase("test_req_server_get_options")) perRequestSuite.addTest(PerRequestTestCase("test_fileupload")) perRequestSuite.addTest(PerRequestTestCase("test_fileupload_embedded_cr")) perRequestSuite.addTest(PerRequestTestCase("test_fileupload_split_boundary")) perRequestSuite.addTest(PerRequestTestCase("test_sys_argv")) perRequestSuite.addTest(PerRequestTestCase("test_PythonOption_override")) perRequestSuite.addTest(PerRequestTestCase("test_PythonOption_remove")) perRequestSuite.addTest(PerRequestTestCase("test_PythonOption_remove2")) perRequestSuite.addTest(PerRequestTestCase("test_util_fieldstorage")) perRequestSuite.addTest(PerRequestTestCase("test_postreadrequest")) perRequestSuite.addTest(PerRequestTestCase("test_trans")) perRequestSuite.addTest(PerRequestTestCase("test_outputfilter")) perRequestSuite.addTest(PerRequestTestCase("test_req_add_output_filter")) perRequestSuite.addTest(PerRequestTestCase("test_req_register_output_filter")) perRequestSuite.addTest(PerRequestTestCase("test_connectionhandler")) perRequestSuite.addTest(PerRequestTestCase("test_import")) perRequestSuite.addTest(PerRequestTestCase("test_pipe_ext")) perRequestSuite.addTest(PerRequestTestCase("test_cgihandler")) perRequestSuite.addTest(PerRequestTestCase("test_psphandler")) perRequestSuite.addTest(PerRequestTestCase("test_psp_parser")) perRequestSuite.addTest(PerRequestTestCase("test_psp_error")) perRequestSuite.addTest(PerRequestTestCase("test_Cookie_Cookie")) perRequestSuite.addTest(PerRequestTestCase("test_Cookie_MarshalCookie")) perRequestSuite.addTest(PerRequestTestCase("test_Session_Session")) perRequestSuite.addTest(PerRequestTestCase("test_Session_illegal_sid")) perRequestSuite.addTest(PerRequestTestCase("test_interpreter_per_directive")) perRequestSuite.addTest(PerRequestTestCase("test_interpreter_per_directory")) perRequestSuite.addTest(PerRequestTestCase("test_files_directive")) perRequestSuite.addTest(PerRequestTestCase("test_none_handler")) perRequestSuite.addTest(PerRequestTestCase("test_server_return")) perRequestSuite.addTest(PerRequestTestCase("test_phase_status")) perRequestSuite.addTest(PerRequestTestCase("test_publisher")) perRequestSuite.addTest(PerRequestTestCase("test_publisher_auth_nested")) perRequestSuite.addTest(PerRequestTestCase("test_publisher_auth_method_nested")) perRequestSuite.addTest(PerRequestTestCase("test_publisher_auth_digest")) perRequestSuite.addTest(PerRequestTestCase("test_publisher_old_style_instance")) perRequestSuite.addTest(PerRequestTestCase("test_publisher_instance")) perRequestSuite.addTest(PerRequestTestCase("test_publisher_security")) # perRequestSuite.addTest(PerRequestTestCase("test_publisher_iterator")) perRequestSuite.addTest(PerRequestTestCase("test_publisher_hierarchy")) # test_publisher_cache does not work correctly for mpm-prefork/worker # and it man not be possible to get a reliable test for all # configurations, so disable it. #perRequestSuite.addTest(PerRequestTestCase("test_publisher_cache")) perRequestSuite.addTest(PerRequestTestCase("test_server_side_include")) # this must be last so its error_log is not overwritten perRequestSuite.addTest(PerRequestTestCase("test_internal")) self.makeConfig(PerRequestTestCase.appendConfig) self.startHttpd() tr = unittest.TextTestRunner() result = tr.run(perRequestSuite) self.failUnless(result.wasSuccessful()) def test_srv_register_cleanup(self): print "\n* Testing server.register_cleanup()..." c = Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::srv_register_cleanup"), PythonDebug("On")) self.makeConfig(str(c)) self.startHttpd() f = urllib.urlopen("http://127.0.0.1:%s/tests.py" % PORT) f.read() f.close() time.sleep(2) self.stopHttpd() # see what's in the log now time.sleep(2) f = open(os.path.join(SERVER_ROOT, "logs/error_log")) log = f.read() f.close() if log.find("srv_register_cleanup test ok") == -1: self.fail("Could not find test message in error_log") def test_apache_register_cleanup(self): print "\n* Testing apache.register_cleanup()..." c = Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::apache_register_cleanup"), PythonDebug("On")) self.makeConfig(str(c)) self.startHttpd() f = urllib.urlopen("http://127.0.0.1:%s/tests.py" % PORT) f.read() f.close() time.sleep(2) self.stopHttpd() # see what's in the log now time.sleep(2) f = open(os.path.join(SERVER_ROOT, "logs/error_log")) log = f.read() f.close() if log.find("apache_register_cleanup test ok") == -1: self.fail("Could not find test message in error_log") def test_apache_exists_config_define(self): print "\n* Testing apache.exists_config_define()..." c = Directory(DOCUMENT_ROOT, SetHandler("mod_python"), PythonHandler("tests::apache_exists_config_define"), PythonDebug("On")) self.makeConfig(str(c)) self.startHttpd() f = urllib.urlopen("http://127.0.0.1:%s/tests.py" % PORT) rsp = f.read() f.close() self.stopHttpd() if rsp != 'NO_FOOBAR': self.fail('Failure on apache.exists_config_define() : %s'%rsp) self.startHttpd(extra="-DFOOBAR") f = urllib.urlopen("http://127.0.0.1:%s/tests.py" % PORT) rsp = f.read() f.close() self.stopHttpd() if rsp != 'FOOBAR': self.fail('Failure on apache.exists_config_define() : %s'%rsp) def suite(): mpTestSuite = unittest.TestSuite() mpTestSuite.addTest(PerInstanceTestCase("testLoadModule")) mpTestSuite.addTest(PerInstanceTestCase("test_srv_register_cleanup")) mpTestSuite.addTest(PerInstanceTestCase("test_apache_register_cleanup")) mpTestSuite.addTest(PerInstanceTestCase("test_apache_exists_config_define")) mpTestSuite.addTest(PerInstanceTestCase("test_global_lock")) mpTestSuite.addTest(PerInstanceTestCase("testPerRequestTests")) return mpTestSuite tr = unittest.TextTestRunner() tr.run(suite()) mod_python-3.3.1/test/README0000644000175000017500000000626610345235130013663 0ustar jimjimRunning the test suite ====================== 1) Setting up Apache -------------------- - You must have a valid Apache 2 installation, responding to start and stop commands. The test suite will launch an Apache instance with its own configuration file, on its own TCP/IP port, so hopefully it won't break anything on your Apache setup. - If you're running the Apache Monitor under Win32 (the tray icon that shows the state of the Apache Server), you'll notice that it will show the status of the test server during the tests. Unfortunately once the tests are over the monitor does not revert back to showing the status of your Apache server. The server itself is still running, though. 2) Setting up mod_python source code ------------------------------------ - The source code is required because the unit test aren't provided in the binary distributions. - Get it from http://www.modpython.org/ or using SVN from : http://svn.apache.org/repos/asf/httpd/mod_python/trunk - We'll suppose you've extracted or checked it out in a directory named MOD_PYTHON. - Either you run the MOD_PYTHON/configure script... - ..or if you're under Win32, then running the configure script may be too much of a hassle. We advise you to copy MOD_PYTHON/test/testconf.py.in to MOD_PYTHON/test/testconf.py and edit this file as described in the comments. 3) Building and/or installing mod_python binaries ------------------------------------------------- - If you're really adventurous, you may want to build mod_python from source. Then it's either "./configure; make; make install" on Unix, or running MOD_PYTHON/dist/build_installer.bat on Win32. - The best way to ensure that the test suite will run is to install the target mod_python binaries on your system. The complete list of binaries (including Win32 ones) can be found following the "Other Binaries" link on : http://httpd.apache.org/modules/python-download.cgi - Running your own version of mod_python without installing it is possible and useful if you cannot be root, but you're a bit on your own, sorry. You'll have to make sure MOD_PYTHON/testconf.py points to the right version of mod_python.so and tweak Apache user's PYTHONPATH environment variable so that mod_python can find its Python modules. 4) Running the test suite ------------------------- In the current directory, just launch the test.py script : python test.py You should see a bunch of text scrolling by as the tests unfold. If everything goes well, you should see two lines around the end of the unput, one with : 8<---8<---8<---8<---8<--- Ran 43 tests in 17.955s OK 8<---8<---8<---8<---8<--- and the other with : 8<---8<---8<---8<---8<--- Ran 6 tests in 70.942s OK 8<---8<---8<---8<---8<--- Of course the number of tests will vary in the future, but what's important here are the two shiny "OK". This means the tests were successful. 5) Report the results --------------------- Now you can report your success to python-dev@httpd.apache.org ! Of course if it's not successful and you're sure it's not due to a problem in your setup, we're also interested. Send us the full output of the test suite, or at least the stack trace of the failed tests. Thanks for your time spent of running those tests !mod_python-3.3.1/src/0000755000175000017500000000000010557377762012630 5ustar jimjimmod_python-3.3.1/src/include/0000755000175000017500000000000010557377762014253 5ustar jimjimmod_python-3.3.1/src/include/serverobject.h0000644000175000017500000000237710151454154017107 0ustar jimjim#ifndef Mp_SERVEROBJECT_H #define Mp_SERVEROBJECT_H #ifdef __cplusplus extern "C" { #endif /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * serverobject.h * * $Id: serverobject.h 106619 2004-11-25 22:10:52Z nd $ * */ typedef struct serverobject { PyObject_HEAD PyObject *dict; server_rec *server; PyObject *next; } serverobject; extern DL_IMPORT(PyTypeObject) MpServer_Type; #define MpServer_Check(op) ((op)->ob_type == &MpServer_Type) extern DL_IMPORT(PyObject *) MpServer_FromServer Py_PROTO((server_rec *s)); #ifdef __cplusplus } #endif #endif /* !Mp_SERVEROBJECT_H */ mod_python-3.3.1/src/include/_pspmodule.h0000644000175000017500000000140610151454154016551 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * $Id: _pspmodule.h 106619 2004-11-25 22:10:52Z nd $ * */ #ifndef __PSP_MODULE_H #define __PSP_MODULE_H void init_psp(void); #endif /* __PSP_MODULE_H */ mod_python-3.3.1/src/include/hlistobject.h0000644000175000017500000000240210470063622016711 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * hlistobject.h * * $Id: hlistobject.h 431327 2006-08-14 12:07:46Z grahamd $ * * See accompanying documentation and source code comments * for details. * */ #ifndef Mp_HLISTOBJECT_H #define Mp_HLISTOBJECT_H #ifdef __cplusplus extern "C" { #endif typedef struct hlist { PyObject_HEAD struct hl_entry *head; } hlistobject; extern DL_IMPORT(PyTypeObject) MpHList_Type; #define MpHList_Check(op) ((op)->ob_type == &MpHList_Type) extern DL_IMPORT(PyObject *)MpHList_FromHLEntry Py_PROTO((hl_entry *hle)); #ifdef __cplusplus } #endif #endif /* !Mp_HLISTOBJECT_H */ mod_python-3.3.1/src/include/filterobject.h0000644000175000017500000000375510463104564017072 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * filterobject.h * * $Id: filterobject.h 426882 2006-07-30 10:27:00Z grahamd $ * */ #ifndef Mp_FILTEROBJECT_H #define Mp_FILTEROBJECT_H #ifdef __cplusplus extern "C" { #endif typedef struct filterobject { PyObject_HEAD ap_filter_t *f; /* in out refers to the dircetion of data with respect to filter, not the filter type */ apr_bucket_brigade *bb_in; apr_bucket_brigade *bb_out; apr_status_t rc; int is_input; ap_input_mode_t mode; apr_size_t readbytes; int closed; int softspace; int bytes_written; char *handler; PyObject *callable; char *dir; hl_entry *parent; requestobject *request_obj; } filterobject; extern DL_IMPORT(PyTypeObject) MpFilter_Type; #define MpFilter_Check(op) ((op)->ob_type == &MpFilter_Type) extern DL_IMPORT(PyObject *) MpFilter_FromFilter Py_PROTO((ap_filter_t *f, apr_bucket_brigade *bb_in, int is_input, ap_input_mode_t mode, apr_size_t readbytes, char *handler, PyObject *callable, char *dir, hl_entry *parent)); #ifdef __cplusplus } #endif #endif /* !Mp_FILTEROBJECT_H */ mod_python-3.3.1/src/include/util.h0000644000175000017500000000243210151454154015357 0ustar jimjim#ifndef Mp_UTIL_H #define Mp_UTIL_H /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * util.h * * $Id: util.h 106619 2004-11-25 22:10:52Z nd $ * * See accompanying documentation and source code comments * for details. * */ PyObject * tuple_from_array_header(const apr_array_header_t *ah); PyObject * tuple_from_method_list(const ap_method_list_t *l); PyObject *tuple_from_finfo(apr_finfo_t *f); PyObject *tuple_from_apr_uri(apr_uri_t *u); char * get_addhandler_extensions(request_rec *req); apr_status_t python_decref(void *object); PyMemberDef *find_memberdef(const PyMemberDef *mlist, const char *name); PyObject *cfgtree_walk(ap_directive_t *dir); #endif /* !Mp_UTIL_H */ mod_python-3.3.1/src/include/tableobject.h0000644000175000017500000000262610151454154016665 0ustar jimjim#ifndef Mp_TABLEOBJECT_H #define Mp_TABLEOBJECT_H #ifdef __cplusplus extern "C" { #endif /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * tableobject.h * * $Id: tableobject.h 106619 2004-11-25 22:10:52Z nd $ * */ /* * This is a mapping of a Python object to an Apache table. * */ typedef struct tableobject { PyObject_VAR_HEAD apr_table_t *table; apr_pool_t *pool; } tableobject; extern DL_IMPORT(PyTypeObject) MpTable_Type; extern DL_IMPORT(PyTypeObject) MpTableIter_Type; #define MpTable_Check(op) ((op)->ob_type == &MpTable_Type) extern DL_IMPORT(PyObject *) MpTable_FromTable Py_PROTO((apr_table_t *t)); extern DL_IMPORT(PyObject *) MpTable_New Py_PROTO((void)); #ifdef __cplusplus } #endif #endif /* !Mp_TABLEOBJECT_H */ mod_python-3.3.1/src/include/psp_parser.h0000644000175000017500000000222410151454154016557 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * $Id: psp_parser.h 106619 2004-11-25 22:10:52Z nd $ * */ #ifndef __PSP_PARSER_H #define __PSP_PARSER_H #include "psp_string.h" #include #define STATIC_STR(s) s, sizeof(s)-1 #define PSP_PG(v) (((psp_parser_t*)yyget_extra(yyscanner))->v) typedef struct { /* PyObject *files; XXX removed until cache is fixed */ psp_string whitespace; psp_string pycode; char * dir; unsigned is_psp_echo : 1; unsigned after_colon : 1; unsigned seen_newline : 1; } psp_parser_t; #endif /* __PSP_PARSER_H */ mod_python-3.3.1/src/include/requestobject.h0000644000175000017500000000371110512145713017261 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * requestobject.h * * $Id: requestobject.h 454115 2006-10-08 09:58:35Z grahamd $ * */ #ifndef Mp_REQUESTOBJECT_H #define Mp_REQUESTOBJECT_H #ifdef __cplusplus extern "C" { #endif typedef struct requestobject { PyObject_HEAD PyObject * dict; request_rec * request_rec; PyObject * connection; PyObject * server; PyObject * headers_in; PyObject * headers_out; PyObject * err_headers_out; PyObject * subprocess_env; PyObject * notes; PyObject * phase; char * extension; /* for | .ext syntax */ int content_type_set; apr_off_t bytes_queued; hlistobject * hlo; PyObject * callbacks; char * rbuff; /* read bufer */ int rbuff_len; /* read buffer size */ int rbuff_pos; /* position into the buffer */ PyObject * session; } requestobject; extern DL_IMPORT(PyTypeObject) MpRequest_Type; #define MpRequest_Check(op) ((op)->ob_type == &MpRequest_Type) extern DL_IMPORT(PyObject *) MpRequest_FromRequest Py_PROTO((request_rec *r)); #ifdef __cplusplus } #endif #endif /* !Mp_REQUESTOBJECT_H */ mod_python-3.3.1/src/include/psp_flex.h0000644000175000017500000001745010175546722016241 0ustar jimjim#ifndef yyHEADER_H #define yyHEADER_H 1 #define yyIN_HEADER 1 #line 6 "include/psp_flex.h" #line 8 "include/psp_flex.h" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 31 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r int yylex_init (yyscan_t* scanner); #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef unsigned int yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ void yyrestart (FILE *input_file ,yyscan_t yyscanner ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); void yypop_buffer_state (yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); void *yyalloc (yy_size_t ,yyscan_t yyscanner ); void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); void yyfree (void * ,yyscan_t yyscanner ); /* Begin user sect3 */ #define yywrap(n) 1 #define YY_SKIP_YYWRAP #define yytext_ptr yytext_r #ifdef YY_HEADER_EXPORT_START_CONDITIONS #define INITIAL 0 #define TEXT 1 #define PYCODE 2 #define INDENT 3 #define DIR 4 #define COMMENT 5 #endif /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #ifndef WIN32 #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (yyscan_t yyscanner ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (yyscan_t yyscanner ); int yyget_debug (yyscan_t yyscanner ); void yyset_debug (int debug_flag ,yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); FILE *yyget_in (yyscan_t yyscanner ); void yyset_in (FILE * in_str ,yyscan_t yyscanner ); FILE *yyget_out (yyscan_t yyscanner ); void yyset_out (FILE * out_str ,yyscan_t yyscanner ); int yyget_leng (yyscan_t yyscanner ); char *yyget_text (yyscan_t yyscanner ); int yyget_lineno (yyscan_t yyscanner ); void yyset_lineno (int line_number ,yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (yyscan_t yyscanner ); #else extern int yywrap (yyscan_t yyscanner ); #endif #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (yyscan_t yyscanner); #define YY_DECL int yylex (yyscan_t yyscanner) #endif /* !YY_DECL */ /* yy_get_previous_state - get the state just before the EOB char was reached */ #undef YY_NEW_FILE #undef YY_FLUSH_BUFFER #undef yy_set_bol #undef yy_new_buffer #undef yy_set_interactive #undef yytext_ptr #undef YY_DO_BEFORE_ACTION #ifdef YY_DECL_IS_OURS #undef YY_DECL_IS_OURS #undef YY_DECL #endif #line 228 "psp_parser.l" #line 328 "include/psp_flex.h" #undef yyIN_HEADER #endif /* yyHEADER_H */ mod_python-3.3.1/src/include/mod_python.h0000644000175000017500000001354010517305602016563 0ustar jimjim#ifndef Mp_MOD_PYTHON_H #define Mp_MOD_PYTHON_H /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * mod_python.h * * $Id: mod_python.h 467228 2006-10-24 03:41:54Z grahamd $ * * See accompanying documentation and source code comments * for details. * */ /* * NOTE - NOTE - NOTE - NOTE * * If you are looking at mod_python.h, it is an auto-generated file on * UNIX. This file is kept around for the Win32 platform which * doesnot use autoconf. Any changes to mod_python.h must also be * reflected in mod_python.h.in. */ /* Apache headers */ #include "httpd.h" #define CORE_PRIVATE #include "http_config.h" #include "http_core.h" #include "http_main.h" #include "http_connection.h" #include "http_protocol.h" #include "http_request.h" #include "util_script.h" #include "util_filter.h" #include "http_log.h" #include "apr_strings.h" #include "apr_lib.h" #include "apr_hash.h" #include "apr_fnmatch.h" #include "scoreboard.h" #include "ap_mpm.h" #include "ap_mmn.h" #include "mod_include.h" #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) #include "unixd.h" #endif #if !AP_MODULE_MAGIC_AT_LEAST(20050127,0) /* Debian backported ap_regex_t to Apache 2.0 and * thus made official version checking break. */ #ifndef AP_REG_EXTENDED typedef regex_t ap_regex_t; #define AP_REG_EXTENDED REG_EXTENDED #define AP_REG_ICASE REG_ICASE #endif #endif /* Python headers */ /* this gets rid of some compile warnings */ #if defined(_POSIX_THREADS) #undef _POSIX_THREADS #endif #include "Python.h" #include "structmember.h" #if defined(WIN32) && !defined(WITH_THREAD) #error Python threading must be enabled on Windows #endif #if !defined(WIN32) #include #endif /* pool given to us in ChildInit. We use it for server.register_cleanup() */ extern apr_pool_t *child_init_pool; /* Apache module declaration */ extern module AP_MODULE_DECLARE_DATA python_module; #include "mpversion.h" #include "util.h" #include "hlist.h" #include "hlistobject.h" #include "tableobject.h" #include "serverobject.h" #include "connobject.h" #include "_apachemodule.h" #include "requestobject.h" #include "filterobject.h" #include "_pspmodule.h" #include "finfoobject.h" /** Things specific to mod_python, as an Apache module **/ #define MP_CONFIG_KEY "mod_python_config" #define VERSION_COMPONENT "mod_python/" MPV_STRING #define MODULENAME "mod_python.apache" #define INITFUNC "init" #define MAIN_INTERPRETER "main_interpreter" #define FILTER_NAME "MOD_PYTHON" /* used in python_directive_handler */ #define SILENT 1 #define NOTSILENT 0 /* MAX_LOCKS can now be set as a configure option * ./configure --with-max-locks=INTEGER */ #define MAX_LOCKS 8 /* MUTEX_DIR can be set as a configure option * ./configure --with-mutex-dir=/path/to/dir */ #define MUTEX_DIR "/tmp" /* python 2.3 no longer defines LONG_LONG, it defines PY_LONG_LONG */ #ifndef LONG_LONG #define LONG_LONG PY_LONG_LONG #endif /* structure to hold interpreter data */ typedef struct { PyInterpreterState *istate; PyObject *obcallback; } interpreterdata; /* global configuration parameters */ typedef struct { apr_global_mutex_t **g_locks; int nlocks; int parent_pid; } py_global_config; /* structure describing per directory configuration parameters */ typedef struct { int authoritative; char *config_dir; apr_table_t *directives; apr_table_t *options; apr_hash_t *hlists; /* hlists for every phase */ apr_hash_t *in_filters; apr_hash_t *out_filters; apr_table_t *imports; /* for PythonImport */ } py_config; /* register_cleanup info */ typedef struct { request_rec *request_rec; server_rec *server_rec; PyObject *handler; const char *interpreter; PyObject *data; } cleanup_info; /* request config structure */ typedef struct { requestobject *request_obj; apr_hash_t *dynhls; /* dynamically registered handlers for this request */ apr_hash_t *in_filters; /* dynamically registered input filters for this request */ apr_hash_t *out_filters; /* dynamically registered output filters for this request */ } py_req_config; /* filter context */ typedef struct { char *name; int transparent; } python_filter_ctx; /* a structure to hold a handler, used in configuration for filters */ typedef struct { char *handler; PyObject *callable; char *directory; int d_is_fnmatch; ap_regex_t *d_regex; char *location; int l_is_fnmatch; ap_regex_t *l_regex; hl_entry *parent; } py_handler; apr_status_t python_cleanup(void *data); PyObject* python_interpreter_name(void); requestobject *python_get_request_object(request_rec *req, const char *phase); APR_DECLARE_OPTIONAL_FN(PyInterpreterState *, mp_acquire_interpreter, (const char *)); APR_DECLARE_OPTIONAL_FN(void *, mp_release_interpreter, ()); APR_DECLARE_OPTIONAL_FN(PyObject *, mp_get_request_object, (request_rec *)); APR_DECLARE_OPTIONAL_FN(PyObject *, mp_get_server_object, (server_rec *)); APR_DECLARE_OPTIONAL_FN(PyObject *, mp_get_connection_object, (conn_rec *)); #endif /* !Mp_MOD_PYTHON_H */ /* # makes emacs go into C mode ### Local Variables: ### mode:c ### End: */ mod_python-3.3.1/src/include/mpversion.h0000644000175000017500000000016210557374400016427 0ustar jimjim#define MPV_MAJOR 3 #define MPV_MINOR 3 #define MPV_PATCH 1 #define MPV_BUILD 20070129 #define MPV_STRING "3.3.1" mod_python-3.3.1/src/include/hlist.h0000644000175000017500000000426310517305602015530 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * hlist.h * * $Id: hlist.h 467228 2006-10-24 03:41:54Z grahamd $ * * See accompanying documentation and source code comments * for details. * */ #ifndef Mp_HLIST_H #define Mp_HLIST_H #ifdef __cplusplus extern "C" { #endif /* handler list entry */ typedef struct hl_entry { const char *handler; PyObject *callable; const char *directory; int d_is_fnmatch; ap_regex_t *d_regex; const char *location; int l_is_fnmatch; ap_regex_t *l_regex; int silent; /* 1 for PythonHandlerModule, where if a handler is not found in a module, no error should be reported */ struct hl_entry *next; struct hl_entry *parent; } hl_entry; hl_entry *hlist_new(apr_pool_t *p, const char *h, PyObject* o, const char *d, int d_is_fnmatch, ap_regex_t *d_regex, const char *l, int l_is_fnmatch, ap_regex_t *l_regex, const int s, hl_entry* parent); hl_entry *hlist_append(apr_pool_t *p, hl_entry *hle, const char * h, PyObject* o, const char *d, int d_is_fnmatch, ap_regex_t *d_regex, const char *l, int l_is_fnmatch, ap_regex_t *l_regex, const int s, hl_entry* parent); hl_entry *hlist_copy(apr_pool_t *p, const hl_entry *hle); void hlist_extend(apr_pool_t *p, hl_entry *hle1, const hl_entry *hle2); #ifdef __cplusplus } #endif #endif /* !Mp_HLIST_H */ mod_python-3.3.1/src/include/connobject.h0000644000175000017500000000311710523422146016526 0ustar jimjim#ifndef Mp_CONNOBJECT_H #define Mp_CONNOBJECT_H #ifdef __cplusplus extern "C" { #endif /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * connobject.h * * $Id: connobject.h 471474 2006-11-05 17:50:30Z jgallacher $ * */ /* * This is a mapping of a Python object to an Apache table. * * This object behaves like a dictionary. Note that the * underlying table can have duplicate keys, which can never * happen to a Python dictionary. But this is such a rare thing * that I can't even think of a possible scenario or implications. * */ typedef struct connobject { PyObject_HEAD conn_rec *conn; PyObject *base_server; PyObject *notes; hlistobject *hlo; } connobject; extern DL_IMPORT(PyTypeObject) MpConn_Type; #define MpConn_Check(op) ((op)->ob_type == &MpConn_Type) extern DL_IMPORT(PyObject *) MpConn_FromConn Py_PROTO((conn_rec *c)); #ifdef __cplusplus } #endif #endif /* !Mp_CONNOBJECT_H */ mod_python-3.3.1/src/include/mod_python.h.in0000644000175000017500000001356410517305602017176 0ustar jimjim#ifndef Mp_MOD_PYTHON_H #define Mp_MOD_PYTHON_H /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * mod_python.h * * $Id: mod_python.h 231054 2005-08-09 15:37:04Z jgallacher $ * * See accompanying documentation and source code comments * for details. * */ /* * NOTE - NOTE - NOTE - NOTE * * If you are looking at mod_python.h, it is an auto-generated file on * UNIX. This file is kept around for the Win32 platform which * doesnot use autoconf. Any changes to mod_python.h must also be * reflected in mod_python.h.in. */ /* Apache headers */ #include "httpd.h" #define CORE_PRIVATE #include "http_config.h" #include "http_core.h" #include "http_main.h" #include "http_connection.h" #include "http_protocol.h" #include "http_request.h" #include "util_script.h" #include "util_filter.h" #include "http_log.h" #include "apr_strings.h" #include "apr_lib.h" #include "apr_hash.h" #include "apr_fnmatch.h" #include "scoreboard.h" #include "ap_mpm.h" #include "ap_mmn.h" #include "mod_include.h" #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) #include "unixd.h" #endif #if !AP_MODULE_MAGIC_AT_LEAST(20050127,0) /* Debian backported ap_regex_t to Apache 2.0 and * thus made official version checking break. */ #ifndef AP_REG_EXTENDED typedef regex_t ap_regex_t; #define AP_REG_EXTENDED REG_EXTENDED #define AP_REG_ICASE REG_ICASE #endif #endif /* Python headers */ /* this gets rid of some compile warnings */ #if defined(_POSIX_THREADS) #undef _POSIX_THREADS #endif #include "Python.h" #include "structmember.h" #if defined(WIN32) && !defined(WITH_THREAD) #error Python threading must be enabled on Windows #endif #if !defined(WIN32) #include #endif /* pool given to us in ChildInit. We use it for server.register_cleanup() */ extern apr_pool_t *child_init_pool; /* Apache module declaration */ extern module AP_MODULE_DECLARE_DATA python_module; #include "mpversion.h" #include "util.h" #include "hlist.h" #include "hlistobject.h" #include "tableobject.h" #include "serverobject.h" #include "connobject.h" #include "_apachemodule.h" #include "requestobject.h" #include "filterobject.h" #include "_pspmodule.h" #include "finfoobject.h" /** Things specific to mod_python, as an Apache module **/ #define MP_CONFIG_KEY "mod_python_config" #define VERSION_COMPONENT "mod_python/" MPV_STRING #define MODULENAME "mod_python.apache" #define INITFUNC "init" #define MAIN_INTERPRETER "main_interpreter" #define FILTER_NAME "MOD_PYTHON" /* used in python_directive_handler */ #define SILENT 1 #define NOTSILENT 0 /* MAX_LOCKS can now be set as a configure option * ./configure --with-max-locks=INTEGER */ #define MAX_LOCKS @MAX_LOCKS@ /* MUTEX_DIR can be set as a configure option * ./configure --with-mutex-dir=/path/to/dir */ #define MUTEX_DIR "@MUTEX_DIR@" /* python 2.3 no longer defines LONG_LONG, it defines PY_LONG_LONG */ #ifndef LONG_LONG #define LONG_LONG PY_LONG_LONG #endif /* structure to hold interpreter data */ typedef struct { PyInterpreterState *istate; PyObject *obcallback; } interpreterdata; /* global configuration parameters */ typedef struct { apr_global_mutex_t **g_locks; int nlocks; int parent_pid; } py_global_config; /* structure describing per directory configuration parameters */ typedef struct { int authoritative; char *config_dir; apr_table_t *directives; apr_table_t *options; apr_hash_t *hlists; /* hlists for every phase */ apr_hash_t *in_filters; apr_hash_t *out_filters; apr_table_t *imports; /* for PythonImport */ } py_config; /* register_cleanup info */ typedef struct { request_rec *request_rec; server_rec *server_rec; PyObject *handler; const char *interpreter; PyObject *data; } cleanup_info; /* request config structure */ typedef struct { requestobject *request_obj; apr_hash_t *dynhls; /* dynamically registered handlers for this request */ apr_hash_t *in_filters; /* dynamically registered input filters for this request */ apr_hash_t *out_filters; /* dynamically registered output filters for this request */ } py_req_config; /* filter context */ typedef struct { char *name; int transparent; } python_filter_ctx; /* a structure to hold a handler, used in configuration for filters */ typedef struct { char *handler; PyObject *callable; char *directory; int d_is_fnmatch; ap_regex_t *d_regex; char *location; int l_is_fnmatch; ap_regex_t *l_regex; hl_entry *parent; } py_handler; apr_status_t python_cleanup(void *data); PyObject* python_interpreter_name(void); requestobject *python_get_request_object(request_rec *req, const char *phase); APR_DECLARE_OPTIONAL_FN(PyInterpreterState *, mp_acquire_interpreter, (const char *)); APR_DECLARE_OPTIONAL_FN(void *, mp_release_interpreter, ()); APR_DECLARE_OPTIONAL_FN(PyObject *, mp_get_request_object, (request_rec *)); APR_DECLARE_OPTIONAL_FN(PyObject *, mp_get_server_object, (server_rec *)); APR_DECLARE_OPTIONAL_FN(PyObject *, mp_get_connection_object, (conn_rec *)); #endif /* !Mp_MOD_PYTHON_H */ /* # makes emacs go into C mode ### Local Variables: ### mode:c ### End: */ mod_python-3.3.1/src/include/_apachemodule.h0000644000175000017500000000173410151454154017174 0ustar jimjim#ifndef Mp_APACHEMODULE_H #define Mp_APACHEMODULE_H /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * apachemodule.h * * $Id: _apachemodule.h 106619 2004-11-25 22:10:52Z nd $ * * See accompanying documentation and source code comments * for details. * */ PyObject *get_ServerReturn(void); DL_EXPORT(void) init_apache(void); #endif /* !Mp_APACHEMODULE_H */ mod_python-3.3.1/src/include/psp_string.h0000644000175000017500000000230010151454154016564 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * $Id: psp_string.h 106619 2004-11-25 22:10:52Z nd $ * */ #ifndef __PSP_STRING_H #define __PSP_STRING_H #include #include #ifndef PSP_STRING_BLOCK #define PSP_STRING_BLOCK 256 #endif typedef struct { size_t allocated; size_t length; char *blob; } psp_string; void psp_string_0(psp_string *); void psp_string_appendl(psp_string *, char *, size_t); void psp_string_append(psp_string *, char *); void psp_string_appendc(psp_string *, char); void psp_string_clear(psp_string *); void psp_string_free(psp_string *); #endif /* __PSP_STRING_H */ mod_python-3.3.1/src/include/finfoobject.h0000644000175000017500000000243010473317323016673 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * finfoobject.h * * $Id: finfoobject.h 434388 2006-08-24 12:42:59Z grahamd $ * */ #ifndef Mp_FINFOOBJECT_H #define Mp_FINFOOBJECT_H #ifdef __cplusplus extern "C" { #endif typedef struct finfoobject { PyObject_HEAD apr_pool_t *pool; apr_finfo_t *finfo; } finfoobject; extern DL_IMPORT(PyTypeObject) MpFinfo_Type; #define MpFinfo_Check(op) ((op)->ob_type == &MpFinfo_Type) extern DL_IMPORT(PyObject *) MpFinfo_FromFinfo Py_PROTO((apr_finfo_t *f)); extern DL_IMPORT(PyObject *) MpFinfo_New Py_PROTO((void)); #ifdef __cplusplus } #endif #endif /* !Mp_FINFOOBJECT_H */ mod_python-3.3.1/src/util.c0000644000175000017500000002564110516147342013741 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * util.c * * $Id: util.c 466105 2006-10-20 13:28:02Z jgallacher $ * * See accompanying documentation and source code comments * for details. * */ #include "mod_python.h" /** ** tuple_from_array_header ** * Given an array header return a tuple. The array elements * assumed to be strings. */ PyObject * tuple_from_array_header(const apr_array_header_t *ah) { PyObject *t; int i; char **s; if (ah == NULL) { /* PYTHON 2.5: PyTuple_New uses Py_ssize_t for input parameters */ t = PyTuple_New(0); } else { /* PYTHON 2.5: PyTuple_New uses Py_ssize_t for input parameters */ t = PyTuple_New(ah->nelts); s = (char **) ah->elts; for (i = 0; i < ah->nelts; i++) { /* PYTHON 2.5: PyTuple_SetItem uses Py_ssize_t for input parameters */ PyTuple_SetItem(t, i, PyString_FromString(s[i])); } } return t; } /** ** tuple_from_method_list ** * Given an apr_method_list_t return a tuple. */ PyObject * tuple_from_method_list(const ap_method_list_t *l) { PyObject *t; int i; char **methods; if ((l->method_list == NULL) || (l->method_list->nelts == 0)) { /* PYTHON 2.5: PyTuple_New uses Py_ssize_t for input parameters */ t = PyTuple_New(0); } else { /* PYTHON 2.5: PyTuple_New uses Py_ssize_t for input parameters */ t = PyTuple_New(l->method_list->nelts); methods = (char **)l->method_list->elts; for (i = 0; i < l->method_list->nelts; ++i) { /* PYTHON 2.5: PyTuple_SetItem uses Py_ssize_t for input parameters */ PyTuple_SetItem(t, i, PyString_FromString(methods[i])); } } return t; } /** ** tuple_from_finfo ** * makes a tuple similar to return of os.stat() from apr_finfo_t * */ PyObject *tuple_from_finfo(apr_finfo_t *f) { PyObject *t; if (f->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } /* PYTHON 2.5: PyTuple_New uses Py_ssize_t for input parameters */ t = PyTuple_New(13); /* this should have been first, but was added later */ PyTuple_SET_ITEM(t, 12, PyInt_FromLong(f->filetype)); if (f->valid & APR_FINFO_PROT) { PyTuple_SET_ITEM(t, 0, PyInt_FromLong(f->protection)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 0, Py_None); } if (f->valid & APR_FINFO_INODE) { PyTuple_SET_ITEM(t, 1, PyInt_FromLong(f->inode)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 1, Py_None); } if (f->valid & APR_FINFO_DEV) { PyTuple_SET_ITEM(t, 2, PyInt_FromLong(f->device)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 2, Py_None); } if (f->valid & APR_FINFO_NLINK) { PyTuple_SET_ITEM(t, 3, PyInt_FromLong(f->nlink)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 3, Py_None); } if (f->valid & APR_FINFO_USER) { PyTuple_SET_ITEM(t, 4, PyInt_FromLong(f->user)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 4, Py_None); } if (f->valid & APR_FINFO_GROUP) { PyTuple_SET_ITEM(t, 5, PyInt_FromLong(f->group)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 5, Py_None); } if (f->valid & APR_FINFO_SIZE) { PyTuple_SET_ITEM(t, 6, PyInt_FromLong(f->size)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 6, Py_None); } if (f->valid & APR_FINFO_ATIME) { PyTuple_SET_ITEM(t, 7, PyInt_FromLong(f->atime*0.000001)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 7, Py_None); } if (f->valid & APR_FINFO_MTIME) { PyTuple_SET_ITEM(t, 8, PyInt_FromLong(f->mtime*0.000001)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 8, Py_None); } if (f->valid & APR_FINFO_CTIME) { PyTuple_SET_ITEM(t, 9, PyInt_FromLong(f->ctime*0.000001)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 9, Py_None); } if (f->fname) { PyTuple_SET_ITEM(t, 10, PyString_FromString(f->fname)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 10, Py_None); } if (f->valid & APR_FINFO_NAME) { PyTuple_SET_ITEM(t, 11, PyString_FromString(f->name)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 11, Py_None); } /* it'd be nice to also return the file dscriptor, f->filehand->filedes, but it's platform dependent, so may be later... */ return t; } /** ** tuple_from_apr_uri ** * makes a tuple from uri_components * */ PyObject *tuple_from_apr_uri(apr_uri_t *u) { PyObject *t; /* PYTHON 2.5: PyTuple_New uses Py_ssize_t for input parameters */ t = PyTuple_New(9); if (u->scheme) { PyTuple_SET_ITEM(t, 0, PyString_FromString(u->scheme)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 0, Py_None); } if (u->hostinfo) { PyTuple_SET_ITEM(t, 1, PyString_FromString(u->hostinfo)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 1, Py_None); } if (u->user) { PyTuple_SET_ITEM(t, 2, PyString_FromString(u->user)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 2, Py_None); } if (u->password) { PyTuple_SET_ITEM(t, 3, PyString_FromString(u->password)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 3, Py_None); } if (u->hostname) { PyTuple_SET_ITEM(t, 4, PyString_FromString(u->hostname)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 4, Py_None); } if (u->port_str) { PyTuple_SET_ITEM(t, 5, PyInt_FromLong(u->port)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 5, Py_None); } if (u->path) { PyTuple_SET_ITEM(t, 6, PyString_FromString(u->path)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 6, Py_None); } if (u->query) { PyTuple_SET_ITEM(t, 7, PyString_FromString(u->query)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 7, Py_None); } if (u->fragment) { PyTuple_SET_ITEM(t, 8, PyString_FromString(u->fragment)); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(t, 8, Py_None); } /* XXX hostent, is_initialized, dns_* */ return t; } /** ** python_decref ** * This helper function is used with apr_pool_cleanup_register to destroy * python objects when a certain pool is destroyed. */ apr_status_t python_decref(void *object) { Py_XDECREF((PyObject *) object); return 0; } /** ** find_module ** * Find an Apache module by name, used by get_addhandler_extensions */ static module *find_module(char *name) { int n; for (n = 0; ap_loaded_modules[n]; ++n) { if (strcmp(name, ap_loaded_modules[n]->name) == 0) return ap_loaded_modules[n]; } return NULL; } /** ** get_addhandler_extensions ** * Get extensions specified for AddHandler, if any. To do this we * retrieve mod_mime's config. This is used by the publisher to strip * file extentions from modules in the most meaningful way. * * XXX This function is a hack and will stop working if mod_mime people * decide to change their code. A better way to implement this would * be via the config tree, but it doesn't seem to be quite there just * yet, because it doesn't have .htaccess directives. */ char * get_addhandler_extensions(request_rec *req) { /* these typedefs are copied from mod_mime.c */ typedef struct { apr_hash_t *extension_mappings; apr_array_header_t *remove_mappings; char *default_language; int multimatch; } mime_dir_config; typedef struct extension_info { char *forced_type; /* Additional AddTyped stuff */ char *encoding_type; /* Added with AddEncoding... */ char *language_type; /* Added with AddLanguage... */ char *handler; /* Added with AddHandler... */ char *charset_type; /* Added with AddCharset... */ char *input_filters; /* Added with AddInputFilter... */ char *output_filters; /* Added with AddOutputFilter... */ } extension_info; mime_dir_config *mconf; apr_hash_index_t *hi; void *val; void *key; extension_info *ei; char *result = NULL; module *mod_mime = find_module("mod_mime.c"); mconf = (mime_dir_config *) ap_get_module_config(req->per_dir_config, mod_mime); if (mconf->extension_mappings) { for (hi = apr_hash_first(req->pool, mconf->extension_mappings); hi; hi = apr_hash_next(hi)) { apr_hash_this(hi, (const void **)&key, NULL, &val); ei = (extension_info *)val; if (ei->handler) if (strcmp("mod_python", ei->handler) == 0 || strcmp("python-program", ei->handler) == 0) result = apr_pstrcat(req->pool, (char *)key, " ", result, NULL); } } return result; } /** ** find_memberdef ** * Find a memberdef in a PyMemberDef array */ PyMemberDef *find_memberdef(const PyMemberDef *mlist, const char *name) { const PyMemberDef *md; for (md = mlist; md->name != NULL; md++) if (strcmp(md->name, name) == 0) return (PyMemberDef *)md; /* this should never happen or the mlist is screwed up */ return NULL; } /** ** cfgtree_walk ** * walks ap_directive_t tree returning a list of * tuples and lists */ PyObject *cfgtree_walk(ap_directive_t *dir) { /* PYTHON 2.5: PyList_New uses Py_ssize_t for input parameters */ PyObject *list = PyList_New(0); if (!list) return PyErr_NoMemory(); while (dir) { PyObject *t = Py_BuildValue("(s, s)", dir->directive, dir->args); if (!t) return PyErr_NoMemory(); PyList_Append(list, t); Py_DECREF(t); if (dir->first_child) { PyObject *child = cfgtree_walk(dir->first_child); if (!child) return PyErr_NoMemory(); PyList_Append(list, child); Py_DECREF(child); } dir = dir->next; } return list; } mod_python-3.3.1/src/mod_python.vcproj0000644000175000017500000000636310151454154016222 0ustar jimjim mod_python-3.3.1/src/Makefile.in0000644000175000017500000000352410473317323014661 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Originally developed by Gregory Trubetskoy. # CC=@CC@ AR=@AR@ APXS=@APXS@ MKDEP=@MKDEP@ # requires flex 2.5.31 for reentrant support LEX=@LEX@ INCLUDES=@INCLUDES@ LIBS=@LIBS@ LDFLAGS=@LDFLAGS@ OPT= CFLAGS=$(OPT) $(INCLUDES) srcdir=. SRCS= mod_python.c _apachemodule.c requestobject.c tableobject.c util.c \ serverobject.c connobject.c filterobject.c hlist.c \ hlistobject.c finfoobject.c all: @ALL@ psp_parser.c: psp_parser.l @rm -f psp_parser.c $(LEX) -R -opsp_parser.c --header-file=include/psp_flex.h psp_parser.l dso: mod_python.so @echo dso > .install mod_python.so: $(SRCS) @SOLARIS_HACKS@ @echo @echo 'Compiling for DSO.' @echo $(APXS) $(INCLUDES) -c $(SRCS) $(LDFLAGS) $(LIBS) @SOLARIS_HACKS@ @rm -f mod_python.so @ln -s .libs/mod_python.so mod_python.so clean: rm -rf $(OBJS) core libpython.a mod_python.so *~ .libs *.o *.slo *.lo *.la distclean: clean rm -f Makefile .depend .install # this is a hack to help avoid a gcc/solaris problem # python uses assert() which needs _eprintf(). See # SOLARIS_HACKS above _eprintf.o: ar -x `gcc -print-libgcc-file-name` _eprintf.o _floatdidf.o: ar -x `gcc -print-libgcc-file-name` _floatdidf.o _muldi3.o: ar -x `gcc -print-libgcc-file-name` _muldi3.o # DO NOT DELETE THIS LINE mod_python-3.3.1/src/hlistobject.c0000644000175000017500000001175310517305602015271 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * hlist.c * * $Id: hlistobject.c 467228 2006-10-24 03:41:54Z grahamd $ * * See accompanying documentation and source code comments * for details. * */ #include "mod_python.h" /** ** MpHList_FromHLEntry() ** * new list from hl_entry */ PyObject *MpHList_FromHLEntry(hl_entry *hle) { hlistobject *result; result = PyObject_New(hlistobject, &MpHList_Type); if (! result) PyErr_NoMemory(); result->head = hle; return (PyObject *) result; } /** ** hlist_next ** */ static PyObject *hlist_next(hlistobject *self, PyObject *args) { if (! self->head) { Py_INCREF(Py_None); return Py_None; } self->head = self->head->next; Py_INCREF(Py_None); return Py_None; } static PyMethodDef hlistmethods[] = { {"next", (PyCFunction) hlist_next, METH_VARARGS}, { NULL, NULL } /* sentinel */ }; #define OFF(x) offsetof(hl_entry, x) static struct memberlist hlist_memberlist[] = { {"directory", T_STRING, OFF(directory), RO}, {"location", T_STRING, OFF(location), RO}, {"silent", T_INT, OFF(silent), RO}, {NULL} /* Sentinel */ }; /** ** hlist_dealloc ** */ static void hlist_dealloc(hlistobject *self) { PyObject_Del(self); } /** ** hlist_getattr ** */ static PyObject *hlist_getattr(hlistobject *self, char *name) { PyObject *res; res = Py_FindMethod(hlistmethods, (PyObject *)self, name); if (res != NULL) return res; PyErr_Clear(); /* when we are at the end of the list, everything would return None */ if (! self->head) { Py_INCREF(Py_None); return Py_None; } if (strcmp(name, "handler") == 0) { if (self->head->callable) { Py_INCREF(self->head->callable); return self->head->callable; } else if (self->head->handler) { return PyString_FromString(self->head->handler); } else { Py_INCREF(Py_None); return Py_None; } } else if (strcmp(name, "parent") == 0) { if (self->head->parent) { return MpHList_FromHLEntry(self->head->parent); } else { Py_INCREF(Py_None); return Py_None; } } return PyMember_Get((char *)self->head, hlist_memberlist, name); } /** ** hlist_repr ** * */ static PyObject *hlist_repr(hlistobject *self) { PyObject *t; PyObject *s; if (! self->head) { s = PyString_FromString("None"); return s; } s = PyString_FromString("{"); if (self->head->handler) { PyString_ConcatAndDel(&s, PyString_FromString("'handler':")); t = PyString_FromString(self->head->handler); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); } else if (self->head->callable) { PyString_ConcatAndDel(&s, PyString_FromString("'handler':")); PyString_ConcatAndDel(&s, PyObject_Repr(self->head->callable)); } if (self->head->directory) { PyString_ConcatAndDel(&s, PyString_FromString(",'directory':")); t = PyString_FromString(self->head->directory); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); } if (self->head->location) { PyString_ConcatAndDel(&s, PyString_FromString(",'location':")); t = PyString_FromString(self->head->location); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); } PyString_ConcatAndDel(&s, PyString_FromString(",'silent':")); if (self->head->silent) PyString_ConcatAndDel(&s, PyString_FromString("1}")); else PyString_ConcatAndDel(&s, PyString_FromString("0}")); return s; } PyTypeObject MpHList_Type = { PyObject_HEAD_INIT(NULL) 0, "mp_hlist", sizeof(hlistobject), 0, (destructor) hlist_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc) hlist_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ (reprfunc)hlist_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; mod_python-3.3.1/src/_pspmodule.c0000644000175000017500000001000710470372273015123 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * This file originally written by Stering Hughes * * $Id: _pspmodule.c 431636 2006-08-15 16:22:19Z jgallacher $ * * See accompanying documentation and source code comments for * details. * */ #include "psp_flex.h" #include "psp_parser.h" #include "psp_string.h" #include "_pspmodule.h" #include "Python.h" /* calm down compile warning from psp_flex.h*/ static int yy_init_globals (yyscan_t yyscanner ) {return 0;}; static psp_parser_t *psp_parser_init(void) { psp_parser_t *parser; parser = (psp_parser_t *) malloc(sizeof(*parser)); memset(&parser->pycode, 0, sizeof(psp_string)); memset(&parser->whitespace, 0, sizeof(psp_string)); parser->dir = NULL; parser->is_psp_echo = 0; parser->after_colon = 0; parser->seen_newline = 0; return parser; } static void psp_parser_cleanup(psp_parser_t *parser) { if (parser->pycode.allocated) { free(parser->pycode.blob); } if (parser->whitespace.allocated) { free(parser->whitespace.blob); } free(parser); } static PyObject * _psp_module_parse(PyObject *self, PyObject *argv) { PyObject *code; char *filename; char *dir = NULL; char *path; psp_parser_t *parser; yyscan_t scanner; FILE *f; if (!PyArg_ParseTuple(argv, "s|s", &filename, &dir)) { return NULL; } if (dir) { path = malloc(strlen(filename)+strlen(dir)+1); if (!path) return PyErr_NoMemory(); strcpy(path, dir); strcat(path, filename); } else { path = filename; } Py_BEGIN_ALLOW_THREADS f = fopen(path, "rb"); Py_END_ALLOW_THREADS if (f == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, path); if (dir) free(path); return NULL; } if (dir) free(path); parser = psp_parser_init(); if (dir) parser->dir = dir; yylex_init(&scanner); yyset_in(f, scanner); yyset_extra(parser, scanner); yylex(scanner); yylex_destroy(scanner); fclose(f); psp_string_0(&parser->pycode); if (PyErr_Occurred()) { psp_parser_cleanup(parser); return NULL; } if (parser->pycode.blob) { code = PyString_FromString(parser->pycode.blob); } else { code = PyString_FromString(""); } psp_parser_cleanup(parser); return code; } static PyObject * _psp_module_parsestring(PyObject *self, PyObject *argv) { PyObject *code; PyObject *str; yyscan_t scanner; psp_parser_t *parser; YY_BUFFER_STATE bs; if (!PyArg_ParseTuple(argv, "S", &str)) { return NULL; } Py_BEGIN_ALLOW_THREADS parser = psp_parser_init(); yylex_init(&scanner); yyset_extra(parser, scanner); bs = yy_scan_string(PyString_AsString(str), scanner); yylex(scanner); /* yy_delete_buffer(bs, scanner); */ yylex_destroy(scanner); psp_string_0(&parser->pycode); Py_END_ALLOW_THREADS if (parser->pycode.blob) { code = PyString_FromString(parser->pycode.blob); } else { code = PyString_FromString(""); } psp_parser_cleanup(parser); return code; } struct PyMethodDef _psp_module_methods[] = { {"parse", (PyCFunction) _psp_module_parse, METH_VARARGS}, {"parsestring", (PyCFunction) _psp_module_parsestring, METH_VARARGS}, {NULL, NULL} }; void init_psp(void) { Py_InitModule("_psp", _psp_module_methods); } mod_python-3.3.1/src/Version.rc0000644000175000017500000000347710151454154014573 0ustar jimjim#define APSTUDIO_READONLY_SYMBOLS #include "afxres.h" #include "include\mpversion.h" #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION MPV_MAJOR,MPV_MINOR,MPV_PATCH,MPV_BUILD PRODUCTVERSION MPV_MAJOR,MPV_MINOR,MPV_PATCH,MPV_BUILD FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "Mod_python allows embedding Python within the Apache http server for a considerable boost in performance and added flexibility in designing web based applications. \0" VALUE "CompanyName", "\0" VALUE "FileDescription", "Embedding Python within Apache.\0" VALUE "FileVersion", MPV_STRING "\0" VALUE "InternalName", "mod_python\0" VALUE "LegalCopyright", "Copyright © 2000-2002 Apache Software Foundation.\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "mod_python\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "mod_python\0" VALUE "ProductVersion", MPV_STRING "\0" VALUE "SpecialBuild", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // !_MAC #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// mod_python-3.3.1/src/filterobject.c0000644000175000017500000004051510516147342015435 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * filterobject.c * * $Id: filterobject.c 466105 2006-10-20 13:28:02Z jgallacher $ * * See accompanying documentation and source code comments * for details. * */ #include "mod_python.h" /*** Some explanation of what is going on here: * * In Apache terminology, an "input" filter filters data flowing from * network to application (aka "up"), an "output" filter filters data * flowing from application to network (aka "down"). * * An output filter is invoked as a result of ap_pass_brigade() * call. It is given a populated brigade, which it then gives in the * same fashion to the next filter via ap_pass_brigade(). (The filter * may chose to create a new brigade and pass it instead). * * An input filter is invoked as a result of ap_get_brigade() call. It * is given an empty brigade, which it is expected to populate, which * may in turn require the filter to invoke the next filter in the * same fashion (via ap_get_brigade()). * * In mod_python Output filters: * * filter.read() - copies data from *given* bucket brigade (saved in * self->bb_in) into a Python string. * * filter.write() - copies data from a Python string into a *new* * bucket brigade (saved in self->bb_out). * * filter.close() - appends an EOS and passes the self->bb_out brigade * to the next filter via ap_pass_brigade() * * In mod_python Input filters: * * filter.read() - copies data from a *new* and *populated via * ap_get_brigade* (saved as self->bb_in) into a Python string. * * filter.write() - copies data from a Python string into a *given* * brigade (saved as self->bb_out). * * filter.close() - appends an EOS to *given* brigade. * */ /** ** MpFilter_FromFilter ** * This routine creates a Python filerobject. * */ PyObject *MpFilter_FromFilter(ap_filter_t *f, apr_bucket_brigade *bb, int is_input, ap_input_mode_t mode, apr_size_t readbytes, char *handler, PyObject *callable, char *dir, hl_entry *parent) { filterobject *result; result = PyObject_New(filterobject, &MpFilter_Type); if (! result) return PyErr_NoMemory(); result->f = f; result->is_input = is_input; result->rc = APR_SUCCESS; if (is_input) { result->bb_in = NULL; result->bb_out = bb; result->mode = mode; result->readbytes = readbytes; } else { result->bb_in = bb; result->bb_out = NULL; result->mode = 0; result->readbytes = 0; } result->closed = 0; result->softspace = 0; result->handler = handler; result->callable = callable; result->dir = dir; result->parent = parent; result->request_obj = NULL; apr_pool_cleanup_register(f->r->pool, (PyObject *)result, python_decref, apr_pool_cleanup_null); return (PyObject *)result; } /** ** filter_pass_on ** * just passes everything on */ static PyObject *filter_pass_on(filterobject *self) { Py_BEGIN_ALLOW_THREADS; if (self->is_input) self->rc = ap_get_brigade(self->f->next, self->bb_out, self->mode, APR_BLOCK_READ, self->readbytes); else self->rc = ap_pass_brigade(self->f->next, self->bb_in); Py_END_ALLOW_THREADS; Py_INCREF(Py_None); return Py_None; } /** ** _filter_read ** * read from filter - works for both read() and readline() */ static PyObject *_filter_read(filterobject *self, PyObject *args, int readline) { apr_bucket *b; long bytes_read; PyObject *result; char *buffer; long bufsize; int newline = 0; long len = -1; conn_rec *c = self->request_obj->request_rec->connection; if (! PyArg_ParseTuple(args, "|l", &len)) return NULL; if (self->closed) { PyErr_SetString(PyExc_ValueError, "I/O operation on closed filter"); return NULL; } if (self->is_input) { /* does the output brigade exist? */ if (!self->bb_in) { self->bb_in = apr_brigade_create(self->f->r->pool, c->bucket_alloc); } Py_BEGIN_ALLOW_THREADS; self->rc = ap_get_brigade(self->f->next, self->bb_in, self->mode, APR_BLOCK_READ, self->readbytes); Py_END_ALLOW_THREADS; if (!APR_STATUS_IS_EAGAIN(self->rc) && !(self->rc == APR_SUCCESS)) { PyErr_SetObject(PyExc_IOError, PyString_FromString("Input filter read error")); return NULL; } } /* * loop through the brigade reading buckets into the string */ b = APR_BRIGADE_FIRST(self->bb_in); if (b == APR_BRIGADE_SENTINEL(self->bb_in)) return PyString_FromString(""); /* reached eos ? */ if (APR_BUCKET_IS_EOS(b)) { apr_bucket_delete(b); Py_INCREF(Py_None); return Py_None; } bufsize = len < 0 ? HUGE_STRING_LEN : len; /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ result = PyString_FromStringAndSize(NULL, bufsize); /* possibly no more memory */ if (result == NULL) return PyErr_NoMemory(); buffer = PyString_AS_STRING((PyStringObject *) result); bytes_read = 0; while ((bytes_read < len || len == -1) && !(APR_BUCKET_IS_EOS(b) || APR_BUCKET_IS_FLUSH(b) || b == APR_BRIGADE_SENTINEL(self->bb_in))) { const char *data; apr_size_t size; apr_bucket *old; int i; if (apr_bucket_read(b, &data, &size, APR_BLOCK_READ) != APR_SUCCESS) { PyErr_SetObject(PyExc_IOError, PyString_FromString("Filter read error")); return NULL; } if (bytes_read + size > bufsize) { apr_bucket_split(b, bufsize - bytes_read); size = bufsize - bytes_read; /* now the bucket is the exact size we need */ } if (readline) { /* scan for newline */ for (i=0; iis_input) { */ /* if (b == APR_BRIGADE_SENTINEL(self->bb_in)) { */ /* /\* brigade ended, but no EOS - get another */ /* brigade *\/ */ /* Py_BEGIN_ALLOW_THREADS; */ /* self->rc = ap_get_brigade(self->f->next, self->bb_in, self->mode, */ /* APR_BLOCK_READ, self->readbytes); */ /* Py_END_ALLOW_THREADS; */ /* if (! APR_STATUS_IS_SUCCESS(self->rc)) { */ /* PyErr_SetObject(PyExc_IOError, */ /* PyString_FromString("Input filter read error")); */ /* return NULL; */ /* } */ /* b = APR_BRIGADE_FIRST(self->bb_in); */ /* } */ /* } */ } /* resize if necessary */ if (bytes_read < len || len < 0) /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ if(_PyString_Resize(&result, bytes_read)) return NULL; return result; } /** ** filter.read(filter self, int bytes) ** * Reads from previous filter */ static PyObject *filter_read(filterobject *self, PyObject *args) { return _filter_read(self, args, 0); } /** ** filter.readline(filter self, int bytes) ** * Reads a line from previous filter */ static PyObject *filter_readline(filterobject *self, PyObject *args) { return _filter_read(self, args, 1); } /** ** filter.write(filter self) ** * Write to next filter */ static PyObject *filter_write(filterobject *self, PyObject *args) { char *buff; int len; apr_bucket *b; PyObject *s; conn_rec *c = self->request_obj->request_rec->connection; if (! PyArg_ParseTuple(args, "O", &s)) return NULL; if (! PyString_Check(s)) { PyErr_SetString(PyExc_TypeError, "Argument to write() must be a string"); return NULL; } if (self->closed) { PyErr_SetString(PyExc_ValueError, "I/O operation on closed filter"); return NULL; } /* PYTHON 2.5: 'PyString_Size' uses Py_ssize_t for return values (may need overflow check) */ len = PyString_Size(s); if (len) { /* does the output brigade exist? */ if (!self->bb_out) { self->bb_out = apr_brigade_create(self->f->r->pool, c->bucket_alloc); } buff = apr_bucket_alloc(len, c->bucket_alloc); memcpy(buff, PyString_AS_STRING(s), len); b = apr_bucket_heap_create(buff, len, apr_bucket_free, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(self->bb_out, b); } Py_INCREF(Py_None); return Py_None; } /** ** filter.flush(filter self) ** * Flush output (i.e. pass brigade) */ static PyObject *filter_flush(filterobject *self, PyObject *args) { conn_rec *c = self->request_obj->request_rec->connection; /* does the output brigade exist? */ if (!self->bb_out) { self->bb_out = apr_brigade_create(self->f->r->pool, c->bucket_alloc); } APR_BRIGADE_INSERT_TAIL(self->bb_out, apr_bucket_flush_create(c->bucket_alloc)); if (!self->is_input) { Py_BEGIN_ALLOW_THREADS; self->rc = ap_pass_brigade(self->f->next, self->bb_out); apr_brigade_destroy(self->bb_out); Py_END_ALLOW_THREADS; if(self->rc != APR_SUCCESS) { PyErr_SetString(PyExc_IOError, "Flush failed."); return NULL; } } Py_INCREF(Py_None); return Py_None; } /** ** filter.close(filter self) ** * passes EOS */ static PyObject *filter_close(filterobject *self, PyObject *args) { conn_rec *c = self->request_obj->request_rec->connection; if (! self->closed) { /* does the output brigade exist? */ if (!self->bb_out) { self->bb_out = apr_brigade_create(self->f->r->pool, c->bucket_alloc); } APR_BRIGADE_INSERT_TAIL(self->bb_out, apr_bucket_eos_create(c->bucket_alloc)); if (! self->is_input) { Py_BEGIN_ALLOW_THREADS; self->rc = ap_pass_brigade(self->f->next, self->bb_out); apr_brigade_destroy(self->bb_out); Py_END_ALLOW_THREADS; self->bb_out = NULL; } self->closed = 1; } Py_INCREF(Py_None); return Py_None; } /** ** filter.disable(filter self) ** * Sets the transparent flag on causeing the filter_handler to * just pass the data through without envoking Python at all. * This is used during filter error output. */ static PyObject *filter_disable(filterobject *self, PyObject *args) { python_filter_ctx *ctx; ctx = (python_filter_ctx *) self->f->ctx; ctx->transparent = 1; Py_INCREF(Py_None); return Py_None; } static PyMethodDef filterobjectmethods[] = { {"pass_on", (PyCFunction) filter_pass_on, METH_NOARGS}, {"read", (PyCFunction) filter_read, METH_VARARGS}, {"readline", (PyCFunction) filter_readline, METH_VARARGS}, {"write", (PyCFunction) filter_write, METH_VARARGS}, {"flush", (PyCFunction) filter_flush, METH_VARARGS}, {"close", (PyCFunction) filter_close, METH_VARARGS}, {"disable", (PyCFunction) filter_disable, METH_VARARGS}, {NULL, NULL} }; #define OFF(x) offsetof(filterobject, x) static struct memberlist filter_memberlist[] = { {"softspace", T_INT, OFF(softspace), }, {"closed", T_INT, OFF(closed), RO}, {"name", T_OBJECT, 0, RO}, {"req", T_OBJECT, OFF(request_obj), }, {"is_input", T_INT, OFF(is_input), RO}, {"dir", T_STRING, OFF(dir), RO}, {NULL} /* Sentinel */ }; /** ** filter_dealloc ** * */ static void filter_dealloc(filterobject *self) { Py_XDECREF(self->request_obj); PyObject_Del(self); } /** ** filter_getattr ** * Get filter object attributes * * */ static PyObject * filter_getattr(filterobject *self, char *name) { PyObject *res; res = Py_FindMethod(filterobjectmethods, (PyObject *)self, name); if (res != NULL) return res; PyErr_Clear(); if (strcmp(name, "name") == 0) { if (! self->f->frec->name) { Py_INCREF(Py_None); return Py_None; } else { return PyString_FromString(self->f->frec->name); } } else if (strcmp(name, "req") == 0) { if (! self->request_obj) { Py_INCREF(Py_None); return Py_None; } else { Py_INCREF(self->request_obj); return (PyObject *)self->request_obj; } } else if (strcmp(name, "handler") == 0) { if (self->callable) { Py_INCREF(self->callable); return self->callable; } else if (self->handler) { return PyString_FromString(self->handler); } else { Py_INCREF(Py_None); return Py_None; } } else if (strcmp(name, "parent") == 0) { if (self->parent) { return MpHList_FromHLEntry(self->parent); } else { Py_INCREF(Py_None); return Py_None; } } else return PyMember_Get((char *)self, filter_memberlist, name); } /** ** filter_setattr ** * Set filter object attributes * */ static int filter_setattr(filterobject *self, char *name, PyObject *v) { if (v == NULL) { PyErr_SetString(PyExc_AttributeError, "can't delete filter attributes"); return -1; } return PyMember_Set((char *)self, filter_memberlist, name, v); } PyTypeObject MpFilter_Type = { PyObject_HEAD_INIT(NULL) 0, "mp_filter", sizeof(filterobject), 0, (destructor) filter_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc) filter_getattr, /*tp_getattr*/ (setattrfunc) filter_setattr, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; mod_python-3.3.1/src/psp_parser.c0000644000175000017500000016560610424736222015147 0ustar jimjim#line 2 "psp_parser.c" #line 4 "psp_parser.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 33 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r int yylex_init (yyscan_t* scanner); /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ,yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef unsigned int yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] void yyrestart (FILE *input_file ,yyscan_t yyscanner ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); void yypop_buffer_state (yyscan_t yyscanner ); static void yyensure_buffer_stack (yyscan_t yyscanner ); static void yy_load_buffer_state (yyscan_t yyscanner ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); void *yyalloc (yy_size_t ,yyscan_t yyscanner ); void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); void yyfree (void * ,yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define yywrap(n) 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); static int yy_get_next_buffer (yyscan_t yyscanner ); static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 23 #define YY_END_OF_BUFFER 24 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[73] = { 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 24, 2, 1, 2, 11, 10, 11, 11, 11, 15, 12, 12, 15, 14, 19, 18, 19, 19, 16, 23, 23, 23, 23, 1, 10, 7, 3, 4, 5, 12, 13, 18, 17, 16, 21, 0, 0, 0, 6, 8, 0, 0, 9, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 6, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 10, 11, 12, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, 1, 1, 15, 16, 17, 18, 1, 1, 19, 1, 1, 20, 1, 21, 1, 1, 1, 22, 1, 23, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[25] = { 0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int16_t yy_base[79] = { 0, 0, 2, 4, 16, 28, 35, 6, 43, 4, 5, 81, 80, 87, 90, 90, 83, 90, 90, 82, 77, 6, 90, 90, 80, 70, 90, 90, 90, 78, 68, 20, 90, 67, 57, 69, 90, 90, 41, 90, 90, 90, 90, 90, 90, 90, 31, 90, 61, 68, 66, 90, 90, 53, 60, 90, 47, 90, 54, 52, 63, 16, 37, 35, 36, 46, 32, 10, 35, 0, 34, 11, 90, 57, 59, 61, 63, 65, 0 } ; static yyconst flex_int16_t yy_def[79] = { 0, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 77, 77, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 78, 78, 78, 0, 72, 72, 72, 72, 72, 72 } ; static yyconst flex_int16_t yy_nxt[115] = { 0, 70, 72, 15, 16, 15, 16, 18, 19, 28, 29, 33, 33, 30, 20, 68, 69, 71, 21, 18, 19, 61, 46, 34, 34, 46, 20, 39, 40, 41, 21, 23, 24, 46, 62, 25, 46, 26, 23, 24, 71, 69, 25, 67, 26, 31, 28, 29, 31, 50, 30, 66, 51, 65, 52, 64, 63, 67, 14, 14, 17, 17, 22, 22, 27, 27, 32, 32, 61, 60, 59, 58, 57, 56, 55, 54, 53, 49, 48, 47, 45, 44, 43, 42, 38, 37, 36, 72, 35, 35, 13, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72 } ; static yyconst flex_int16_t yy_chk[115] = { 0, 78, 0, 1, 1, 2, 2, 3, 3, 7, 7, 9, 10, 7, 3, 67, 67, 71, 3, 4, 4, 61, 31, 9, 10, 31, 4, 21, 21, 21, 4, 5, 5, 46, 61, 5, 46, 5, 6, 6, 70, 68, 6, 66, 6, 8, 8, 8, 8, 38, 8, 65, 38, 64, 38, 63, 62, 65, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 60, 59, 58, 56, 54, 53, 50, 49, 48, 35, 34, 33, 30, 29, 25, 24, 20, 19, 16, 13, 12, 11, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72 } ; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET #line 1 "psp_parser.l" #line 2 "psp_parser.l" /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * $Id: psp_parser.c 398222 2006-04-29 19:20:50Z jgallacher $ * * This file originally written by Sterling Hughes. * */ /* NOTE The seemingly unusual generated Python code (sometime using * ";" to separate statements, newline placement, etc) is such that * for vast majority of cases the line number of the input file will * match the line number of the output! */ #include "psp_parser.h" #define OUTPUT_WHITESPACE(__wsstring) \ psp_string_0((__wsstring)); \ psp_string_append(&PSP_PG(pycode), (__wsstring)->blob) #define CLEAR_WHITESPACE(__wsstring) psp_string_clear((__wsstring)); #define YY_NO_UNISTD_H 1 #line 527 "psp_parser.c" #define INITIAL 0 #define TEXT 1 #define PYCODE 2 #define INDENT 3 #define DIR 4 #define COMMENT 5 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; int yy_n_chars; int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; }; /* end struct yyguts_t */ static int yy_init_globals (yyscan_t yyscanner ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (yyscan_t yyscanner ); int yyget_debug (yyscan_t yyscanner ); void yyset_debug (int debug_flag ,yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner ); void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); FILE *yyget_in (yyscan_t yyscanner ); void yyset_in (FILE * in_str ,yyscan_t yyscanner ); FILE *yyget_out (yyscan_t yyscanner ); void yyset_out (FILE * out_str ,yyscan_t yyscanner ); int yyget_leng (yyscan_t yyscanner ); char *yyget_text (yyscan_t yyscanner ); int yyget_lineno (yyscan_t yyscanner ); void yyset_lineno (int line_number ,yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (yyscan_t yyscanner ); #else extern int yywrap (yyscan_t yyscanner ); #endif #endif static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner ); #else static int input (yyscan_t yyscanner ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (yyscan_t yyscanner); #define YY_DECL int yylex (yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; #line 47 "psp_parser.l" #line 755 "psp_parser.c" if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); } yy_load_buffer_state(yyscanner ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yyg->yy_start; yy_current_state += YY_AT_BOL(); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 73 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 90 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: /* rule 1 can match eol */ YY_RULE_SETUP #line 49 "psp_parser.l" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("req.write(\"\"\"")); yyless(0); BEGIN TEXT; } YY_BREAK case 2: YY_RULE_SETUP #line 56 "psp_parser.l" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("req.write(\"\"\"")); yyless(0); BEGIN TEXT; } YY_BREAK case 3: YY_RULE_SETUP #line 63 "psp_parser.l" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\\n")); } YY_BREAK case 4: YY_RULE_SETUP #line 67 "psp_parser.l" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\\r")); } YY_BREAK case 5: YY_RULE_SETUP #line 71 "psp_parser.l" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\\t")); } YY_BREAK case 6: YY_RULE_SETUP #line 75 "psp_parser.l" { /* expression */ psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\"\"\",0); req.write(str(")); PSP_PG(is_psp_echo) = 1; BEGIN PYCODE; } YY_BREAK case 7: YY_RULE_SETUP #line 82 "psp_parser.l" { /* python code */ psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\"\"\",0);")); CLEAR_WHITESPACE(&PSP_PG(whitespace)); PSP_PG(seen_newline) = 0; BEGIN PYCODE; } YY_BREAK case 8: YY_RULE_SETUP #line 89 "psp_parser.l" { /* directive */ BEGIN DIR; } YY_BREAK case 9: YY_RULE_SETUP #line 93 "psp_parser.l" { /* comment */ BEGIN COMMENT; } YY_BREAK case 10: /* rule 10 can match eol */ YY_RULE_SETUP #line 97 "psp_parser.l" { psp_string_appendc(&PSP_PG(pycode), '\n'); } YY_BREAK case 11: YY_RULE_SETUP #line 101 "psp_parser.l" { if (yytext[0] == '"') { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\"")); } else { psp_string_appendc(&PSP_PG(pycode), yytext[0]); } } YY_BREAK case YY_STATE_EOF(TEXT): #line 109 "psp_parser.l" { yypop_buffer_state(yyscanner); if (!YY_CURRENT_BUFFER) { /* this is really the end */ psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\"\"\",0)\n")); yyterminate(); } else { /* we are inside include, continue scanning */ BEGIN DIR; } } YY_BREAK case 12: /* rule 12 can match eol */ YY_RULE_SETUP #line 122 "psp_parser.l" { psp_string_appendc(&PSP_PG(pycode), '\n'); PSP_PG(seen_newline) = 1; BEGIN INDENT; } YY_BREAK case 13: YY_RULE_SETUP #line 129 "psp_parser.l" { if (PSP_PG(is_psp_echo)) { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("),0); req.write(\"\"\"")); PSP_PG(is_psp_echo) = 0; } else { if (!PSP_PG(seen_newline)) { /* this will happen is you have <%%> */ psp_string_appendc(&PSP_PG(pycode), ';'); } if (PSP_PG(after_colon)) { /* this is dumb mistake-proof measure, if %> is immediately following where there should be an indent */ psp_string_appendc(&PSP_PG(whitespace), '\t'); PSP_PG(after_colon) = 0; } OUTPUT_WHITESPACE(&PSP_PG(whitespace)); psp_string_appendl(&PSP_PG(pycode), STATIC_STR("req.write(\"\"\"")); } BEGIN TEXT; } YY_BREAK case 14: YY_RULE_SETUP #line 154 "psp_parser.l" { psp_string_appendc(&PSP_PG(pycode), yytext[0]); PSP_PG(after_colon) = 1; } YY_BREAK case 15: YY_RULE_SETUP #line 159 "psp_parser.l" { psp_string_appendc(&PSP_PG(pycode), yytext[0]); PSP_PG(after_colon) = 0; } YY_BREAK case 16: YY_RULE_SETUP #line 164 "psp_parser.l" { CLEAR_WHITESPACE(&PSP_PG(whitespace)); psp_string_appendl(&PSP_PG(whitespace), yytext, yyleng); psp_string_appendl(&PSP_PG(pycode), yytext, yyleng); BEGIN PYCODE; } YY_BREAK case 17: YY_RULE_SETUP #line 173 "psp_parser.l" { yyless(0); BEGIN PYCODE; } YY_BREAK case 18: /* rule 18 can match eol */ YY_RULE_SETUP #line 178 "psp_parser.l" { CLEAR_WHITESPACE(&PSP_PG(whitespace)); yyless(0); BEGIN PYCODE; } YY_BREAK case 19: YY_RULE_SETUP #line 184 "psp_parser.l" { CLEAR_WHITESPACE(&PSP_PG(whitespace)); yyless(0); BEGIN PYCODE; } YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP #line 190 "psp_parser.l" { char *filename; char *path; FILE *f; /* find a quote */ filename = strchr(yytext, '"') + 1; filename[strchr(filename, '"')-filename] = '\0'; /* XXX The absolute path check won't work on Windows, * needs to be corrected */ if (PSP_PG(dir) && filename[0] != '/') { path = malloc(strlen(filename)+strlen(PSP_PG(dir))+1); if (path == NULL) { PyErr_NoMemory(); yyterminate(); } strcpy(path, PSP_PG(dir)); strcat(path, filename); } else { path = filename; } Py_BEGIN_ALLOW_THREADS f = fopen(path, "rb"); Py_END_ALLOW_THREADS if (f == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, path); } else { yypush_buffer_state(yy_create_buffer(f,YY_BUF_SIZE,yyscanner),yyscanner); BEGIN(TEXT); } if (PSP_PG(dir)) free(path); } YY_BREAK case 21: YY_RULE_SETUP #line 232 "psp_parser.l" { BEGIN TEXT; } YY_BREAK case 22: YY_RULE_SETUP #line 236 "psp_parser.l" { BEGIN TEXT; } YY_BREAK case 23: YY_RULE_SETUP #line 240 "psp_parser.l" ECHO; YY_BREAK #line 1107 "psp_parser.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(PYCODE): case YY_STATE_EOF(INDENT): case YY_STATE_EOF(DIR): case YY_STATE_EOF(COMMENT): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yyg->yy_c_buf_p; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap(yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = yyg->yytext_ptr; register int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, (size_t) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ,yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { register yy_state_type yy_current_state; register char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; yy_current_state += YY_AT_BOL(); for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 73 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { register int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ register char *yy_cp = yyg->yy_c_buf_p; register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 73 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 72); return yy_is_jam ? 0 : yy_current_state; } static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) { register char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_cp = yyg->yy_c_buf_p; /* undo effects of setting up yytext */ *yy_cp = yyg->yy_hold_char; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = yyg->yy_n_chars + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; yyg->yytext_ptr = yy_bp; yyg->yy_hold_char = *yy_cp; yyg->yy_c_buf_p = yy_cp; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ,yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap(yyscanner ) ) return EOF; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); yy_load_buffer_state(yyscanner ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state(yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } static void yy_load_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ,yyscanner); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ,yyscanner ); yyfree((void *) b ,yyscanner ); } #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer(b ,yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state(yyscanner ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state(yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ void yypop_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state(yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (yyscan_t yyscanner) { int num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ,yyscanner ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) { return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ,yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ,yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ int yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /** Set the current line number. * @param line_number * @param yyscanner The scanner object. */ void yyset_lineno (int line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner); yylineno = line_number; } /** Set the current column. * @param line_number * @param yyscanner The scanner object. */ void yyset_column (int column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) yy_fatal_error( "yyset_column called with no buffer" , yyscanner); yycolumn = column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = in_str ; } void yyset_out (FILE * out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = bdebug ; } /* Accessor methods for yylval and yylloc */ /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = 0; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = (char *) 0; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack ,yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree(yyg->yy_start_stack ,yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size , yyscan_t yyscanner) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr , yyscan_t yyscanner) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 240 "psp_parser.l" /* this is for emacs Local Variables: mode:C End: */ mod_python-3.3.1/src/tableobject.c0000644000175000017500000007564410516147342015252 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * tableobject.c * * $Id: tableobject.c 466105 2006-10-20 13:28:02Z jgallacher $ * */ #include "mod_python.h" /** XXX this is a hack. because apr_table_t is not available in a header file */ #define TABLE_HASH_SIZE 32 struct apr_table_t { apr_array_header_t a; #ifdef MAKE_TABLE_PROFILE void *creator; #endif apr_uint32_t index_initialized; int index_first[TABLE_HASH_SIZE]; int index_last[TABLE_HASH_SIZE]; }; /** ** MpTable_FromTable ** * This routine creates a Python tableobject given an Apache * table pointer. * */ PyObject * MpTable_FromTable(apr_table_t *t) { tableobject *result; result = PyObject_New(tableobject, &MpTable_Type); if (! result) return PyErr_NoMemory(); result->table = t; result->pool = NULL; return (PyObject *)result; } /** ** MpTable_New ** * This returns a new object of built-in type table. * * NOTE: The ap_table gets greated in its own pool, which lives * throught the live of the tableobject. This is because this * object may persist from hit to hit. * * ALSO NOTE: table_new() also creates tables, independent of this * (it gets called when table is being subclassed) * */ PyObject * MpTable_New() { tableobject *t; apr_pool_t *p; /* XXX need second arg abort function to report mem error */ apr_pool_create_ex(&p, NULL, NULL, NULL); /* two is a wild guess */ t = (tableobject *)MpTable_FromTable(apr_table_make(p, 2)); /* remember the pointer to our own pool */ t->pool = p; return (PyObject *)t; } /** ** table_dealloc ** * Frees table's memory */ static void table_dealloc(register tableobject *self) { if (MpTable_Check(self)) { if (self->pool) apr_pool_destroy(self->pool); PyObject_Del(self); } else self->ob_type->tp_free((PyObject *)self); } /** ** table_print ** * prints table like a dictionary */ static int table_print(register tableobject *self, register FILE *fp, register int flags) { const apr_array_header_t *ah = NULL; apr_table_entry_t *elts; register int i; fprintf(fp, "{"); ah = apr_table_elts(self->table); elts = (apr_table_entry_t *) ah->elts; i = ah->nelts; if (i == 0) { fprintf(fp, "}"); return 0; } while (i--) if (elts[i].key) { fprintf(fp, "'%s': '%s'", elts[i].key, elts[i].val); if (i > 0) fprintf(fp, ", "); else fprintf(fp, "}"); } return 0; } /** ** table_repr ** * prints table like a dictionary */ static PyObject * table_repr(tableobject *self) { PyObject *s; PyObject *t = NULL; const apr_array_header_t *ah; apr_table_entry_t *elts; int i; s = PyString_FromString("{"); ah = apr_table_elts (self->table); elts = (apr_table_entry_t *) ah->elts; i = ah->nelts; if (i == 0) PyString_ConcatAndDel(&s, PyString_FromString("}")); while (i--) if (elts[i].key) { t = PyString_FromString(elts[i].key); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(": ")); if (elts[i].val) { t = PyString_FromString(elts[i].val); } else { t = Py_None; Py_INCREF(t); } PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); if (i > 0) PyString_ConcatAndDel(&s, PyString_FromString(", ")); else PyString_ConcatAndDel(&s, PyString_FromString("}")); } return s; } /** ** tablelength ** * Number of elements in a table. Called * when you do len(table) in Python. */ static int tablelength(tableobject *self) { return apr_table_elts(self->table)->nelts; } /** ** table_subscript ** * Gets a dictionary item */ static PyObject * table_subscript(tableobject *self, register PyObject *key) { char *k; const apr_array_header_t *ah; apr_table_entry_t *elts; register int i; PyObject *list; if (key && !PyString_CheckExact(key)) { PyErr_SetString(PyExc_TypeError, "table keys must be strings"); return NULL; } k = PyString_AsString(key); /* it's possible that we have duplicate keys, so we can't simply use apr_table_get since that just returns the first match. */ /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ list = PyList_New(0); if (!list) return NULL; ah = apr_table_elts (self->table); elts = (apr_table_entry_t *) ah->elts; i = ah->nelts; while (i--) if (elts[i].key) { if (apr_strnatcasecmp(elts[i].key, k) == 0) { PyObject *v = NULL; if (elts[i].val != NULL) { v = PyString_FromString(elts[i].val); } else { v = Py_None; Py_INCREF(v); } /* PYTHON 2.5: 'PyList_Insert' uses Py_ssize_t for input parameters */ PyList_Insert(list, 0, v); Py_DECREF(v); } } /* if no match */ /* PYTHON 2.5: 'PyList_Size' uses Py_ssize_t for return values (may need overflow check) */ if (PyList_Size(list) == 0) { Py_DECREF(list); PyErr_SetObject(PyExc_KeyError, key); return NULL; } /* if we got one match */ /* PYTHON 2.5: 'PyList_Size' uses Py_ssize_t for return values (may need overflow check) */ if (PyList_Size(list) == 1) { /* PYTHON 2.5: 'PyList_GetItem' uses Py_ssize_t for input parameters */ PyObject *v = PyList_GetItem(list, 0); Py_INCREF(v); Py_DECREF(list); return v; } /* else we return a list */ return list; } /** ** table_ass_subscript ** * insert into table dictionary-style * *** NOTE *** * Since the underlying ap_table_set makes a *copy* of the string, * there is no need to increment the reference to the Python * string passed in. */ static int table_ass_subscript(tableobject *self, PyObject *key, PyObject *val) { char *k; if (key && !PyString_CheckExact(key)) { PyErr_SetString(PyExc_TypeError, "table keys must be strings"); return -1; } k = PyString_AsString(key); if (val == NULL) { apr_table_unset(self->table, k); } else { if (val && !PyString_CheckExact(val)) { PyErr_SetString(PyExc_TypeError, "table values must be strings"); return -1; } apr_table_set(self->table, k, PyString_AsString(val)); } return 0; } /* table as mapping */ static PyMappingMethods table_as_mapping = { /* PYTHON 2.5: 'inquiry' should be perhaps replaced with 'lenfunc' */ (inquiry) tablelength, /*mp_length*/ (binaryfunc) table_subscript, /*mp_subscript*/ (objobjargproc) table_ass_subscript, /*mp_ass_subscript*/ }; /** ** table_keys ** * * Implements dictionary's keys() method. */ static PyObject * table_keys(register tableobject *self) { PyObject *v; const apr_array_header_t *ah; apr_table_entry_t *elts; int i, j; ah = apr_table_elts(self->table); elts = (apr_table_entry_t *) ah->elts; /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ v = PyList_New(ah->nelts); for (i = 0, j = 0; i < ah->nelts; i++) { if (elts[i].key) { PyObject *key = PyString_FromString(elts[i].key); /* PYTHON 2.5: 'PyList_SetItem' uses Py_ssize_t for input parameters */ PyList_SetItem(v, j, key); j++; } } return v; } /** ** table_values ** * * Implements dictionary's values() method. */ static PyObject * table_values(register tableobject *self) { PyObject *v; const apr_array_header_t *ah; apr_table_entry_t *elts; int i, j; ah = apr_table_elts(self->table); elts = (apr_table_entry_t *) ah->elts; /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ v = PyList_New(ah->nelts); for (i = 0, j = 0; i < ah->nelts; i++) { if (elts[i].key) { PyObject *val = NULL; if (elts[i].val != NULL) { val = PyString_FromString(elts[i].val); } else { val = Py_None; Py_INCREF(val); } /* PYTHON 2.5: 'PyList_SetItem' uses Py_ssize_t for input parameters */ PyList_SetItem(v, j, val); j++; } } return v; } /** ** table_items ** * * Implements dictionary's items() method. */ static PyObject * table_items(register tableobject *self) { PyObject *v; const apr_array_header_t *ah; apr_table_entry_t *elts; int i, j; ah = apr_table_elts(self->table); elts = (apr_table_entry_t *) ah->elts; /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ v = PyList_New(ah->nelts); for (i = 0, j = 0; i < ah->nelts; i++) { if (elts[i].key) { PyObject *keyval = Py_BuildValue("(s,s)", elts[i].key, elts[i].val); /* PYTHON 2.5: 'PyList_SetItem' uses Py_ssize_t for input parameters */ PyList_SetItem(v, j, keyval); j++; } } return v; } /** ** table_merge ** * Since tables can only store strings, key/vals from * mapping object b will be str()ingized. */ static int table_merge(tableobject *a, PyObject *b, int override) { /* Do it the generic, slower way */ PyObject *keys = PyMapping_Keys(b); PyObject *iter; PyObject *key, *value, *skey, *svalue; int status; if (keys == NULL) return -1; iter = PyObject_GetIter(keys); Py_DECREF(keys); if (iter == NULL) return -1; for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) { skey = PyObject_Str(key); if (skey == NULL) { Py_DECREF(iter); Py_DECREF(key); return -1; } if (!override && apr_table_get(a->table, PyString_AsString(skey)) != NULL) { Py_DECREF(key); Py_DECREF(skey); continue; } value = PyObject_GetItem(b, key); if (value == NULL) { Py_DECREF(iter); Py_DECREF(key); Py_DECREF(skey); return -1; } svalue = PyObject_Str(value); if (svalue == NULL) { Py_DECREF(iter); Py_DECREF(key); Py_DECREF(skey); Py_DECREF(value); return -1; } status = table_ass_subscript(a, skey, svalue); Py_DECREF(key); Py_DECREF(value); Py_DECREF(skey); Py_DECREF(svalue); if (status < 0) { Py_DECREF(iter); return -1; } } Py_DECREF(iter); if (PyErr_Occurred()) /* Iterator completed, via error */ return -1; return 0; } /** ** table_update ** */ static PyObject *table_update(tableobject *self, PyObject *other) { if (table_merge(self, other, 1) < 0) return NULL; Py_INCREF(Py_None); return Py_None; } /** ** table_mergefromseq2 ** * Similar to PyDict_MergeFromSeq2 (code borrowed from there). */ static int table_mergefromseq2(tableobject *self, PyObject *seq2, int override) { PyObject *it; /* iter(seq2) */ int i; /* index into seq2 of current element */ PyObject *item; /* seq2[i] */ PyObject *fast; /* item as a 2-tuple or 2-list */ it = PyObject_GetIter(seq2); if (it == NULL) return -1; for (i = 0; ; ++i) { PyObject *key, *value, *skey, *svalue; int n; fast = NULL; item = PyIter_Next(it); if (item == NULL) { if (PyErr_Occurred()) goto Fail; break; } /* Convert item to sequence, and verify length 2. */ fast = PySequence_Fast(item, ""); if (fast == NULL) { if (PyErr_ExceptionMatches(PyExc_TypeError)) PyErr_Format(PyExc_TypeError, "cannot convert table update " "sequence element #%d to a sequence", i); goto Fail; } n = PySequence_Fast_GET_SIZE(fast); if (n != 2) { PyErr_Format(PyExc_ValueError, "table update sequence element #%d " "has length %d; 2 is required", i, n); goto Fail; } /* Update/merge with this (key, value) pair. */ key = PySequence_Fast_GET_ITEM(fast, 0); value = PySequence_Fast_GET_ITEM(fast, 1); skey = PyObject_Str(key); if (skey == NULL) goto Fail; svalue = PyObject_Str(value); if (svalue == NULL) { Py_DECREF(svalue); goto Fail; } if (override || apr_table_get(self->table, PyString_AsString(skey)) == NULL) { int status = table_ass_subscript(self, skey, svalue); if (status < 0) { Py_DECREF(skey); Py_DECREF(svalue); goto Fail; } } Py_DECREF(skey); Py_DECREF(svalue); Py_DECREF(fast); Py_DECREF(item); } i = 0; goto Return; Fail: Py_XDECREF(item); Py_XDECREF(fast); i = -1; Return: Py_DECREF(it); return i; } /** ** table_copy ** */ static PyObject *table_copy(register tableobject *from) { tableobject *to = (tableobject *)MpTable_New(); if (to != NULL) apr_table_overlap(to->table, from->table, 0); return (PyObject*)to; } /** ** table_compare ** */ static int table_compare(tableobject *a, tableobject *b) { /* we're so lazy that we just copy tables to dicts and rely on dict's compare ability. this is not the best way to do this to say the least */ PyObject *ad, *bd; int result; ad = PyDict_New(); bd = PyDict_New(); PyDict_Merge(ad, (PyObject*)a, 0); PyDict_Merge(bd, (PyObject*)b, 0); result = PyObject_Compare(ad, bd); Py_DECREF(ad); Py_DECREF(bd); return result; } /** ** table_richcompare ** */ static PyObject *table_richcompare(PyObject *v, PyObject *w, int op) { Py_INCREF(Py_NotImplemented); /* XXX */ return Py_NotImplemented; } /** ** table_has_key ** */ static PyObject * table_has_key(tableobject *self, PyObject *key) { const char *val; if (!PyString_CheckExact(key)) { PyErr_SetString(PyExc_TypeError, "table keys must be strings"); return NULL; } val = apr_table_get(self->table, PyString_AsString(key)); if (val) return PyInt_FromLong(1); else return PyInt_FromLong(0); } /** ** table_get ** * implements get([failobj]) method */ static PyObject *table_get(register tableobject *self, PyObject *args) { PyObject *key; PyObject *failobj = Py_None; PyObject *val = NULL; const char *sval; if (!PyArg_ParseTuple(args, "S|O:get", &key, &failobj)) return NULL; sval = apr_table_get(self->table, PyString_AsString(key)); if (sval == NULL) { val = failobj; Py_INCREF(val); } else val = PyString_FromString(sval); return val; } /** ** table_setdefault ** * implements setdefault(key, [val]) method */ static PyObject *table_setdefault(register tableobject *self, PyObject *args) { PyObject *key; PyObject *failobj = NULL; PyObject *val = NULL; char *k = NULL; const char *v = NULL; if (!PyArg_ParseTuple(args, "O|O:setdefault", &key, &failobj)) return NULL; if (!PyString_CheckExact(key)) { PyErr_SetString(PyExc_TypeError, "table keys must be strings"); return NULL; } if (failobj && !PyString_CheckExact(failobj)) { PyErr_SetString(PyExc_TypeError, "table values must be strings"); return NULL; } k = PyString_AsString(key); v = apr_table_get(self->table, k); if (v == NULL) { if (failobj == NULL) { apr_table_set(self->table, k, ""); val = PyString_FromString(""); } else { apr_table_set(self->table, k, PyString_AsString(failobj)); val = failobj; Py_XINCREF(val); } } else val = PyString_FromString(v); return val; } /** ** table_clear ** */ static PyObject *table_clear(register tableobject *self) { apr_table_clear(self->table); Py_INCREF(Py_None); return Py_None; } /** ** table_popitem ** */ static PyObject *table_popitem(tableobject *self) { apr_array_header_t *ah; apr_table_entry_t *elts; PyObject *res; ah = (apr_array_header_t *) apr_table_elts(self->table); elts = (apr_table_entry_t *) ah->elts; if (ah->nelts == 0) { PyErr_SetString(PyExc_KeyError, "popitem(): table is empty"); return NULL; } res = Py_BuildValue("(s,s)", elts[0].key, elts[0].val); ah->nelts--; elts++; return res; } /** ** table_traverse ** */ static int table_traverse(tableobject *self, visitproc visit, void *arg) { const apr_array_header_t *ah; apr_table_entry_t *elts; register int i; ah = apr_table_elts (self->table); elts = (apr_table_entry_t *) ah->elts; i = ah->nelts; while (i--) if (elts[i].key) { int err; PyObject *v = NULL; if (elts[i].val != NULL) { v = PyString_FromString(elts[i].val); } else { v = Py_None; Py_INCREF(v); } err = visit(v, arg); Py_XDECREF(v); if (err) return err; } return 0; } /** ** table_tp_clear ** */ static int table_tp_clear(tableobject *self) { table_clear(self); return 0; } /** ** mp_table_add ** * this function is equivalent of ap_table_add - * it can create duplicate entries. */ static PyObject * mp_table_add(tableobject *self, PyObject *args) { const char *val, *key; if (! PyArg_ParseTuple(args, "ss", &key, &val)) return NULL; apr_table_add(self->table, key, val); Py_INCREF(Py_None); return Py_None; } typedef PyObject * (*tableselectfunc)(apr_table_entry_t *); staticforward PyObject *tableiter_new(tableobject *, tableselectfunc); static PyObject *select_key(apr_table_entry_t *elts) { return PyString_FromString(elts->key); } static PyObject *select_value(apr_table_entry_t *elts) { PyObject *val = NULL; if (elts->val != NULL) { val = PyString_FromString(elts->val); } else { val = Py_None; Py_INCREF(val); } return val; } static PyObject *select_item(apr_table_entry_t *elts) { return Py_BuildValue("(s,s)", elts->key, elts->val); } static PyObject *table_iterkeys(tableobject *self) { return tableiter_new(self, select_key); } static PyObject *table_itervalues(tableobject *self) { return tableiter_new(self, select_value); } static PyObject *table_iteritems(tableobject *self) { return tableiter_new(self, select_item); } static char has_key__doc__[] = "T.has_key(k) -> 1 if T has a key k, else 0"; static char get__doc__[] = "T.get(k[,d]) -> T[k] if T.has_key(k), else d. d defaults to None."; static char setdefault_doc__[] = "T.setdefault(k[,d]) -> T.get(k,d), also set T[k]=d if not T.has_key(k)"; static char popitem__doc__[] = "T.popitem() -> (k, v), remove and return some (key, value) pair as a\n\ 2-tuple; but raise KeyError if T is empty"; static char keys__doc__[] = "T.keys() -> list of T's keys"; static char items__doc__[] = "T.items() -> list of T's (key, value) pairs, as 2-tuples"; static char values__doc__[] = "T.values() -> list of T's values"; static char update__doc__[] = "T.update(E) -> None. Update T from E: for k in E.keys(): T[k] = E[k]"; static char clear__doc__[] = "T.clear() -> None. Remove all items from T."; static char copy__doc__[] = "T.copy() -> a shallow copy of T"; static char iterkeys__doc__[] = "T.iterkeys() -> an iterator over the keys of T"; static char itervalues__doc__[] = "T.itervalues() -> an iterator over the values of T"; static char iteritems__doc__[] = "T.iteritems() -> an iterator over the (key, value) items of T"; static char add__doc__[] = "T.add(k, v) -> add (as oppsed to replace) a key k and value v"; /* table method definitions */ static PyMethodDef mp_table_methods[] = { {"has_key", (PyCFunction)table_has_key, METH_O, has_key__doc__}, {"get", (PyCFunction)table_get, METH_VARARGS, get__doc__}, {"setdefault", (PyCFunction)table_setdefault, METH_VARARGS, setdefault_doc__}, {"popitem", (PyCFunction)table_popitem, METH_NOARGS, popitem__doc__}, {"keys", (PyCFunction)table_keys, METH_NOARGS, keys__doc__}, {"items", (PyCFunction)table_items, METH_NOARGS, items__doc__}, {"values", (PyCFunction)table_values, METH_NOARGS, values__doc__}, {"update", (PyCFunction)table_update, METH_O, update__doc__}, {"clear", (PyCFunction)table_clear, METH_NOARGS, clear__doc__}, {"copy", (PyCFunction)table_copy, METH_NOARGS, copy__doc__}, {"iterkeys", (PyCFunction)table_iterkeys, METH_NOARGS, iterkeys__doc__}, {"itervalues", (PyCFunction)table_itervalues, METH_NOARGS, itervalues__doc__}, {"iteritems", (PyCFunction)table_iteritems, METH_NOARGS, iteritems__doc__}, {"add", (PyCFunction)mp_table_add, METH_VARARGS, add__doc__}, {NULL, NULL} /* sentinel */ }; static int table_contains(tableobject *self, PyObject *key) { return apr_table_get(self->table, PyString_AsString(key)) != NULL; } /* Hack to implement "key in table" */ static PySequenceMethods table_as_sequence = { 0, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ 0, /* sq_item */ 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ (objobjproc)table_contains, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }; /** ** table_new ** */ static PyObject *table_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { return MpTable_New(); } static int table_init(tableobject *self, PyObject *args, PyObject *kwds) { PyObject *arg = NULL; static char *kwlist[] = {"items", 0}; int result = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:mp_table", kwlist, &arg)) result = -1; else if (arg != NULL) { if (PyObject_HasAttrString(arg, "keys")) result = table_merge(self, arg, 1); else result = table_mergefromseq2(self, arg, 1); } return result; } static long table_nohash(PyObject *self) { PyErr_SetString(PyExc_TypeError, "mp_table objects are unhashable"); return -1; } static PyObject *table_iter(tableobject *self) { return tableiter_new(self, select_key); } static char mp_table_doc[] = "table() -> new empty table.\n" "table(mapping) -> new table initialized from a mapping object's\n" " (key, value) pairs.\n" "table(seq) -> new table initialized as if via:\n" " d = {}\n" " for k, v in seq:\n" " d[k] = v"; PyTypeObject MpTable_Type = { PyObject_HEAD_INIT(NULL) 0, "mp_table", sizeof(tableobject), 0, (destructor)table_dealloc, /* tp_dealloc */ (printfunc)table_print, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ (cmpfunc)table_compare, /* tp_compare */ (reprfunc)table_repr, /* tp_repr */ 0, /* tp_as_number */ &table_as_sequence, /* tp_as_sequence */ &table_as_mapping, /* tp_as_mapping */ table_nohash, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ mp_table_doc, /* tp_doc */ (traverseproc)table_traverse, /* tp_traverse */ /* PYTHON 2.5: 'inquiry' should be perhaps replaced with 'lenfunc' */ (inquiry)table_tp_clear, /* tp_clear */ table_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)table_iter, /* tp_iter */ 0, /* tp_iternext */ mp_table_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)table_init, /* tp_init */ 0, /* tp_alloc */ table_new, /* tp_new */ (destructor)table_dealloc, /* tp_free */ }; /* Table iterator type */ extern PyTypeObject MpTableIter_Type; /* Forward */ typedef struct { PyObject_HEAD tableobject *table; int ti_nelts; int ti_pos; tableselectfunc ti_select; } tableiterobject; static PyObject *tableiter_new(tableobject *table, tableselectfunc select) { tableiterobject *ti; ti = PyObject_NEW(tableiterobject, &MpTableIter_Type); if (ti == NULL) return NULL; Py_INCREF(table); ti->table = table; ti->ti_nelts = table->table->a.nelts; ti->ti_pos = 0; ti->ti_select = select; return (PyObject *)ti; } static void tableiter_dealloc(tableiterobject *ti) { Py_DECREF(ti->table); PyObject_DEL(ti); } static PyObject *tableiter_next(tableiterobject *ti, PyObject *args) { apr_table_entry_t *elts = (apr_table_entry_t *) ti->table->table->a.elts; /* make sure the table hasn't change while being iterated */ if (ti->ti_nelts != ti->table->table->a.nelts) { PyErr_SetString(PyExc_RuntimeError, "table changed size during iteration"); return NULL; } /* return the next key/val */ if (ti->ti_pos < ti->table->table->a.nelts) { return (*ti->ti_select)(&elts[ti->ti_pos++]); } /* the end has been reached */ PyErr_SetObject(PyExc_StopIteration, Py_None); return NULL; } static PyObject *tableiter_getiter(PyObject *it) { Py_INCREF(it); return it; } static PyMethodDef tableiter_methods[] = { {"next", (PyCFunction)tableiter_next, METH_VARARGS, "it.next() -- get the next value, or raise StopIteration"}, {NULL, NULL} /* sentinel */ }; static PyObject *tableiter_iternext(tableiterobject *ti) { apr_table_entry_t *elts = (apr_table_entry_t *) ti->table->table->a.elts; /* make sure the table hasn't change while being iterated */ if (ti->ti_nelts != ti->table->table->a.nelts) { PyErr_SetString(PyExc_RuntimeError, "table changed size during iteration"); return NULL; } /* return the next key/val */ if (ti->ti_pos < ti->table->table->a.nelts) { return (*ti->ti_select)(&elts[ti->ti_pos++]); } /* the end has been reached */ PyErr_SetObject(PyExc_StopIteration, Py_None); return NULL; } PyTypeObject MpTableIter_Type = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "dictionary-iterator", /* tp_name */ sizeof(tableiterobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)tableiter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)tableiter_getiter, /* tp_iter */ (iternextfunc)tableiter_iternext, /* tp_iternext */ tableiter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ }; mod_python-3.3.1/src/requestobject.c0000644000175000017500000020316410534452125015637 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * requestobject.c * * $Id: requestobject.c 481717 2006-12-03 04:36:37Z grahamd $ * */ #include "mod_python.h" /* mod_ssl.h is not safe for inclusion in 2.0, so duplicate the * optional function declarations. */ APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup, (apr_pool_t *, server_rec *, conn_rec *, request_rec *, char *)); APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); /* Optional functions imported from mod_ssl when loaded: */ static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *optfn_ssl_var_lookup = NULL; static APR_OPTIONAL_FN_TYPE(ssl_is_https) *optfn_is_https = NULL; /** ** MpRequest_FromRequest ** * This routine creates a Python requestobject given an Apache * request_rec pointer. * */ PyObject * MpRequest_FromRequest(request_rec *req) { requestobject *result; result = PyObject_GC_New(requestobject, &MpRequest_Type); if (! result) return PyErr_NoMemory(); result->dict = PyDict_New(); if (!result->dict) return PyErr_NoMemory(); result->request_rec = req; result->connection = NULL; result->server = NULL; result->headers_in = MpTable_FromTable(req->headers_in); result->headers_out = MpTable_FromTable(req->headers_out); result->err_headers_out = MpTable_FromTable(req->err_headers_out); result->subprocess_env = MpTable_FromTable(req->subprocess_env); result->notes = MpTable_FromTable(req->notes); result->phase = NULL; result->extension = NULL; result->content_type_set = 0; result->bytes_queued = 0; result->hlo = NULL; /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ result->callbacks = PyList_New(0); if (!result->callbacks) return PyErr_NoMemory(); result->rbuff = NULL; result->rbuff_pos = 0; result->rbuff_len = 0; /* we make sure that the object dictionary is there * before registering the object with the GC */ PyObject_GC_Track(result); return (PyObject *) result; } /* Methods */ /** ** request.add_common_vars(reqeust self) ** * Interface to ap_add_common_vars. Adds a bunch of CGI * environment variables. * */ static PyObject * req_add_common_vars(requestobject *self) { ap_add_common_vars(self->request_rec); Py_INCREF(Py_None); return Py_None; } /** ** valid_phase() ** * utility func - makes sure a phase is valid */ static int valid_phase(const char *p) { if ((strcmp(p, "PythonHandler") != 0) && (strcmp(p, "PythonAuthenHandler") != 0) && (strcmp(p, "PythonPostReadRequestHandler") != 0) && (strcmp(p, "PythonTransHandler") != 0) && (strcmp(p, "PythonHeaderParserHandler") != 0) && (strcmp(p, "PythonAccessHandler") != 0) && (strcmp(p, "PythonAuthzHandler") != 0) && (strcmp(p, "PythonTypeHandler") != 0) && (strcmp(p, "PythonFixupHandler") != 0) && (strcmp(p, "PythonLogHandler") != 0) && (strcmp(p, "PythonInitHandler") != 0)) return 0; else return 1; } /** ** request.add_handler(request self, string phase, string handler) ** * Allows to add another handler to the handler list. */ static PyObject *req_add_handler(requestobject *self, PyObject *args) { char *phase = NULL; char *handler = NULL; PyObject *callable = NULL; const char *dir = NULL; const char *currphase; if (! PyArg_ParseTuple(args, "ss|z", &phase, &handler, &dir)) { PyErr_Clear(); if (! PyArg_ParseTuple(args, "sO|z", &phase, &callable, &dir)) { PyErr_SetString(PyExc_ValueError, "handler must be a string or callable object"); return NULL; } } if (! valid_phase(phase)) { PyErr_SetString(PyExc_IndexError, apr_psprintf(self->request_rec->pool, "Invalid phase: %s", phase)); return NULL; } if (callable) { if (!PyCallable_Check(callable)) { PyErr_SetString(PyExc_ValueError, "handler must be a string or callable object"); return NULL; } else { /* Cache reference in list of callable handler objects * so that they can be dereferenced when request object * destroyed at end of phase. */ if (PyList_Append(self->callbacks, callable) == -1) return NULL; } } /* Canonicalize path and add trailing slash at * this point if directory was provided. */ if (dir) { char *newpath = 0; apr_status_t rv; rv = apr_filepath_merge(&newpath, NULL, dir, APR_FILEPATH_TRUENAME, self->request_rec->pool); /* If there is a failure, use the original path * which was supplied. */ if (rv == APR_SUCCESS || rv == APR_EPATHWILD) { dir = newpath; if (dir[strlen(dir) - 1] != '/') { dir = apr_pstrcat(self->request_rec->pool, dir, "/", NULL); } } else { /* dir is from Python, so duplicate it */ dir = apr_pstrdup(self->request_rec->pool, dir); } } /* handler is from Python, so duplicate it */ handler = apr_pstrdup(self->request_rec->pool, handler); /* which phase are we processing? */ currphase = PyString_AsString(self->phase); /* are we in same phase as what's being added? */ if (strcmp(currphase, phase) == 0) { /* then just append to hlist */ hlist_append(self->request_rec->pool, self->hlo->head, handler, callable, dir, 0, NULL, NULL, 0, NULL, NOTSILENT, self->hlo->head); } else { /* this is a phase that we're not in */ py_req_config *req_config; hl_entry *hle; /* get request config */ req_config = (py_req_config *) ap_get_module_config(self->request_rec->request_config, &python_module); hle = apr_hash_get(req_config->dynhls, phase, APR_HASH_KEY_STRING); if (! hle) { hle = hlist_new(self->request_rec->pool, handler, callable, dir, 0, NULL, NULL, 0, NULL, NOTSILENT, self->hlo->head); apr_hash_set(req_config->dynhls, phase, APR_HASH_KEY_STRING, hle); } else { hlist_append(self->request_rec->pool, hle, handler, callable, dir, 0, NULL, NULL, 0, NULL, NOTSILENT, self->hlo->head); } } Py_INCREF(Py_None); return Py_None; } /** ** request.add_input_filter(request self, string name) ** * Specifies that a pre registered filter be added to input filter chain. */ static PyObject *req_add_input_filter(requestobject *self, PyObject *args) { char *name; py_req_config *req_config; python_filter_ctx *ctx; if (! PyArg_ParseTuple(args, "s", &name)) return NULL; req_config = (py_req_config *) ap_get_module_config( self->request_rec->request_config, &python_module); if (apr_hash_get(req_config->in_filters, name, APR_HASH_KEY_STRING)) { ctx = (python_filter_ctx *) apr_pcalloc(self->request_rec->pool, sizeof(python_filter_ctx)); ctx->name = apr_pstrdup(self->request_rec->pool, name); ap_add_input_filter(FILTER_NAME, ctx, self->request_rec, self->request_rec->connection); } else { ap_add_input_filter(name, NULL, self->request_rec, self->request_rec->connection); } Py_INCREF(Py_None); return Py_None; } /** ** request.add_output_filter(request self, string name) ** * Specifies that a pre registered filter be added to output filter chain. */ static PyObject *req_add_output_filter(requestobject *self, PyObject *args) { char *name; py_req_config *req_config; python_filter_ctx *ctx; if (! PyArg_ParseTuple(args, "s", &name)) return NULL; req_config = (py_req_config *) ap_get_module_config( self->request_rec->request_config, &python_module); if (apr_hash_get(req_config->out_filters, name, APR_HASH_KEY_STRING)) { ctx = (python_filter_ctx *) apr_pcalloc(self->request_rec->pool, sizeof(python_filter_ctx)); ctx->name = apr_pstrdup(self->request_rec->pool, name); ap_add_output_filter(FILTER_NAME, ctx, self->request_rec, self->request_rec->connection); } else { ap_add_output_filter(name, NULL, self->request_rec, self->request_rec->connection); } Py_INCREF(Py_None); return Py_None; } /** ** request.register_input_filter(request self, string name, string handler, list dir) ** * Registers an input filter active for life of the request. */ static PyObject *req_register_input_filter(requestobject *self, PyObject *args) { char *name = NULL; char *handler = NULL; PyObject *callable = NULL; char *dir = NULL; py_req_config *req_config; py_handler *fh; if (! PyArg_ParseTuple(args, "ss|s", &name, &handler, &dir)) { PyErr_Clear(); if (! PyArg_ParseTuple(args, "sO|s", &name, &callable, &dir)) { PyErr_SetString(PyExc_ValueError, "handler must be a string or callable object"); return NULL; } } if (callable) { /* Cache reference in list of callable filter objects * so that they can be dereferenced when request object * destroyed at end of phase. */ if (PyList_Append(self->callbacks, callable) == -1) return NULL; } req_config = (py_req_config *) ap_get_module_config( self->request_rec->request_config, &python_module); fh = (py_handler *) apr_pcalloc(self->request_rec->pool, sizeof(py_handler)); fh->handler = apr_pstrdup(self->request_rec->pool, handler); fh->callable = callable; fh->parent = self->hlo->head; /* Canonicalize path and add trailing slash at * this point if directory was provided. */ if (dir) { char *newpath = 0; apr_status_t rv; rv = apr_filepath_merge(&newpath, NULL, dir, APR_FILEPATH_TRUENAME, self->request_rec->pool); /* If there is a failure, use the original path * which was supplied. */ if (rv == APR_SUCCESS || rv == APR_EPATHWILD) { dir = newpath; if (dir[strlen(dir) - 1] != '/') { dir = apr_pstrcat(self->request_rec->pool, dir, "/", NULL); } fh->directory = dir; } else { fh->directory = apr_pstrdup(self->request_rec->pool, dir); } } apr_hash_set(req_config->in_filters, apr_pstrdup(self->request_rec->pool, name), APR_HASH_KEY_STRING, fh); Py_INCREF(Py_None); return Py_None; } /** ** request.register_output_filter(request self, string name, string handler, list dir) ** * Registers an output filter active for life of the request. */ static PyObject *req_register_output_filter(requestobject *self, PyObject *args) { char *name = NULL; char *handler = NULL; PyObject *callable = NULL; char *dir = NULL; py_req_config *req_config; py_handler *fh; if (! PyArg_ParseTuple(args, "ss|s", &name, &handler, &dir)) { PyErr_Clear(); if (! PyArg_ParseTuple(args, "sO|s", &name, &callable, &dir)) { PyErr_SetString(PyExc_ValueError, "handler must be a string or callable object"); return NULL; } } if (callable) { /* Cache reference in list of callable filter objects * so that they can be dereferenced when request object * destroyed at end of phase. */ if (PyList_Append(self->callbacks, callable) == -1) return NULL; } req_config = (py_req_config *) ap_get_module_config( self->request_rec->request_config, &python_module); fh = (py_handler *) apr_pcalloc(self->request_rec->pool, sizeof(py_handler)); fh->handler = apr_pstrdup(self->request_rec->pool, handler); fh->callable = callable; fh->parent = self->hlo->head; /* Canonicalize path and add trailing slash at * this point if directory was provided. */ if (dir) { char *newpath = 0; apr_status_t rv; rv = apr_filepath_merge(&newpath, NULL, dir, APR_FILEPATH_TRUENAME, self->request_rec->pool); /* If there is a failure, use the original path * which was supplied. */ if (rv == APR_SUCCESS || rv == APR_EPATHWILD) { dir = newpath; if (dir[strlen(dir) - 1] != '/') { dir = apr_pstrcat(self->request_rec->pool, dir, "/", NULL); } fh->directory = dir; } else { fh->directory = apr_pstrdup(self->request_rec->pool, dir); } } apr_hash_set(req_config->out_filters, apr_pstrdup(self->request_rec->pool, name), APR_HASH_KEY_STRING, fh); Py_INCREF(Py_None); return Py_None; } /** ** request.allow_methods(request self, list methods, reset=0) ** * a wrapper around ap_allow_methods. (used for the "allow:" header * to be passed to client when needed.) */ static PyObject *req_allow_methods(requestobject *self, PyObject *args) { PyObject *methods; int reset = 0; int len, i; if (! PyArg_ParseTuple(args, "O|i", &methods, &reset)) return NULL; if (! PySequence_Check(methods)){ PyErr_SetString(PyExc_TypeError, "First argument must be a sequence"); return NULL; } /* PYTHON 2.5: 'PySequence_Length' uses Py_ssize_t for input parameters */ len = PySequence_Length(methods); if (len) { PyObject *method; /* PYTHON 2.5: 'PySequence_GetItem' uses Py_ssize_t for input parameters */ method = PySequence_GetItem(methods, 0); if (! PyString_Check(method)) { PyErr_SetString(PyExc_TypeError, "Methods must be strings"); return NULL; } ap_allow_methods(self->request_rec, (reset == REPLACE_ALLOW), PyString_AS_STRING(method), NULL); for (i = 1; i < len; i++) { /* PYTHON 2.5: 'PySequence_GetItem' uses Py_ssize_t for input parameters */ method = PySequence_GetItem(methods, i); if (! PyString_Check(method)) { PyErr_SetString(PyExc_TypeError, "Methods must be strings"); return NULL; } ap_allow_methods(self->request_rec, MERGE_ALLOW, PyString_AS_STRING(method), NULL); } } Py_INCREF(Py_None); return Py_None; } /** ** request.is_https(self) ** * mod_ssl ssl_is_https() wrapper */ static PyObject * req_is_https(requestobject *self) { int is_https; if (!optfn_is_https) optfn_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); is_https = optfn_is_https && optfn_is_https(self->request_rec->connection); return PyInt_FromLong(is_https); } /** ** request.ssl_var_lookup(self, string variable_name) ** * mod_ssl ssl_var_lookup() wrapper */ static PyObject * req_ssl_var_lookup(requestobject *self, PyObject *args) { char *var_name; if (! PyArg_ParseTuple(args, "s", &var_name)) return NULL; /* error */ if (!optfn_ssl_var_lookup) optfn_ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); if (optfn_ssl_var_lookup) { const char *val; val = optfn_ssl_var_lookup(self->request_rec->pool, self->request_rec->server, self->request_rec->connection, self->request_rec, var_name); if (val) return PyString_FromString(val); } /* variable not found, or mod_ssl is not loaded */ Py_INCREF(Py_None); return Py_None; } /** ** request.document_root(self) ** * ap_docuement_root wrapper */ static PyObject *req_document_root(requestobject *self) { return PyString_FromString(ap_document_root(self->request_rec)); } /** ** request.get_basic_auth_pw(request self) ** * get basic authentication password, * similar to ap_get_basic_auth_pw */ static PyObject * req_get_basic_auth_pw(requestobject *self, PyObject *args) { const char *pw; request_rec *req; req = self->request_rec; if (! ap_get_basic_auth_pw(req, &pw)) return PyString_FromString(pw); else { Py_INCREF(Py_None); return Py_None; } } /** ** request.auth_name(self) ** * ap_auth_name wrapper */ static PyObject *req_auth_name(requestobject *self) { const char *auth_name = ap_auth_name(self->request_rec); if (!auth_name) { Py_INCREF(Py_None); return Py_None; } return PyString_FromString(auth_name); } /** ** request.auth_type(self) ** * ap_auth_type wrapper */ static PyObject *req_auth_type(requestobject *self) { const char *auth_type = ap_auth_type(self->request_rec); if (!auth_type) { Py_INCREF(Py_None); return Py_None; } return PyString_FromString(auth_type); } /** ** request.construct_url(self) ** * ap_construct_url wrapper */ static PyObject *req_construct_url(requestobject *self, PyObject *args) { char *uri; if (! PyArg_ParseTuple(args, "s", &uri)) return NULL; return PyString_FromString(ap_construct_url(self->request_rec->pool, uri, self->request_rec)); } /** ** request.discard_request_body(request self) ** * discard content supplied with request */ static PyObject * req_discard_request_body(requestobject *self) { return PyInt_FromLong(ap_discard_request_body(self->request_rec)); } /** ** request.get_addhandler_exts(request self) ** * Returns file extentions that were given as argument to AddHandler mod_mime * directive, if any, if at all. This is useful for the Publisher, which can * chop off file extentions for modules based on this info. * * XXX Due to the way this is implemented, it is best stay undocumented. */ static PyObject * req_get_addhandler_exts(requestobject *self, PyObject *args) { char *exts = get_addhandler_extensions(self->request_rec); if (exts) return PyString_FromString(exts); else return PyString_FromString(""); } /** ** request.get_config(request self) ** * Returns the config directives set through Python* apache directives. * except for Python*Handler and PythonOption (which you get via get_options). */ static PyObject * req_get_config(requestobject *self) { py_config *conf = (py_config *) ap_get_module_config(self->request_rec->per_dir_config, &python_module); return MpTable_FromTable(conf->directives); } /** ** request.get_remodte_host(request self, [int type]) ** * An interface to the ap_get_remote_host function. */ static PyObject * req_get_remote_host(requestobject *self, PyObject *args) { int type = REMOTE_NAME; PyObject *str_is_ip = Py_None; int _str_is_ip; const char *host; if (! PyArg_ParseTuple(args, "|iO", &type, &str_is_ip)) return NULL; if (str_is_ip != Py_None) { host = ap_get_remote_host(self->request_rec->connection, self->request_rec->per_dir_config, type, &_str_is_ip); } else { host = ap_get_remote_host(self->request_rec->connection, self->request_rec->per_dir_config, type, NULL); } if (! host) { Py_INCREF(Py_None); return Py_None; } else { if (str_is_ip != Py_None) { return Py_BuildValue("(s,i)", host, _str_is_ip); } else { return PyString_FromString(host); } } } /** ** request.get_options(request self) ** */ static PyObject * req_get_options(requestobject *self, PyObject *args) { py_config *conf = (py_config *) ap_get_module_config(self->request_rec->per_dir_config, &python_module); apr_table_t* table = conf->options; int i; const apr_array_header_t* ah = apr_table_elts(table); apr_table_entry_t* elts = (apr_table_entry_t *) ah->elts; /* * We remove the empty values, since they cannot have been defined * by the directive. */ for(i=0;inelts;i++,elts++) { if(strlen(elts->val)==0) { apr_table_unset(table,elts->key); } } /* XXX shouldn't we free the apr_array_header_t* ah ? */ return MpTable_FromTable(table); } /** ** request.internal_redirect(request self, string newuri) ** */ static PyObject * req_internal_redirect(requestobject *self, PyObject *args) { char *new_uri; if (! PyArg_ParseTuple(args, "z", &new_uri)) return NULL; /* error */ Py_BEGIN_ALLOW_THREADS ap_internal_redirect(new_uri, self->request_rec); Py_END_ALLOW_THREADS Py_INCREF(Py_None); return Py_None; } /** ** request.log_error(req self, string message, int level) ** * calls ap_log_rerror */ static PyObject * req_log_error(requestobject *self, PyObject *args) { int level = 0; char *message = NULL; if (! PyArg_ParseTuple(args, "z|i", &message, &level)) return NULL; /* error */ if (message) { if (! level) level = APLOG_NOERRNO|APLOG_ERR; ap_log_rerror(APLOG_MARK, level, 0, self->request_rec, "%s", message); } Py_INCREF(Py_None); return Py_None; } /** ** request.meets_conditions(req self) ** * ap_meets_conditions wrapper */ static PyObject * req_meets_conditions(requestobject *self) { return PyInt_FromLong(ap_meets_conditions(self->request_rec)); } /** ** request.read(request self, int bytes) ** * Reads stuff like POST requests from the client * (based on the old net_read) */ static PyObject * req_read(requestobject *self, PyObject *args) { int rc, bytes_read, chunk_len; char *buffer; PyObject *result; int copied = 0; long len = -1; if (! PyArg_ParseTuple(args, "|l", &len)) return NULL; if (len == 0) { return PyString_FromString(""); } /* is this the first read? */ if (! self->request_rec->read_length) { /* then do some initial setting up */ rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR); if(rc != OK) { PyObject *val = PyInt_FromLong(rc); if (val == NULL) return NULL; PyErr_SetObject(get_ServerReturn(), val); Py_DECREF(val); return NULL; } if (! ap_should_client_block(self->request_rec)) { /* client has nothing to send */ return PyString_FromString(""); } } if (len < 0) /* XXX ok to use request_rec->remaining? */ len = self->request_rec->remaining + (self->rbuff_len - self->rbuff_pos); /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ result = PyString_FromStringAndSize(NULL, len); /* possibly no more memory */ if (result == NULL) return NULL; buffer = PyString_AS_STRING((PyStringObject *) result); /* if anything left in the readline buffer */ while ((self->rbuff_pos < self->rbuff_len) && (copied < len)) buffer[copied++] = self->rbuff[self->rbuff_pos++]; /* Free rbuff if we're done with it */ if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL) { free(self->rbuff); self->rbuff = NULL; } if (copied == len) return result; /* we're done! */ /* read it in */ Py_BEGIN_ALLOW_THREADS chunk_len = ap_get_client_block(self->request_rec, buffer, len); Py_END_ALLOW_THREADS bytes_read = chunk_len; /* if this is a "short read", try reading more */ while ((bytes_read < len) && (chunk_len != 0)) { Py_BEGIN_ALLOW_THREADS chunk_len = ap_get_client_block(self->request_rec, buffer+bytes_read, len-bytes_read); Py_END_ALLOW_THREADS if (chunk_len == -1) { PyErr_SetObject(PyExc_IOError, PyString_FromString("Client read error (Timeout?)")); return NULL; } else bytes_read += chunk_len; } /* resize if necessary */ if (bytes_read < len) /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ if(_PyString_Resize(&result, bytes_read)) return NULL; return result; } /** ** request.readline(request self, int maxbytes) ** * Reads stuff like POST requests from the client * (based on the old net_read) until EOL */ static PyObject * req_readline(requestobject *self, PyObject *args) { int rc, chunk_len, bytes_read; char *buffer; PyObject *result; int copied = 0; long len = -1; if (! PyArg_ParseTuple(args, "|l", &len)) return NULL; if (len == 0) { return PyString_FromString(""); } /* is this the first read? */ if (! self->request_rec->read_length) { /* then do some initial setting up */ rc = ap_setup_client_block(self->request_rec, REQUEST_CHUNKED_ERROR); if (rc != OK) { PyObject *val = PyInt_FromLong(rc); if (val == NULL) return NULL; PyErr_SetObject(get_ServerReturn(), val); Py_DECREF(val); return NULL; } if (! ap_should_client_block(self->request_rec)) { /* client has nothing to send */ return PyString_FromString(""); } } if (len < 0) len = self->request_rec->remaining + (self->rbuff_len - self->rbuff_pos); /* create the result buffer */ /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ result = PyString_FromStringAndSize(NULL, len); /* possibly no more memory */ if (result == NULL) return NULL; buffer = PyString_AS_STRING((PyStringObject *) result); /* is there anything left in the rbuff from previous reads? */ if (self->rbuff_pos < self->rbuff_len) { /* if yes, process that first */ while (self->rbuff_pos < self->rbuff_len) { buffer[copied++] = self->rbuff[self->rbuff_pos]; if ((self->rbuff[self->rbuff_pos++] == '\n') || (copied == len)) { /* our work is done */ /* resize if necessary */ if (copied < len) /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ if(_PyString_Resize(&result, copied)) return NULL; /* fix for MODPYTHON-181 leak */ if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL) { free(self->rbuff); self->rbuff = NULL; } return result; } } } /* Free old rbuff as the old contents have been copied over and we are about to allocate a new rbuff. Perhaps this could be reused somehow? */ if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL) { free(self->rbuff); self->rbuff = NULL; } /* if got this far, the buffer should be empty, we need to read more */ /* create a read buffer The buffer len will be at least HUGE_STRING_LEN in size, to avoid memory fragmention */ self->rbuff_len = len > HUGE_STRING_LEN ? len : HUGE_STRING_LEN; self->rbuff_pos = 0; self->rbuff = malloc(self->rbuff_len); if (! self->rbuff) return PyErr_NoMemory(); /* read it in */ Py_BEGIN_ALLOW_THREADS chunk_len = ap_get_client_block(self->request_rec, self->rbuff, self->rbuff_len); Py_END_ALLOW_THREADS; /* ap_get_client_block could return -1 on error */ if (chunk_len == -1) { /* Free rbuff since returning NULL here should end the request */ free(self->rbuff); self->rbuff = NULL; PyErr_SetObject(PyExc_IOError, PyString_FromString("Client read error (Timeout?)")); return NULL; } bytes_read = chunk_len; /* if this is a "short read", try reading more */ while ((chunk_len != 0 ) && (bytes_read + copied < len)) { Py_BEGIN_ALLOW_THREADS chunk_len = ap_get_client_block(self->request_rec, self->rbuff + bytes_read, self->rbuff_len - bytes_read); Py_END_ALLOW_THREADS if (chunk_len == -1) { /* Free rbuff since returning NULL here should end the request */ free(self->rbuff); self->rbuff = NULL; PyErr_SetObject(PyExc_IOError, PyString_FromString("Client read error (Timeout?)")); return NULL; } else bytes_read += chunk_len; } self->rbuff_len = bytes_read; self->rbuff_pos = 0; /* now copy the remaining bytes */ while (self->rbuff_pos < self->rbuff_len) { buffer[copied++] = self->rbuff[self->rbuff_pos]; if ((self->rbuff[self->rbuff_pos++] == '\n') || (copied == len)) /* our work is done */ break; } /* Free rbuff if we're done with it */ if (self->rbuff_pos >= self->rbuff_len && self->rbuff != NULL) { free(self->rbuff); self->rbuff = NULL; } /* resize if necessary */ if (copied < len) /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ if(_PyString_Resize(&result, copied)) return NULL; return result; } /** ** request.readlines([long maxsize]) ** * just like file.readlines() */ static PyObject *req_readlines(requestobject *self, PyObject *args) { /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ PyObject *result = PyList_New(0); PyObject *line, *rlargs; long sizehint = -1; long size = 0; long linesize; if (! PyArg_ParseTuple(args, "|l", &sizehint)) return NULL; if (result == NULL) return PyErr_NoMemory(); /* PYTHON 2.5: 'PyTuple_New' uses Py_ssize_t for input parameters */ rlargs = PyTuple_New(0); if (result == NULL) return PyErr_NoMemory(); line = req_readline(self, rlargs); /* PYTHON 2.5: 'PyString_Size' uses Py_ssize_t for input parameters */ while (line && ((linesize=PyString_Size(line))>0)) { PyList_Append(result, line); size += linesize; if ((sizehint != -1) && (size >= sizehint)) break; Py_DECREF(line); line = req_readline(self, args); } Py_XDECREF(line); if (!line) return NULL; return result; } /** ** request.register_cleanup(handler, data) ** * registers a cleanup at request pool destruction time. * optional data argument will be passed to the cleanup function. */ static PyObject *req_register_cleanup(requestobject *self, PyObject *args) { cleanup_info *ci; PyObject *handler = NULL; PyObject *data = NULL; PyObject *name_obj = NULL; char *name = NULL; if (! PyArg_ParseTuple(args, "O|O", &handler, &data)) return NULL; /* bad args */ ci = (cleanup_info *)malloc(sizeof(cleanup_info)); ci->request_rec = self->request_rec; ci->server_rec = self->request_rec->server; if (PyCallable_Check(handler)) { Py_INCREF(handler); ci->handler = handler; name_obj = python_interpreter_name(); name = (char *)malloc(strlen(PyString_AsString(name_obj))+1); strcpy(name, PyString_AsString(name_obj)); ci->interpreter = name; if (data) { Py_INCREF(data); ci->data = data; } else { Py_INCREF(Py_None); ci->data = Py_None; } } else { PyErr_SetString(PyExc_ValueError, "first argument must be a callable object"); free(ci); return NULL; } apr_pool_cleanup_register(self->request_rec->pool, ci, python_cleanup, apr_pool_cleanup_null); Py_INCREF(Py_None); return Py_None; } /** ** request.requires(self) ** * Interface to ap_requires() */ static PyObject * req_requires(requestobject *self) { /* This function returns everything specified after the "requires" as is, without any attempts to parse/organize because "requires" args only need to be grokable by mod_auth if it is authoritative. When AuthAuthoritative is off, anything can follow requires, e.g. "requires role terminator". */ const apr_array_header_t *reqs_arr = ap_requires(self->request_rec); require_line *reqs; int i, ti = 0; PyObject *result; if (!reqs_arr) { return Py_BuildValue("()"); } /* PYTHON 2.5: 'PyTuple_New' uses Py_ssize_t for input parameters */ result = PyTuple_New(reqs_arr->nelts); reqs = (require_line *) reqs_arr->elts; for (i = 0; i < reqs_arr->nelts; ++i) { if (reqs[i].method_mask & (AP_METHOD_BIT << self->request_rec->method_number)) { /* PYTHON 2.5: 'PyTuple_SetItem' uses Py_ssize_t for input parameters */ PyTuple_SetItem(result, ti++, PyString_FromString(reqs[i].requirement)); } } /* PYTHON 2.5: '_PyTuple_Resize' uses Py_ssize_t for input parameters */ _PyTuple_Resize(&result, ti); return result; } /** ** request.send_http_header(request self) ** * this is a noop, just so we don't break old scripts */ static PyObject * req_send_http_header(requestobject *self) { Py_INCREF(Py_None); return Py_None; } /** ** request.set_content_length(request self, long content_length) ** * write output to the client */ static PyObject * req_set_content_length(requestobject *self, PyObject *args) { long len; if (! PyArg_ParseTuple(args, "l", &len)) return NULL; /* bad args */ ap_set_content_length(self->request_rec, len); Py_INCREF(Py_None); return Py_None; } /** ** request.set_etag(request self) ** * sets the outgoing ETag header */ static PyObject * req_set_etag(requestobject *self, PyObject *args) { ap_set_etag(self->request_rec); Py_INCREF(Py_None); return Py_None; } /** ** request.set_last_modified(request self) ** * set the Last-modified header */ static PyObject * req_set_last_modified(requestobject *self, PyObject *args) { ap_set_last_modified(self->request_rec); Py_INCREF(Py_None); return Py_None; } /** ** request.update_mtime(request self, long mtime) ** * updates mtime attribute if newer */ static PyObject * req_update_mtime(requestobject *self, PyObject *args) { double mtime; if (! PyArg_ParseTuple(args, "d", &mtime)) return NULL; /* bad args */ ap_update_mtime(self->request_rec, apr_time_from_sec(mtime)); Py_INCREF(Py_None); return Py_None; } /** ** request.write(request self, string what, flush=1) ** * write output to the client */ static PyObject * req_write(requestobject *self, PyObject *args) { int len; int rc; char *buff; int flush=1; if (! PyArg_ParseTuple(args, "s#|i", &buff, &len, &flush)) return NULL; /* bad args */ if (len > 0 ) { Py_BEGIN_ALLOW_THREADS rc = ap_rwrite(buff, len, self->request_rec); if (flush && (rc != -1)) rc = ap_rflush(self->request_rec); Py_END_ALLOW_THREADS if (rc == -1) { PyErr_SetString(PyExc_IOError, "Write failed, client closed connection."); return NULL; } } self->bytes_queued += len; Py_INCREF(Py_None); return Py_None; } /** ** request.flush(request self) ** * flush output buffer */ static PyObject * req_flush(requestobject *self) { int rc; Py_BEGIN_ALLOW_THREADS rc = ap_rflush(self->request_rec); Py_END_ALLOW_THREADS if (rc == -1) { PyErr_SetString(PyExc_IOError, "Flush failed, client closed connection."); return NULL; } Py_INCREF(Py_None); return Py_None; } /** ** request.sendfile ** */ static PyObject * req_sendfile(requestobject *self, PyObject *args) { char *fname; apr_file_t *fd; apr_size_t offset=0, len=-1, nbytes; apr_status_t status; PyObject * py_result = NULL; apr_finfo_t finfo; if (! PyArg_ParseTuple(args, "s|ll", &fname, &offset, &len)) return NULL; /* bad args */ Py_BEGIN_ALLOW_THREADS status=apr_stat(&finfo, fname, APR_FINFO_SIZE, self->request_rec->pool); Py_END_ALLOW_THREADS if (status != APR_SUCCESS) { PyErr_SetString(PyExc_IOError, "Could not stat file for reading"); return NULL; } Py_BEGIN_ALLOW_THREADS status=apr_file_open(&fd, fname, APR_READ, APR_OS_DEFAULT, self->request_rec->pool); Py_END_ALLOW_THREADS if (status != APR_SUCCESS) { PyErr_SetString(PyExc_IOError, "Could not open file for reading"); return NULL; } if (len==-1) len=finfo.size; Py_BEGIN_ALLOW_THREADS status = ap_send_fd(fd, self->request_rec, offset, len, &nbytes); Py_END_ALLOW_THREADS apr_file_close(fd); if (status != APR_SUCCESS) { PyErr_SetString(PyExc_IOError, "Write failed, client closed connection."); return NULL; } self->bytes_queued += len; py_result = PyLong_FromLong (nbytes); Py_INCREF(py_result); return py_result; } static PyMethodDef request_methods[] = { {"add_common_vars", (PyCFunction) req_add_common_vars, METH_NOARGS}, {"add_handler", (PyCFunction) req_add_handler, METH_VARARGS}, {"add_input_filter", (PyCFunction) req_add_input_filter, METH_VARARGS}, {"add_output_filter", (PyCFunction) req_add_output_filter, METH_VARARGS}, {"allow_methods", (PyCFunction) req_allow_methods, METH_VARARGS}, {"auth_name", (PyCFunction) req_auth_name, METH_NOARGS}, {"auth_type", (PyCFunction) req_auth_type, METH_NOARGS}, {"construct_url", (PyCFunction) req_construct_url, METH_VARARGS}, {"discard_request_body", (PyCFunction) req_discard_request_body, METH_NOARGS}, {"get_config", (PyCFunction) req_get_config, METH_NOARGS}, {"document_root", (PyCFunction) req_document_root, METH_NOARGS}, {"flush", (PyCFunction) req_flush, METH_NOARGS}, {"get_basic_auth_pw", (PyCFunction) req_get_basic_auth_pw, METH_NOARGS}, {"get_addhandler_exts", (PyCFunction) req_get_addhandler_exts, METH_NOARGS}, {"get_remote_host", (PyCFunction) req_get_remote_host, METH_VARARGS}, {"get_options", (PyCFunction) req_get_options, METH_NOARGS}, {"internal_redirect", (PyCFunction) req_internal_redirect, METH_VARARGS}, {"is_https", (PyCFunction) req_is_https, METH_NOARGS}, {"log_error", (PyCFunction) req_log_error, METH_VARARGS}, {"meets_conditions", (PyCFunction) req_meets_conditions, METH_NOARGS}, {"read", (PyCFunction) req_read, METH_VARARGS}, {"readline", (PyCFunction) req_readline, METH_VARARGS}, {"readlines", (PyCFunction) req_readlines, METH_VARARGS}, {"register_cleanup", (PyCFunction) req_register_cleanup, METH_VARARGS}, {"register_input_filter", (PyCFunction) req_register_input_filter, METH_VARARGS}, {"register_output_filter", (PyCFunction) req_register_output_filter, METH_VARARGS}, {"requires", (PyCFunction) req_requires, METH_NOARGS}, {"send_http_header", (PyCFunction) req_send_http_header, METH_NOARGS}, {"sendfile", (PyCFunction) req_sendfile, METH_VARARGS}, {"set_content_length", (PyCFunction) req_set_content_length, METH_VARARGS}, {"set_etag", (PyCFunction) req_set_etag, METH_NOARGS}, {"set_last_modified", (PyCFunction) req_set_last_modified, METH_NOARGS}, {"ssl_var_lookup", (PyCFunction) req_ssl_var_lookup, METH_VARARGS}, {"update_mtime", (PyCFunction) req_update_mtime, METH_VARARGS}, {"write", (PyCFunction) req_write, METH_VARARGS}, { NULL, NULL } /* sentinel */ }; /* These are offsets into the Apache request_rec structure. They are accessed via getset functions. Note that the types specified here are irrelevant if a function other than getreq_recmbr() is used. E.g. bytes_sent is a long long, and is retrieved via getreq_recmbr_off() which ignores what's here. */ #define OFF(x) offsetof(request_rec, x) static struct PyMemberDef request_rec_mbrs[] = { {"the_request", T_STRING, OFF(the_request)}, {"assbackwards", T_INT, OFF(assbackwards)}, {"proxyreq", T_INT, OFF(proxyreq)}, {"header_only", T_INT, OFF(header_only)}, {"protocol", T_STRING, OFF(protocol)}, {"proto_num", T_INT, OFF(proto_num)}, {"hostname", T_STRING, OFF(hostname)}, {"request_time", T_LONG, OFF(request_time)}, {"status_line", T_STRING, OFF(status_line)}, {"status", T_INT, OFF(status)}, {"method", T_STRING, OFF(method)}, {"method_number", T_INT, OFF(method_number)}, {"allowed", T_LONG, OFF(allowed)}, {"allowed_xmethods", T_OBJECT, OFF(allowed_xmethods)}, {"allowed_methods", T_OBJECT, OFF(allowed_methods)}, {"sent_bodyct", T_LONG, OFF(sent_bodyct)}, {"bytes_sent", T_LONG, OFF(bytes_sent)}, {"mtime", T_LONG, OFF(mtime)}, {"chunked", T_INT, OFF(chunked)}, {"range", T_STRING, OFF(range)}, {"clength", T_LONG, OFF(clength)}, {"remaining", T_LONG, OFF(remaining)}, {"read_length", T_LONG, OFF(read_length)}, {"read_body", T_INT, OFF(read_body)}, {"read_chunked", T_INT, OFF(read_chunked)}, {"expecting_100", T_INT, OFF(expecting_100)}, {"content_type", T_STRING, OFF(content_type)}, {"handler", T_STRING, OFF(handler)}, {"content_encoding", T_STRING, OFF(content_encoding)}, {"content_languages", T_OBJECT, OFF(content_languages)}, {"vlist_validator", T_STRING, OFF(vlist_validator)}, {"user", T_STRING, OFF(user)}, {"ap_auth_type", T_STRING, OFF(ap_auth_type)}, {"no_cache", T_INT, OFF(no_cache)}, {"no_local_copy", T_INT, OFF(no_local_copy)}, {"unparsed_uri", T_STRING, OFF(unparsed_uri)}, {"uri", T_STRING, OFF(uri)}, {"filename", T_STRING, OFF(filename)}, {"canonical_filename", T_STRING, OFF(canonical_filename)}, {"path_info", T_STRING, OFF(path_info)}, {"args", T_STRING, OFF(args)}, {"finfo", T_OBJECT, OFF(finfo)}, {"parsed_uri", T_OBJECT, OFF(parsed_uri)}, {"used_path_info", T_INT, OFF(used_path_info)}, {"eos_sent", T_INT, OFF(eos_sent)}, {NULL} /* Sentinel */ }; /** ** getreq_recmbr ** * Retrieves request_rec structure members */ static PyObject *getreq_recmbr(requestobject *self, void *name) { /* * apparently at least ap_internal_fast_redirect blatently * substitute request members, and so we always have to make * sure that various apr_tables referenced haven't been * replaced in between handlers and we're left with a stale. */ if (strcmp(name, "interpreter") == 0) { return python_interpreter_name(); } else if (strcmp(name, "headers_in") == 0) { if (((tableobject*)self->headers_in)->table != self->request_rec->headers_in) ((tableobject*)self->headers_in)->table = self->request_rec->headers_in; Py_INCREF(self->headers_in); return self->headers_in; } else if (strcmp(name, "headers_out") == 0) { if (((tableobject*)self->headers_out)->table != self->request_rec->headers_out) ((tableobject*)self->headers_out)->table = self->request_rec->headers_out; Py_INCREF(self->headers_out); return self->headers_out; } else if (strcmp(name, "err_headers_out") == 0) { if (((tableobject*)self->err_headers_out)->table != self->request_rec->err_headers_out) ((tableobject*)self->err_headers_out)->table = self->request_rec->err_headers_out; Py_INCREF(self->err_headers_out); return self->err_headers_out; } else if (strcmp(name, "subprocess_env") == 0) { if (((tableobject*)self->subprocess_env)->table != self->request_rec->subprocess_env) ((tableobject*)self->subprocess_env)->table = self->request_rec->subprocess_env; Py_INCREF(self->subprocess_env); return self->subprocess_env; } else if (strcmp(name, "notes") == 0) { if (((tableobject*)self->notes)->table != self->request_rec->notes) ((tableobject*)self->notes)->table = self->request_rec->notes; Py_INCREF(self->notes); return self->notes; } else if (strcmp(name, "_bytes_queued") == 0) { if (sizeof(apr_off_t) == sizeof(LONG_LONG)) { LONG_LONG l = self->bytes_queued; return PyLong_FromLongLong(l); } else { /* assume it's long */ long l = self->bytes_queued; return PyLong_FromLong(l); } } else if (strcmp(name, "_request_rec") == 0) { return PyCObject_FromVoidPtr(self->request_rec, 0); } else return PyMember_GetOne((char*)self->request_rec, find_memberdef(request_rec_mbrs, name)); } /** ** setreq_recmbr ** * Sets request_rec structure members */ static int setreq_recmbr(requestobject *self, PyObject *val, void *name) { if (strcmp(name, "content_type") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "content_type must be a string"); return -1; } ap_set_content_type(self->request_rec, apr_pstrdup(self->request_rec->pool, PyString_AsString(val))); self->content_type_set = 1; return 0; } else if (strcmp(name, "user") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "user must be a string"); return -1; } self->request_rec->user = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "ap_auth_type") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "ap_auth_type must be a string"); return -1; } self->request_rec->ap_auth_type = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "filename") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "filename must be a string"); return -1; } self->request_rec->filename = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "canonical_filename") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "canonical_filename must be a string"); return -1; } self->request_rec->canonical_filename = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "path_info") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "path_info must be a string"); return -1; } self->request_rec->path_info = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "args") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "args must be a string"); return -1; } self->request_rec->args = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "handler") == 0) { if (val == Py_None) { self->request_rec->handler = 0; return 0; } if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "handler must be a string"); return -1; } self->request_rec->handler = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "uri") == 0) { if (! PyString_Check(val)) { PyErr_SetString(PyExc_TypeError, "uri must be a string"); return -1; } self->request_rec->uri = apr_pstrdup(self->request_rec->pool, PyString_AsString(val)); return 0; } else if (strcmp(name, "finfo") == 0) { finfoobject *f; if (! MpFinfo_Check(val)) { PyErr_SetString(PyExc_TypeError, "finfo must be a finfoobject"); return -1; } f = (finfoobject *)val; self->request_rec->finfo = *f->finfo; self->request_rec->finfo.fname = apr_pstrdup(self->request_rec->pool, f->finfo->fname); self->request_rec->finfo.name = apr_pstrdup(self->request_rec->pool, f->finfo->name); return 0; } return PyMember_SetOne((char*)self->request_rec, find_memberdef(request_rec_mbrs, (char*)name), val); } /** ** getreq_recmbr_time ** * Retrieves apr_time_t request_rec members */ static PyObject *getreq_recmbr_time(requestobject *self, void *name) { PyMemberDef *md = find_memberdef(request_rec_mbrs, name); char *addr = (char *)self->request_rec + md->offset; apr_time_t time = *(apr_time_t*)addr; return PyFloat_FromDouble(time*0.000001); } /** ** getreq_recmbr_off ** * Retrieves apr_off_t request_rec members */ static PyObject *getreq_recmbr_off(requestobject *self, void *name) { PyMemberDef *md = find_memberdef(request_rec_mbrs, name); char *addr = (char *)self->request_rec + md->offset; if (sizeof(apr_off_t) == sizeof(LONG_LONG)) { LONG_LONG l = *(LONG_LONG*)addr; return PyLong_FromLongLong(l); } else { /* assume it's long */ long l = *(long*)addr; return PyLong_FromLong(l); } } /** ** getreq_rec_ah ** * For array headers that will get converted to tuple */ static PyObject *getreq_rec_ah(requestobject *self, void *name) { const PyMemberDef *md = find_memberdef(request_rec_mbrs, name); apr_array_header_t *ah = *(apr_array_header_t **)((char *)self->request_rec + md->offset); return tuple_from_array_header(ah); } /** ** getreq_rec_ml ** * For method lists that will get converted to tuple */ static PyObject *getreq_rec_ml(requestobject *self, void *name) { const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name); ap_method_list_t *ml = *(ap_method_list_t **)((char *)self->request_rec + md->offset); return tuple_from_method_list(ml); } /** ** getreq_rec_fi ** * For file info that will get converted to tuple */ static PyObject *getreq_rec_fi(requestobject *self, void *name) { const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name); apr_finfo_t *fi = (apr_finfo_t *)((char *)self->request_rec + md->offset); return MpFinfo_FromFinfo(fi); } /** ** getreq_rec_uri ** * For parsed uri that will get converted to tuple */ static PyObject *getreq_rec_uri(requestobject *self, void *name) { const PyMemberDef *md = find_memberdef(request_rec_mbrs, (char*)name); apr_uri_t *uri = (apr_uri_t *)((char *)self->request_rec + md->offset); return tuple_from_apr_uri(uri); } /** ** getmakeobj ** * A getter func that creates an object as needed. */ static PyObject *getmakeobj(requestobject* self, void *objname) { char *name = (char *)objname; PyObject *result = NULL; if (strcmp(name, "connection") == 0) { if (!self->connection && self->request_rec->connection) { self->connection = MpConn_FromConn(self->request_rec->connection); } result = self->connection; } else if (strcmp(name, "server") == 0) { if (!self->server && self->request_rec->server) { self->server = MpServer_FromServer(self->request_rec->server); } result = self->server; } else if (strcmp(name, "next") == 0) { if (self->request_rec->next) { result = (PyObject*)python_get_request_object( self->request_rec->next, 0); } } else if (strcmp(name, "prev") == 0) { if (self->request_rec->prev) { result = (PyObject*)python_get_request_object( self->request_rec->prev, 0); } } else if (strcmp(name, "main") == 0) { if (self->request_rec->main) { result = (PyObject*)python_get_request_object( self->request_rec->main, 0); } } if (!result) result = Py_None; Py_INCREF(result); return result; } static PyGetSetDef request_getsets[] = { {"interpreter", (getter)getreq_recmbr, NULL, "Python interpreter name", "interpreter"}, {"connection", (getter)getmakeobj, NULL, "Connection object", "connection"}, {"server", (getter)getmakeobj, NULL, "Server object", "server"}, {"next", (getter)getmakeobj, NULL, "If redirected, pointer to the to request", "next"}, {"prev", (getter)getmakeobj, NULL, "If redirected, pointer to the from request", "prev"}, {"main", (getter)getmakeobj, NULL, "If subrequest, pointer to the main request", "main"}, {"the_request", (getter)getreq_recmbr, NULL, "First line of request", "the_request"}, {"assbackwards", (getter)getreq_recmbr, (setter)setreq_recmbr, "HTTP/0.9 \"simple\" request", "assbackwards"}, {"proxyreq", (getter)getreq_recmbr, (setter)setreq_recmbr, "A proxy request: one of apache.PROXYREQ_* values", "proxyreq"}, {"header_only", (getter)getreq_recmbr, NULL, "HEAD request, as oppsed to GET", "header_only"}, {"protocol", (getter)getreq_recmbr, NULL, "Protocol as given to us, or HTTP/0.9", "protocol"}, {"proto_num", (getter)getreq_recmbr, NULL, "Protocol version. 1.1 = 1001", "proto_num"}, {"hostname", (getter)getreq_recmbr, NULL, "Host, as set by full URI or Host:", "hostname"}, {"request_time", (getter)getreq_recmbr_time, NULL, "When request started", "request_time"}, {"status_line", (getter)getreq_recmbr, NULL, "Status line, if set by script", "status_line"}, {"status", (getter)getreq_recmbr, (setter)setreq_recmbr, "Status", "status"}, {"method", (getter)getreq_recmbr, NULL, "Request method", "method"}, {"method_number", (getter)getreq_recmbr, NULL, "Request method number, one of apache.M_*", "method_number"}, {"allowed", (getter)getreq_recmbr, NULL, "Status", "allowed"}, {"allowed_xmethods", (getter)getreq_rec_ah, NULL, "Allowed extension methods", "allowed_xmethods"}, {"allowed_methods", (getter)getreq_rec_ml, NULL, "Allowed methods", "allowed_methods"}, {"sent_bodyct", (getter)getreq_recmbr_off, NULL, "Byte count in stream for body", "sent_bodyct"}, {"bytes_sent", (getter)getreq_recmbr_off, NULL, "Bytes sent", "bytes_sent"}, {"mtime", (getter)getreq_recmbr_time, NULL, "Time resource was last modified", "mtime"}, {"chunked", (getter)getreq_recmbr, NULL, "Sending chunked transfer-coding", "chunked"}, {"range", (getter)getreq_recmbr, NULL, "The Range: header", "range"}, {"clength", (getter)getreq_recmbr_off, NULL, "The \"real\" contenct length", "clength"}, {"remaining", (getter)getreq_recmbr_off, NULL, "Bytes left to read", "remaining"}, {"read_length", (getter)getreq_recmbr_off, NULL, "Bytes that have been read", "read_length"}, {"read_body", (getter)getreq_recmbr, NULL, "How the request body should be read", "read_body"}, {"read_chunked", (getter)getreq_recmbr, NULL, "Reading chunked transfer-coding", "read_chunked"}, {"expecting_100", (getter)getreq_recmbr, NULL, "Is client waitin for a 100 response?", "expecting_100"}, {"content_type", (getter)getreq_recmbr, (setter)setreq_recmbr, "Content type", "content_type"}, {"handler", (getter)getreq_recmbr, (setter)setreq_recmbr, "The handler string", "handler"}, {"content_encoding", (getter)getreq_recmbr, NULL, "How to encode the data", "content_encoding"}, {"content_languages", (getter)getreq_rec_ah, NULL, "Content languages", "content_languages"}, {"vlist_validator", (getter)getreq_recmbr, NULL, "Variant list validator (if negotiated)", "vlist_validator"}, {"user", (getter)getreq_recmbr, (setter)setreq_recmbr, "If authentication check was made, the user name", "user"}, {"ap_auth_type", (getter)getreq_recmbr, (setter)setreq_recmbr, "If authentication check was made, auth type", "ap_auth_type"}, {"no_cache", (getter)getreq_recmbr, (setter)setreq_recmbr, "This response in non-cacheable", "no_cache"}, {"no_local_copy", (getter)getreq_recmbr, (setter)setreq_recmbr, "There is no local copy of the response", "no_local_copy"}, {"unparsed_uri", (getter)getreq_recmbr, NULL, "The URI without any parsing performed", "unparsed_uri"}, {"uri", (getter)getreq_recmbr, (setter)setreq_recmbr, "The path portion of URI", "uri"}, {"filename", (getter)getreq_recmbr, (setter)setreq_recmbr, "The file name on disk that this request corresponds to", "filename"}, {"canonical_filename", (getter)getreq_recmbr, (setter)setreq_recmbr, "The true filename (req.filename is canonicalized if they dont match)", "canonical_filename"}, {"path_info", (getter)getreq_recmbr, (setter)setreq_recmbr, "Path_info, if any", "path_info"}, {"args", (getter)getreq_recmbr, (setter)setreq_recmbr, "QUERY_ARGS, if any", "args"}, {"finfo", (getter)getreq_rec_fi, (setter)setreq_recmbr, "File information", "finfo"}, {"parsed_uri", (getter)getreq_rec_uri, NULL, "Components of URI", "parsed_uri"}, {"used_path_info", (getter)getreq_recmbr, (setter)setreq_recmbr, "Flag to accept or reject path_info on current request", "used_path_info"}, {"headers_in", (getter)getreq_recmbr, NULL, "Incoming headers", "headers_in"}, {"headers_out", (getter)getreq_recmbr, NULL, "Outgoing headers", "headers_out"}, {"err_headers_out", (getter)getreq_recmbr, NULL, "Outgoing headers for errors", "err_headers_out"}, {"subprocess_env", (getter)getreq_recmbr, NULL, "Subprocess environment", "subprocess_env"}, {"notes", (getter)getreq_recmbr, NULL, "Notes", "notes"}, /* XXX per_dir_config */ /* XXX request_config */ /* XXX htaccess */ /* XXX filters and eos */ {"eos_sent", (getter)getreq_recmbr, NULL, "EOS bucket sent", "eos_sent"}, {"_bytes_queued", (getter)getreq_recmbr, NULL, "Bytes queued by handler", "_bytes_queued"}, {"_request_rec", (getter)getreq_recmbr, NULL, "Actual request_rec struct", "_request_rec"}, {NULL} /* Sentinel */ }; #undef OFF #define OFF(x) offsetof(requestobject, x) static struct PyMemberDef request_members[] = { {"_content_type_set", T_INT, OFF(content_type_set), RO}, {"phase", T_OBJECT, OFF(phase), RO}, {"extension", T_STRING, OFF(extension), RO}, {"hlist", T_OBJECT, OFF(hlo), RO}, {NULL} /* Sentinel */ }; /** ** request_tp_clear ** * */ #ifndef CLEAR_REQUEST_MEMBER #define CLEAR_REQUEST_MEMBER(member)\ tmp = (PyObject *) member;\ member = NULL;\ Py_XDECREF(tmp) #endif static int request_tp_clear(requestobject *self) { PyObject* tmp; CLEAR_REQUEST_MEMBER(self->dict); CLEAR_REQUEST_MEMBER(self->connection); CLEAR_REQUEST_MEMBER(self->server); CLEAR_REQUEST_MEMBER(self->headers_in); CLEAR_REQUEST_MEMBER(self->headers_out); CLEAR_REQUEST_MEMBER(self->err_headers_out); CLEAR_REQUEST_MEMBER(self->subprocess_env); CLEAR_REQUEST_MEMBER(self->notes); CLEAR_REQUEST_MEMBER(self->phase); CLEAR_REQUEST_MEMBER(self->hlo); CLEAR_REQUEST_MEMBER(self->callbacks); return 0; } /** ** request_dealloc ** * */ static void request_tp_dealloc(requestobject *self) { /* de-register the object from the GC * before its deallocation, to prevent the * GC to run on a partially de-allocated object */ PyObject_GC_UnTrack(self); /* self->rebuff is used by req_readline. * It may not have been freed if req_readline was not * enough times to consume rbuff's contents. */ if (self->rbuff != NULL) free(self->rbuff); request_tp_clear(self); PyObject_GC_Del(self); } /** ** request_tp_traverse ** * Traversal of the request object */ #ifndef VISIT_REQUEST_MEMBER #define VISIT_REQUEST_MEMBER(member, visit, arg)\ if (member) {\ result = visit(member, arg);\ if (result)\ return result;\ } #endif static int request_tp_traverse(requestobject* self, visitproc visit, void *arg) { int result; VISIT_REQUEST_MEMBER(self->dict, visit, arg); VISIT_REQUEST_MEMBER(self->connection, visit, arg); VISIT_REQUEST_MEMBER(self->server, visit, arg); VISIT_REQUEST_MEMBER(self->headers_in, visit, arg); VISIT_REQUEST_MEMBER(self->headers_out, visit, arg); VISIT_REQUEST_MEMBER(self->err_headers_out, visit, arg); VISIT_REQUEST_MEMBER(self->subprocess_env, visit, arg); VISIT_REQUEST_MEMBER(self->notes, visit, arg); VISIT_REQUEST_MEMBER(self->phase, visit, arg); /* no need to Py_DECREF(dict) since the reference is borrowed */ return 0; } static char request_doc[] = "Apache request_rec structure\n"; PyTypeObject MpRequest_Type = { PyObject_HEAD_INIT(NULL) 0, "mp_request", sizeof(requestobject), 0, (destructor)request_tp_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE| Py_TPFLAGS_HAVE_GC , /* tp_flags */ request_doc, /* tp_doc */ (traverseproc)request_tp_traverse, /* tp_traverse */ /* PYTHON 2.5: 'inquiry' should be perhaps replaced with 'lenfunc' */ (inquiry)request_tp_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ request_methods, /* tp_methods */ request_members, /* tp_members */ request_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(requestobject, dict), /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ }; mod_python-3.3.1/src/mod_python.c0000644000175000017500000027667510524544343015164 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * mod_python.c * * $Id: mod_python.c 472785 2006-11-09 06:21:23Z grahamd $ * * See accompanying documentation and source code comments * for details. * */ #include "mod_python.h" /* Server object for main server as supplied to python_init(). */ static server_rec *main_server = NULL; /* List of available Python obCallBacks/Interpreters * (In a Python dictionary) */ static PyObject * interpreters = NULL; #if APR_HAS_THREADS static apr_thread_mutex_t* interpreters_lock = 0; #endif apr_pool_t *child_init_pool = NULL; /* Optional functions imported from mod_include when loaded: */ static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *optfn_register_include_handler; static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *optfn_ssi_get_tag_and_value; static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *optfn_ssi_parse_string; /** ** make_interpreter ** * Creates a new Python interpreter. */ static PyInterpreterState *make_interpreter(const char *name) { PyThreadState *tstate; /* create a new interpeter */ tstate = Py_NewInterpreter(); if (! tstate) { /* couldn't create an interpreter, this is bad */ ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "make_interpreter: Py_NewInterpreter() returned NULL. No more memory?"); return NULL; } /* release the thread state */ PyThreadState_Swap(NULL); /* Strictly speaking we don't need that tstate created * by Py_NewInterpreter but is preferable to waste it than re-write * a cousin to Py_NewInterpreter * XXX (maybe we can destroy it?) */ return tstate->interp; } /** ** make_obcallback ** * This function instantiates an obCallBack object. * NOTE: The obCallBack object is instantiated by Python * code. This C module calls into Python code which returns * the reference to obCallBack. */ static PyObject * make_obcallback(char *name) { PyObject *m = NULL; PyObject *obCallBack = NULL; /* This makes _apache appear imported, and subsequent * >>> import _apache * will not give an error. */ /* Py_InitModule("_apache", _apache_module_methods); */ init_apache(); /* Now execute the equivalent of * >>> import * >>> * in the __main__ module to start up Python. */ if (! ((m = PyImport_ImportModule(MODULENAME)))) { PyObject *path; ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "make_obcallback: could not import %s.\n", (!MODULENAME) ? "" : MODULENAME); PyErr_Print(); fflush(stderr); path = PyObject_Repr(PySys_GetObject("path")); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "make_obcallback: Python path being used \"%s\".", PyString_AsString(path)); Py_DECREF(path); return NULL; } if (m && ! ((obCallBack = PyObject_CallMethod(m, INITFUNC, "sO", name, MpServer_FromServer(main_server))))) { const char *mp_compile_version = MPV_STRING; const char *mp_dynamic_version = ""; PyObject *o = NULL; PyObject *d = NULL; PyObject *f = NULL; ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "make_obcallback: could not call %s.\n", (!INITFUNC) ? "" : INITFUNC); PyErr_Print(); fflush(stderr); m = PyImport_ImportModule("mod_python"); if (m) { d = PyModule_GetDict(m); o = PyDict_GetItemString(d, "version"); f = PyDict_GetItemString(d, "__file__"); if (o) { mp_dynamic_version = PyString_AsString(o); } } if (strcmp(mp_compile_version, mp_dynamic_version) != 0) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "make_obcallback: mod_python version mismatch, expected '%s', found '%s'.", mp_compile_version, mp_dynamic_version); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "make_obcallback: mod_python modules location '%s'.", PyString_AsString(f)); } } Py_XDECREF(m); return obCallBack; } /** ** save_interpreter ** * Save away the interpreter. */ static interpreterdata *save_interpreter(const char *name, PyInterpreterState *istate) { PyObject *p; interpreterdata *idata = NULL; idata = (interpreterdata *)malloc(sizeof(interpreterdata)); idata->istate = istate; /* obcallback will be created on first use */ idata->obcallback = NULL; p = PyCObject_FromVoidPtr((void *) idata, NULL); PyDict_SetItemString(interpreters, (char *)name, p); Py_DECREF(p); return idata; } /* * python_interpreter_name * * Get name of current interpreter. Must be called while lock is held. * This is effectively a shortcut for accessing "apache.interpreter". */ PyObject *python_interpreter_name() { PyObject *m = NULL; PyObject *d = NULL; PyObject *o = NULL; m = PyImport_ImportModule("mod_python.apache"); if (m) { d = PyModule_GetDict(m); o = PyDict_GetItemString(d, "interpreter"); if (o) { Py_INCREF(o); Py_DECREF(m); return o; } } return 0; } /** ** get_interpreter ** * Get interpreter given its name. * NOTE: This function will acquire lock */ static interpreterdata *get_interpreter(const char *name) { PyObject *p; PyThreadState *tstate; interpreterdata *idata = NULL; if (! name) name = MAIN_INTERPRETER; #if APR_HAS_THREADS apr_thread_mutex_lock(interpreters_lock); #endif #ifdef WITH_THREAD PyEval_AcquireLock(); #endif if (!interpreters) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "get_interpreter: interpreters dictionary not initialised."); #ifdef WITH_THREAD PyEval_ReleaseLock(); #endif #if APR_HAS_THREADS apr_thread_mutex_unlock(interpreters_lock); #endif return NULL; } p = PyDict_GetItemString(interpreters, (char *)name); if (!p) { PyInterpreterState *istate = make_interpreter(name); if (istate) idata = save_interpreter(name, istate); } else { idata = (interpreterdata *)PyCObject_AsVoidPtr(p); } #ifdef WITH_THREAD PyEval_ReleaseLock(); #endif if (! idata) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "get_interpreter: cannot get interpreter data (no more memory?)"); #if APR_HAS_THREADS apr_thread_mutex_unlock(interpreters_lock); #endif return NULL; } /* create thread state and acquire lock */ tstate = PyThreadState_New(idata->istate); #ifdef WITH_THREAD PyEval_AcquireThread(tstate); #else PyThreadState_Swap(tstate); #endif if (!idata->obcallback) { idata->obcallback = make_obcallback((char*)name); if (!idata->obcallback) { PyThreadState_Clear(tstate); #ifdef WITH_THREAD PyEval_ReleaseThread(tstate); #else PyThreadState_Swap(NULL); #endif PyThreadState_Delete(tstate); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_server, "get_interpreter: no interpreter callback found."); #if APR_HAS_THREADS apr_thread_mutex_unlock(interpreters_lock); #endif return NULL; } } #if APR_HAS_THREADS apr_thread_mutex_unlock(interpreters_lock); #endif return idata; } /** ** release_interpreter ** * Release interpreter. * NOTE: This function will release lock */ static void release_interpreter(void) { PyThreadState *tstate = PyThreadState_Get(); PyThreadState_Clear(tstate); #ifdef WITH_THREAD PyEval_ReleaseThread(tstate); #else PyThreadState_Swap(NULL); #endif PyThreadState_Delete(tstate); } /** ** pytho_cleanup ** * This function gets called for clean ups registered * with register_cleanup(). Clean ups registered via * PythonCleanupHandler run in python_cleanup_handler() * below. */ apr_status_t python_cleanup(void *data) { interpreterdata *idata; cleanup_info *ci = (cleanup_info *)data; /* get/create interpreter */ idata = get_interpreter(ci->interpreter); if (!idata) { Py_DECREF(ci->handler); Py_XDECREF(ci->data); free((void *)ci->interpreter); free(ci); return APR_SUCCESS; /* this is ignored anyway */ } /* * Call the cleanup function. */ if (! PyObject_CallFunction(ci->handler, "O", ci->data)) { PyObject *ptype; PyObject *pvalue; PyObject *ptb; PyObject *handler; PyObject *stype; PyObject *svalue; PyErr_Fetch(&ptype, &pvalue, &ptb); handler = PyObject_Str(ci->handler); stype = PyObject_Str(ptype); svalue = PyObject_Str(pvalue); Py_XDECREF(ptype); Py_XDECREF(pvalue); Py_XDECREF(ptb); if (ci->request_rec) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ci->request_rec, "python_cleanup: Error calling cleanup object %s", PyString_AsString(handler)); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ci->request_rec, " %s: %s", PyString_AsString(stype), PyString_AsString(svalue)); } else { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ci->server_rec, "python_cleanup: Error calling cleanup object %s", PyString_AsString(handler)); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ci->server_rec, " %s: %s", PyString_AsString(stype), PyString_AsString(svalue)); } Py_DECREF(handler); Py_DECREF(stype); Py_DECREF(svalue); } Py_DECREF(ci->handler); Py_DECREF(ci->data); free((void *)ci->interpreter); free(ci); release_interpreter(); return APR_SUCCESS; } static apr_status_t init_mutexes(server_rec *s, apr_pool_t *p, py_global_config *glb) { int max_threads = 0; int max_procs = 0; int is_threaded = 0; int is_forked = 0; int max_clients; int locks; int n; const char *val; const char *mutex_dir; py_config *conf; conf = (py_config *) ap_get_module_config(s->module_config, &python_module); /* figure out maximum possible concurrent connections */ /* MAX_DAEMON_USED seems to account for MaxClients, as opposed to MAX_DAEMONS, which is ServerLimit */ ap_mpm_query(AP_MPMQ_IS_THREADED, &is_threaded); if (is_threaded != AP_MPMQ_NOT_SUPPORTED) { ap_mpm_query(AP_MPMQ_MAX_THREADS, &max_threads); } ap_mpm_query(AP_MPMQ_IS_FORKED, &is_forked); if (is_forked != AP_MPMQ_NOT_SUPPORTED) { /* XXX This looks strange, and it is. prefork.c seems to use MAX_DAEMON_USED the same way that worker.c uses MAX_DAEMONS (prefork is wrong IMO) */ ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_procs); if (max_procs == -1) { ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_procs); } } max_clients = (((max_threads <= 0) ? 1 : max_threads) * ((max_procs <= 0) ? 1 : max_procs)); /* On some systems the locking mechanism chosen uses valuable system resources, notably on RH 8 it will use sysv ipc for which Linux by default provides only 128 semaphores system-wide, and on many other systems flock is used, which results in a relatively large number of open files. The maximum number of locks can be specified at compile time using "./configure --with-max-locks value" or at run time with "PythonOption mod_python.mutex_locks value". If the PythonOption directive is used, it must be in a server config context, otherwise it will be ignored. The optimal number of necessary locks is not clear, perhaps a small number is more than sufficient - if someone took the time to run some research on this, that'd be most welcome! */ val = apr_table_get(conf->options, "mod_python.mutex_locks"); if (val) { locks = atoi(val); } else { locks = MAX_LOCKS; } locks = (max_clients > locks) ? locks : max_clients; ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "mod_python: Creating %d session mutexes based " "on %d max processes and %d max threads.", locks, max_procs, max_threads); glb->g_locks = (apr_global_mutex_t **) apr_palloc(p, locks * sizeof(apr_global_mutex_t *)); glb->nlocks = locks; glb->parent_pid = getpid(); #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) /* On some sytems a directory for the mutex lock files is required. This mutex directory can be specifed at compile time using "./configure --with-mutex-dir value" or at run time with "PythonOption mod_python.mutex_directory value". If the PythonOption directive is used, it must be in a server config context, otherwise it will be ignored. XXX Should we check if mutex_dir exists and has the correct permissions? */ mutex_dir = apr_table_get(conf->options, "mod_python.mutex_directory"); if (!mutex_dir) mutex_dir = MUTEX_DIR; ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "mod_python: using mutex_directory %s ", mutex_dir); #endif for (n=0; ng_locks; #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) char fname[255]; /* XXX What happens if len(mutex_dir) > 255 - len(mpmtx%d%d)? */ snprintf(fname, 255, "%s/mpmtx%d%d", mutex_dir, glb->parent_pid, n); #else char *fname = NULL; #endif rc = apr_global_mutex_create(&mutex[n], fname, APR_LOCK_DEFAULT, p); if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, "mod_python: Failed to create global mutex %d of %d (%s).", n, locks, (!fname) ? "" : fname); if (n > 1) { /* we were able to create at least two, so lets just print a warning/hint and proceed */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_python: We can probably continue, but with diminished ability " "to process session locks."); ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "mod_python: Hint: On Linux, the problem may be the number of " "available semaphores, check 'sysctl kernel.sem'"); /* now free two locks so that if there is another module or two that wants a lock, it will be ok */ apr_global_mutex_destroy(mutex[n-1]); glb->nlocks = n-1; if (n > 2) { apr_global_mutex_destroy(mutex[n-2]); glb->nlocks = n-2; } break; } else { return rc; } } else { /*XXX As of httpd 2.0.4, the below should be just a call to unixd_set_global_mutex_perms(mutex[n]); and nothing else... For now, while 2.0.48 isn't commonplace yet, this ugly code should be here */ #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) if (!geteuid()) { chown(fname, unixd_config.user_id, -1); unixd_set_global_mutex_perms(mutex[n]); } #endif } } return APR_SUCCESS; } static apr_status_t reinit_mutexes(server_rec *s, apr_pool_t *p, py_global_config *glb) { int n; #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) /* Determine the directory to use for mutex lock files. See init_mutexes function for more details. */ const char *mutex_dir; py_config *conf; conf = (py_config *) ap_get_module_config(s->module_config, &python_module); mutex_dir = apr_table_get(conf->options, "mod_python.mutex_directory"); if (!mutex_dir) mutex_dir = MUTEX_DIR; #endif for (n=0; n< glb->nlocks; n++) { apr_status_t rc; apr_global_mutex_t **mutex = glb->g_locks; #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) char fname[255]; snprintf(fname, 255, "%s/mpmtx%d%d", mutex_dir, glb->parent_pid, n); #else char *fname = NULL; #endif rc = apr_global_mutex_child_init(&mutex[n], fname, p); if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, s, "mod_python: Failed to reinit global mutex %s.", (!fname) ? "" : fname); return rc; } } return APR_SUCCESS; } /** ** python_create_global_config ** * This creates the part of config that survives * server restarts * */ static py_global_config *python_create_global_config(server_rec *s) { apr_pool_t *pool = s->process->pool; py_global_config *glb; /* do we already have it in s->process->pool? */ apr_pool_userdata_get((void **)&glb, MP_CONFIG_KEY, pool); if (glb) { return glb; } /* otherwise, create it */ glb = (py_global_config *)apr_palloc(pool, sizeof(*glb)); apr_pool_userdata_set(glb, MP_CONFIG_KEY, apr_pool_cleanup_null, pool); return glb; } /* * mp_acquire_interpreter() * * Exported function for acquiring named interpreter. */ PyInterpreterState *mp_acquire_interpreter(const char *name) { interpreterdata *idata; idata = get_interpreter(name); return idata->istate; } /* * mp_release_interpreter() * * Exported function for releasing acquired interpreter. * */ void mp_release_interpreter(void) { release_interpreter(); } /* * mp_get_request_object(request_rec *req) * * Exported function for obtaining wrapper for request object. * */ PyObject *mp_get_request_object(request_rec *req) { requestobject *request_obj; request_obj = python_get_request_object(req, 0); return (PyObject *)request_obj; } /* * mp_get_server_object(server_rec *srv) * * Exported function for obtaining wrapper for server object. * */ PyObject *mp_get_server_object(server_rec *srv) { return (PyObject *)MpServer_FromServer(srv); } /* * mp_get_connection_object(conn_rec *conn) * * Exported function for obtaining wrapper for connection object. * */ PyObject *mp_get_connection_object(conn_rec *conn) { return (PyObject *)MpConn_FromConn(conn); } /** ** python_init() ** * Called by Apache at mod_python initialization time. */ static int python_init(apr_pool_t *p, apr_pool_t *ptemp, apr_pool_t *plog, server_rec *s) { char buff[255]; void *data; py_global_config *glb; const char *userdata_key = "python_init"; apr_status_t rc; const char *py_compile_version = PY_VERSION; const char *py_dynamic_version = 0; /* The "initialized" flag is a fudge for Mac OS X. It * addresses two issues. The first is that when an Apache * "restart" is performed, Apache will unload the mod_python * shared object, but not the Python framework. This means * that when "python_init()" is called after the restart, * the mod_python initialization will not run if only the * initialized state of Python is checked, because Python * is already initialized. The second problem is that for * some older revisions of Mac OS X, even on the initial * startup of Apache, the "Py_IsInitialized()" function * would return true and mod_python wouldn't initialize * itself correctly and would crash. */ static int initialized = 0; #ifdef WIN32 /* No need to run python_init() in Win32 parent processes as * the lack of fork on Win32 means we get no benefit as far as * inheriting a preinitialized Python interpreter. Further, * upon a restart on Win32 platform the python_init() function * will be called again in the parent process but without some * resources allocated by the previous call having being * released properly, resulting in memory and Win32 resource * leaks. */ if (!getenv("AP_PARENT_PID")) return OK; #endif /* WIN32 */ apr_pool_userdata_get(&data, userdata_key, s->process->pool); if (!data) { apr_pool_userdata_set((const void *)1, userdata_key, apr_pool_cleanup_null, s->process->pool); return OK; } /* mod_python version */ ap_add_version_component(p, VERSION_COMPONENT); py_dynamic_version = strtok((char *)Py_GetVersion(), " "); if (strcmp(py_compile_version, py_dynamic_version) != 0) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, s, "python_init: Python version mismatch, expected '%s', found '%s'.", py_compile_version, py_dynamic_version); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, s, "python_init: Python executable found '%s'.", Py_GetProgramFullPath()); ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, s, "python_init: Python path being used '%s'.", Py_GetPath()); } /* Python version */ sprintf(buff, "Python/%.200s", py_dynamic_version); ap_add_version_component(p, buff); /* cache main server */ main_server = s; /* global config */ glb = python_create_global_config(s); if ((rc = init_mutexes(s, p, glb)) != APR_SUCCESS) { return rc; } /* initialize global Python interpreter if necessary */ if (initialized == 0 || !Py_IsInitialized()) { initialized = 1; /* initialze the interpreter */ Py_Initialize(); #if APR_HAS_THREADS apr_thread_mutex_create(&interpreters_lock, APR_THREAD_MUTEX_UNNESTED, p); #endif #ifdef WITH_THREAD /* create and acquire the interpreter lock */ PyEval_InitThreads(); #endif /* create the obCallBack dictionary */ interpreters = PyDict_New(); if (! interpreters) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, s, "python_init: PyDict_New() failed! No more memory?"); exit(1); } #ifdef WITH_THREAD /* release the lock; now other threads can run */ PyEval_ReleaseLock(); #endif } APR_REGISTER_OPTIONAL_FN(mp_acquire_interpreter); APR_REGISTER_OPTIONAL_FN(mp_release_interpreter); APR_REGISTER_OPTIONAL_FN(mp_get_request_object); APR_REGISTER_OPTIONAL_FN(mp_get_server_object); APR_REGISTER_OPTIONAL_FN(mp_get_connection_object); return OK; } /** ** python_create_config ** * Called by create_dir_config and create_srv_config */ static py_config *python_create_config(apr_pool_t *p) { py_config *conf = (py_config *) apr_pcalloc(p, sizeof(py_config)); conf->authoritative = 1; conf->options = apr_table_make(p, 4); conf->directives = apr_table_make(p, 4); conf->hlists = apr_hash_make(p); conf->in_filters = apr_hash_make(p); conf->out_filters = apr_hash_make(p); return conf; } /** ** python_create_dir_config ** * Allocate memory and initialize the strucure that will * hold configuration parametes. * * This function is called on every hit it seems. */ static void *python_create_dir_config(apr_pool_t *p, char *dir) { py_config *conf = python_create_config(p); /* make sure directory ends with a slash */ if (dir && (dir[strlen(dir) - 1] != '/')) conf->config_dir = apr_pstrcat(p, dir, "/", NULL); else conf->config_dir = apr_pstrdup(p, dir); return conf; } /** ** python_create_srv_config ** * Allocate memory and initialize the strucure that will * hold configuration parametes. */ static void *python_create_srv_config(apr_pool_t *p, server_rec *srv) { py_config *conf = python_create_config(p); return conf; } /** ** modpython_table_overlap ** * Replaces the apr_table_overlap() function using a specific pool * for the resulting table. */ static apr_table_t *modpython_table_overlap(apr_pool_t *p, apr_table_t *current_table, apr_table_t *new_table) { apr_table_t *merge = apr_table_overlay(p, current_table, new_table); apr_table_compress(merge, APR_OVERLAP_TABLES_SET); return merge; } /** ** python_merge_dir_config ** */ static void *python_merge_config(apr_pool_t *p, void *current_conf, void *new_conf) { py_config *merged_conf = (py_config *) apr_pcalloc(p, sizeof(py_config)); py_config *cc = (py_config *) current_conf; py_config *nc = (py_config *) new_conf; apr_hash_index_t *hi; char *key; apr_ssize_t klen; hl_entry *hle; py_handler *fh; /* we basically allow the local configuration to override global, * by first copying current values and then new values on top */ /** create **/ merged_conf->hlists = apr_hash_make(p); merged_conf->in_filters = apr_hash_make(p); merged_conf->out_filters = apr_hash_make(p); /** merge directives and options **/ merged_conf->directives = modpython_table_overlap(p, cc->directives, nc->directives); merged_conf->options = modpython_table_overlap(p, cc->options, nc->options); /** copy current **/ merged_conf->authoritative = cc->authoritative; merged_conf->config_dir = apr_pstrdup(p, cc->config_dir); for (hi = apr_hash_first(p, cc->hlists); hi; hi=apr_hash_next(hi)) { apr_hash_this(hi, (const void **)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->hlists, key, klen, (void *)hle); } for (hi = apr_hash_first(p, cc->in_filters); hi; hi=apr_hash_next(hi)) { apr_hash_this(hi, (const void **)&key, &klen, (void **)&fh); apr_hash_set(merged_conf->in_filters, key, klen, (void *)fh); } for (hi = apr_hash_first(p, cc->out_filters); hi; hi=apr_hash_next(hi)) { apr_hash_this(hi, (const void **)&key, &klen, (void **)&fh); apr_hash_set(merged_conf->out_filters, key, klen, (void *)fh); } /** copy new **/ if (nc->authoritative != merged_conf->authoritative) merged_conf->authoritative = nc->authoritative; if (nc->config_dir) merged_conf->config_dir = apr_pstrdup(p, nc->config_dir); for (hi = apr_hash_first(p, nc->hlists); hi; hi=apr_hash_next(hi)) { apr_hash_this(hi, (const void**)&key, &klen, (void **)&hle); apr_hash_set(merged_conf->hlists, key, klen, (void *)hle); } for (hi = apr_hash_first(p, nc->in_filters); hi; hi=apr_hash_next(hi)) { apr_hash_this(hi, (const void**)&key, &klen, (void **)&fh); apr_hash_set(merged_conf->in_filters, key, klen, (void *)fh); } for (hi = apr_hash_first(p, nc->out_filters); hi; hi=apr_hash_next(hi)) { apr_hash_this(hi, (const void**)&key, &klen, (void **)&fh); apr_hash_set(merged_conf->out_filters, key, klen, (void *)fh); } return (void *) merged_conf; } /** ** python_directive ** * Called by non-handler directives * */ static const char *python_directive(cmd_parms *cmd, void * mconfig, char *key, const char *val) { py_config *conf; conf = (py_config *) mconfig; apr_table_set(conf->directives, key, val); return NULL; } /* returns a parent if it matches the given directive */ static const ap_directive_t * find_parent(const ap_directive_t *dirp, const char *what) { while (dirp->parent != NULL) { dirp = dirp->parent; if (strcasecmp(dirp->directive, what) == 0) return dirp; } return NULL; } #ifdef WIN32 #define USE_ICASE AP_REG_ICASE #else #define USE_ICASE 0 #endif static void determine_context(apr_pool_t *p, const cmd_parms* cmd, char **d, int *d_gx, ap_regex_t **d_rx, char **l, int *l_gx, ap_regex_t **l_rx) { const ap_directive_t *context = 0; const ap_directive_t *directive = 0; const char *endp, *arg; char *directory = 0; int d_is_fnmatch = 0; ap_regex_t *d_regex = 0; char *location = 0; int l_is_fnmatch = 0; ap_regex_t *l_regex = 0; directive = cmd->directive; /* Skip any enclosing File directive if one exists */ if ((context = find_parent(directive, "args; endp = ap_strrchr_c(arg, '>'); arg = apr_pstrndup(p, arg, endp - arg); directory = ap_getword_conf(p, &arg); if (!strcmp(directory, "~")) { directory = ap_getword_conf(p, &arg); d_regex = ap_pregcomp(p, cmd->path, AP_REG_EXTENDED|USE_ICASE); } else if (ap_is_matchexp(directory)) { d_is_fnmatch = 1; } } else if ((context = find_parent(directive, "args; endp = ap_strrchr_c(arg, '>'); arg = apr_pstrndup(p, arg, endp - arg); directory = ap_getword_conf(p, &arg); d_regex = ap_pregcomp(p, directory, AP_REG_EXTENDED|USE_ICASE); } else if ((context = find_parent(directive, "args; endp = ap_strrchr_c(arg, '>'); arg = apr_pstrndup(p, arg, endp - arg); location = ap_getword_conf(p, &arg); if (!strcmp(location, "~")) { location = ap_getword_conf(p, &arg); l_regex = ap_pregcomp(p, cmd->path, AP_REG_EXTENDED|USE_ICASE); } else if (ap_is_matchexp(location)) { l_is_fnmatch = 1; } } else if ((context = find_parent(directive, "args; endp = ap_strrchr_c(arg, '>'); arg = apr_pstrndup(p, arg, endp - arg); location = ap_getword_conf(p, &arg); l_regex = ap_pregcomp(p, location, AP_REG_EXTENDED|USE_ICASE); } else if (cmd->config_file != NULL) { /* cmd->config_file is NULL when in main Apache * configuration file as the file is completely * read in before the directive is processed as * EXEC_ON_READ is not set in req_override field * of command_struct table entry. Thus know then * we are being used in a .htaccess file. */ directory = ap_make_dirstr_parent(p, directive->filename); } /* Only canonicalize path and add trailing slash at * this point if no pattern matching to be done at * a later time. */ if (directory && !d_is_fnmatch && !d_regex) { char *newpath = 0; apr_status_t rv; rv = apr_filepath_merge(&newpath, NULL, directory, APR_FILEPATH_TRUENAME, p); /* Should be able to ignore a failure as any * problem with path should have been flagged * when configuration was read in. */ if (rv == APR_SUCCESS || rv == APR_EPATHWILD) { directory = newpath; if (directory[strlen(directory) - 1] != '/') { directory = apr_pstrcat(p, directory, "/", NULL); } } } *d = directory; *d_gx = d_is_fnmatch; *d_rx = d_regex; *l = location; *l_gx = l_is_fnmatch; *l_rx = l_regex; } static void python_directive_hl_add(apr_pool_t *p, apr_hash_t *hlists, const char *phase, const char *handler, const cmd_parms* cmd, const int silent) { hl_entry *head; char *h; char *directory = 0; int d_is_fnmatch = 0; ap_regex_t *d_regex = 0; char *location = 0; int l_is_fnmatch = 0; ap_regex_t *l_regex = 0; determine_context(p, cmd, &directory, &d_is_fnmatch, &d_regex, &location, &l_is_fnmatch, &l_regex); head = (hl_entry *)apr_hash_get(hlists, phase, APR_HASH_KEY_STRING); /* it's possible that handler is multiple handlers separated by white space */ while (*(h = ap_getword_white(p, &handler)) != '\0') { if (!head) { head = hlist_new(p, h, 0, directory, d_is_fnmatch, d_regex, location, l_is_fnmatch, l_regex, silent, 0); apr_hash_set(hlists, phase, APR_HASH_KEY_STRING, head); } else { hlist_append(p, head, h, 0, directory, d_is_fnmatch, d_regex, location, l_is_fnmatch, l_regex, silent, 0); } } } /** ** python_directive_handler ** * Called by Python*Handler directives. * * When used within the same directory, this will have a * cumulative, rather than overriding effect - i.e. values * from same directives specified multiple times will be appended. * */ static const char *python_directive_handler(cmd_parms *cmd, py_config* conf, char *key, const char *val, int silent) { /* a handler may be restricted to certain file type by * extention using the "| .ext1 .ext2" syntax. When this * is the case, we will end up with a directive concatenated * with the extension, one per, e.g. * "PythonHandler foo | .ext1 .ext2" will result in * PythonHandler.ext1 foo * PythonHandler.ext2 foo */ const char *exts = val; val = ap_getword(cmd->pool, &exts, '|'); if (*exts == '\0') { python_directive_hl_add(cmd->pool, conf->hlists, key, val, cmd, silent); } else { char *ext; /* skip blanks */ while (apr_isspace(*exts)) exts++; /* repeat for every extension */ while (*(ext = ap_getword_white(cmd->pool, &exts)) != '\0') { char *s; /* append extention to the directive name */ s = apr_pstrcat(cmd->pool, key, ext, NULL); python_directive_hl_add(cmd->pool, conf->hlists, s, val, cmd, silent); } } return NULL; } /** ** python_directive_flag ** * Called for FLAG directives. * */ static const char *python_directive_flag(void * mconfig, char *key, int val) { py_config *conf; conf = (py_config *) mconfig; if (val) { apr_table_set(conf->directives, key, "1"); } else { apr_table_set(conf->directives, key, "0"); } return NULL; } static apr_status_t python_cleanup_handler(void *data); /** ** python_get_request_object ** * This creates or retrieves a previously created request object. * The pointer to request object is stored in req->request_config. */ requestobject *python_get_request_object(request_rec *req, const char *phase) { py_req_config *req_config; requestobject *request_obj = NULL; /* see if there is a request object already */ req_config = (py_req_config *) ap_get_module_config(req->request_config, &python_module); if (req_config) { request_obj = req_config->request_obj; } else { /* if ((req->path_info) && */ /* (req->path_info[strlen(req->path_info) - 1] == '/')) */ /* { */ /* int i; */ /* i = strlen(req->path_info); */ /* /\* take out the slash *\/ */ /* req->path_info[i - 1] = 0; */ /* Py_BEGIN_ALLOW_THREADS */ /* ap_add_cgi_vars(req); */ /* Py_END_ALLOW_THREADS */ /* request_obj = (requestobject *)MpRequest_FromRequest(req); */ /* if (!request_obj) return NULL; */ /* /\* put the slash back in *\/ */ /* req->path_info[i - 1] = '/'; */ /* req->path_info[i] = 0; */ /* /\* and also make PATH_INFO == req->subprocess_env *\/ */ /* apr_table_set(req->subprocess_env, "PATH_INFO", req->path_info); */ /* } */ /* else */ /* { */ Py_BEGIN_ALLOW_THREADS ap_add_cgi_vars(req); Py_END_ALLOW_THREADS request_obj = (requestobject *)MpRequest_FromRequest(req); if (!request_obj) return NULL; /* } */ /* store the pointer to this object in request_config */ req_config = apr_pcalloc(req->pool, sizeof(py_req_config)); req_config->request_obj = request_obj; req_config->dynhls = apr_hash_make(req->pool); req_config->in_filters = apr_hash_make(req->pool); req_config->out_filters = apr_hash_make(req->pool); ap_set_module_config(req->request_config, &python_module, req_config); /* register the clean up directive handler */ apr_pool_cleanup_register(req->pool, (void *)req, python_cleanup_handler, apr_pool_cleanup_null); } /* make a note of which phase we are in right now */ if (phase) { Py_XDECREF(request_obj->phase); request_obj->phase = PyString_FromString(phase); } return request_obj; } /** ** resolve_directory ** * resolve any directory match returning the matched directory */ static const char *resolve_directory(request_rec *req, const char *directory, int d_is_fnmatch, ap_regex_t *d_regex) { char *prefix; int len, dirs, i; if (!req || !req->filename || (!d_is_fnmatch && !d_regex)) return directory; dirs = ap_count_dirs(req->filename) + 1; len = strlen(req->filename); prefix = (char*)apr_palloc(req->pool, len+2); for (i=0; i<=dirs; i++) { ap_make_dirstr_prefix(prefix, req->filename, i); /* Match with trailing slash first. */ #ifdef WIN32 if (d_is_fnmatch && apr_fnmatch(directory, prefix, APR_FNM_PATHNAME|APR_FNM_CASE_BLIND) == 0) { #else if (d_is_fnmatch && apr_fnmatch(directory, prefix, APR_FNM_PATHNAME) == 0) { #endif return prefix; } else if (d_regex && ap_regexec(d_regex, prefix, 0, NULL, 0) == 0) { return prefix; } if (strcmp(prefix, "/") != 0) { prefix[strlen(prefix)-1] = '\0'; /* Match without trailing slash. */ #ifdef WIN32 if (d_is_fnmatch && apr_fnmatch(directory, prefix, APR_FNM_PATHNAME|APR_FNM_CASE_BLIND) == 0) { #else if (d_is_fnmatch && apr_fnmatch(directory, prefix, APR_FNM_PATHNAME) == 0) { #endif prefix[strlen(prefix)] = '/'; return prefix; } else if (d_regex && ap_regexec(d_regex, prefix, 0, NULL, 0) == 0) { prefix[strlen(prefix)] = '/'; return prefix; } } } return directory; } /** ** resolve_location ** * resolve any location match returning the matched location */ static const char *resolve_location(request_rec *req, const char *location, int l_is_fnmatch, ap_regex_t *l_regex) { char *prefix; int len, dirs, i; if (!req || !req->uri || (!l_is_fnmatch && !l_regex)) return location; dirs = ap_count_dirs(req->uri) + 1; len = strlen(req->uri); prefix = (char*)apr_palloc(req->pool, len+2); for (i=0; i<=dirs; i++) { int match = 0; ap_make_dirstr_prefix(prefix, req->uri, i); /* Match with trailing slash first. */ if (l_is_fnmatch && apr_fnmatch(location, prefix, APR_FNM_PATHNAME) == 0) { match = 1; } else if (l_regex && ap_regexec(l_regex, prefix, 0, NULL, 0) == 0) { match = 1; } if (strcmp(prefix, "/") != 0) { prefix[strlen(prefix)-1] = '\0'; /* Match without trailing slash. */ if (l_is_fnmatch && apr_fnmatch(location, prefix, APR_FNM_PATHNAME) == 0) { return prefix; } else if (l_regex && ap_regexec(l_regex, prefix, 0, NULL, 0) == 0) { return prefix; } if (match) { prefix[strlen(prefix)] = '/'; return prefix; } } } return location; } /** ** select_interp_name ** * (internal) * figure out the name of the interpreter we should be using * If this is for a handler, then hle is required. If this is * for a filter, then fname and is_input are required. If con * is specified, then its a connection handler. */ static const char *select_interp_name(request_rec *req, conn_rec *con, py_config *conf, hl_entry *hle, py_handler *fh) { const char *s = NULL; if ((s = apr_table_get(conf->directives, "PythonInterpreter"))) { /* forced by configuration */ return s; } else { if ((s = apr_table_get(conf->directives, "PythonInterpPerDirectory")) && (strcmp(s, "1") == 0)) { /* base interpreter on directory where the file is found */ if (req && ap_is_directory(req->pool, req->filename)) { /* Where req->filename is a directory, it is not guaranteed * that it will have a trailing slash in req->filename as * trailing slash redirection only happens in mod_dir at * the very end of the fixup phase. Thus need to ensure * that this is taken into consideration. */ if (req->filename[strlen(req->filename)-1]=='/') { return ap_make_dirstr_parent(req->pool, req->filename); } else { return ap_make_dirstr_parent(req->pool, apr_pstrcat(req->pool, req->filename, "/", NULL )); } } else { if (req && req->filename) return ap_make_dirstr_parent(req->pool, req->filename); else /* * In early phases of the request, req->filename is not known, * so this would have to run in the global interpreter. */ return NULL; } } else if ((s = apr_table_get(conf->directives, "PythonInterpPerDirective")) && (strcmp(s, "1") == 0)) { /* * base interpreter name on directory where the handler directive * was last found. If it was in http.conf, then we will use the * global interpreter. */ if (fh) { s = fh->directory; } else if (hle) { s = hle->directory; } else { return NULL; } if (s && (s[0] == '\0')) return NULL; else return s; } else { /* - default: per server - */ if (con) return con->base_server->server_hostname; else return req->server->server_hostname; } } } /** ** python_handler ** * A generic python handler. Most handlers should use this. */ static int python_handler(request_rec *req, char *phase) { PyObject *resultobject = NULL; interpreterdata *idata; requestobject *request_obj; py_config * conf; int result; const char *interp_name = NULL; char *ext = NULL; hl_entry *hle = NULL; hl_entry *dynhle = NULL; hl_entry *hlohle = NULL; py_req_config *req_conf; /* get configuration */ conf = (py_config *) ap_get_module_config(req->per_dir_config, &python_module); /* get file extension */ if (req->filename) { /* filename is null until after transhandler */ /* get rid of preceeding path */ if ((ext = (char *)ap_strrchr_c(req->filename, '/')) == NULL) ext = req->filename; else ++ext; /* get extension */ ap_getword(req->pool, (const char **)&ext, '.'); if (*ext != '\0') ext = apr_pstrcat(req->pool, ".", ext, NULL); } /* is there an hlist entry, i.e. a handler? */ /* try with extension */ if (ext) { hle = (hl_entry *)apr_hash_get(conf->hlists, apr_pstrcat(req->pool, phase, ext, NULL), APR_HASH_KEY_STRING); } /* try without extension if we don't match */ if (!hle) { hle = (hl_entry *)apr_hash_get(conf->hlists, phase, APR_HASH_KEY_STRING); /* also blank out ext since we didn't succeed with it. this is tested further below */ ext = NULL; } req_conf = (py_req_config *) ap_get_module_config(req->request_config, &python_module); if (req_conf) { dynhle = (hl_entry *)apr_hash_get(req_conf->dynhls, phase, APR_HASH_KEY_STRING); } if (! (hle || dynhle)) { /* nothing to do here */ return DECLINED; } /* construct list for the handler list object */ if (!hle) { hlohle = hlist_copy(req->pool, dynhle); } else { hlohle = hlist_copy(req->pool, hle); if (dynhle) hlist_extend(req->pool, hlohle, dynhle); } /* resolve wildcard or regex directory patterns */ hle = hlohle; while (hle) { if (hle->d_is_fnmatch || hle->d_regex) { hle->directory = resolve_directory(req, hle->directory, hle->d_is_fnmatch, hle->d_regex); hle->d_is_fnmatch = 0; hle->d_regex = NULL; } if (hle->l_is_fnmatch || hle->l_regex) { hle->location = resolve_location(req, hle->location, hle->l_is_fnmatch, hle->l_regex); hle->l_is_fnmatch = 0; hle->l_regex = NULL; } hle = hle->next; } /* determine interpreter to use */ interp_name = select_interp_name(req, NULL, conf, hlohle, NULL); /* get/create interpreter */ idata = get_interpreter(interp_name); if (!idata) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "python_handler: Can't get/create interpreter."); return HTTP_INTERNAL_SERVER_ERROR; } /* create/acquire request object */ request_obj = python_get_request_object(req, phase); /* remember the extension if any. used by publisher */ if (ext) request_obj->extension = apr_pstrdup(req->pool, ext); /* construct a new handler list object */ Py_XDECREF(request_obj->hlo); request_obj->hlo = (hlistobject *)MpHList_FromHLEntry(hlohle); /* * Here is where we call into Python! * This is the C equivalent of * >>> resultobject = obCallBack.Dispatch(request_object, phase) */ resultobject = PyObject_CallMethod(idata->obcallback, "HandlerDispatch", "O", request_obj); /* clear phase from request object */ Py_XDECREF(request_obj->phase); request_obj->phase = NULL; /* release the lock and destroy tstate*/ release_interpreter(); if (! resultobject) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "python_handler: Dispatch() returned nothing."); return HTTP_INTERNAL_SERVER_ERROR; } else { /* Attempt to analyze the result as a string indicating which result to return */ if (! PyInt_Check(resultobject)) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "python_handler: Dispatch() returned non-integer."); return HTTP_INTERNAL_SERVER_ERROR; } else { result = PyInt_AsLong(resultobject); /* authen handlers need one more thing * if authentication failed and this handler is not * authoritative, let the others handle it */ if (strcmp(phase, "PythonAuthenHandler") == 0) { /* This is a prevention measure for what is likely a bug in mod_auth.c whereby r->user is used even if null. XXX Remove in the future */ if (result == OK && !req->user) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "python_handler: After PythonAuthenHandler req->user is NULL. " "Assign something to req.user if returning OK to avoid this error."); return HTTP_INTERNAL_SERVER_ERROR; } if (result == HTTP_UNAUTHORIZED) { if (! conf->authoritative) result = DECLINED; else { /* * This will insert a WWW-Authenticate header * to let the browser know that we are using * Basic authentication. This function does check * to make sure that auth is indeed Basic, no * need to do that here. */ ap_note_basic_auth_failure(req); } } } } } /* When the script sets an error status by using req.status, * it can then either provide its own HTML error message or have * Apache provide one. To have Apache provide one, you need to send * no output and return the error from the handler function. However, * if the script is providing HTML, then the return value of the * handler should be OK, else the user will get both the script * output and the Apache output. */ /* Another note on status. req->status is used to build req->status_line * unless status_line is not NULL. req->status has no effect on how the * server will behave. The error behaviour is dictated by the return * value of this handler. When the handler returns anything other than OK, * the server will display the error that matches req->status, unless it is * 200 (HTTP_OK), in which case it will just show the error matching the return * value. If the req->status and the return of the handle do not match, * then the server will first show what req->status shows, then it will * print "Additionally, X error was recieved", where X is the return code * of the handle. If the req->status or return code is a weird number that the * server doesn't know, it will default to 500 Internal Server Error. */ /* clean up */ Py_XDECREF(resultobject); /* return the translated result (or default result) to the Server. */ return result; } /** ** python_cleanup_handler ** * Runs handler registered via PythonCleanupHandler. Clean ups * registered via register_cleanup() run in python_cleanup() above. */ static apr_status_t python_cleanup_handler(void *data) { apr_status_t rc; py_req_config *req_config; request_rec *req = (request_rec *)data; rc = python_handler((request_rec *)data, "PythonCleanupHandler"); req_config = (py_req_config *) ap_get_module_config(req->request_config, &python_module); if (req_config && req_config->request_obj) { interpreterdata *idata; requestobject *request_obj = req_config->request_obj; /* get interpreter */ idata = get_interpreter(NULL); if (!idata) return APR_SUCCESS; /* this return code is ignored by httpd anyway */ Py_XDECREF(request_obj); /* release interpreter */ release_interpreter(); } return rc; } /** ** python_connection ** * connection handler */ static apr_status_t python_connection(conn_rec *con) { PyObject *resultobject = NULL; interpreterdata *idata; connobject *conn_obj; py_config * conf; int result; const char *interp_name = NULL; hl_entry *hle = NULL; /* get configuration */ conf = (py_config *) ap_get_module_config(con->base_server->module_config, &python_module); /* is there a handler? */ hle = (hl_entry *)apr_hash_get(conf->hlists, "PythonConnectionHandler", APR_HASH_KEY_STRING); if (! hle) { /* nothing to do here */ return DECLINED; } /* determine interpreter to use */ interp_name = select_interp_name(NULL, con, conf, hle, NULL); /* get/create interpreter */ idata = get_interpreter(interp_name); if (!idata) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, con->base_server, "python_connection: Can't get/create interpreter."); return HTTP_INTERNAL_SERVER_ERROR; } /* create connection object */ conn_obj = (connobject*) MpConn_FromConn(con); /* create a handler list object */ conn_obj->hlo = (hlistobject *)MpHList_FromHLEntry(hle); /* * Here is where we call into Python! * This is the C equivalent of * >>> resultobject = obCallBack.Dispatch(request_object, phase) */ resultobject = PyObject_CallMethod(idata->obcallback, "ConnectionDispatch", "O", conn_obj); /* release the lock and destroy tstate*/ release_interpreter(); if (! resultobject) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, con->base_server, "python_connection: ConnectionDispatch() returned nothing."); return HTTP_INTERNAL_SERVER_ERROR; } else { /* Attempt to analyze the result as a string indicating which result to return */ if (! PyInt_Check(resultobject)) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, con->base_server, "python_connection: ConnectionDispatch() returned non-integer."); return HTTP_INTERNAL_SERVER_ERROR; } else result = PyInt_AsLong(resultobject); } /* clean up */ Py_XDECREF(resultobject); /* return the translated result (or default result) to the Server. */ return result; } /** ** python_filter ** * filter */ static apr_status_t python_filter(int is_input, ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_size_t readbytes) { PyObject *resultobject = NULL; interpreterdata *idata; requestobject *request_obj; py_config * conf; py_req_config * req_config; const char * interp_name = NULL; request_rec *req; filterobject *filter; python_filter_ctx *ctx; py_handler *fh; /* we only allow request level filters so far */ req = f->r; /* create ctx if not there yet */ if (!f->ctx) { ctx = (python_filter_ctx *) apr_pcalloc(req->pool, sizeof(python_filter_ctx)); f->ctx = (void *)ctx; } else { ctx = (python_filter_ctx *) f->ctx; } /* are we in transparent mode? transparent mode is on after an error, so a fitler can spit out an error without causing infinite loop */ if (ctx->transparent) { if (is_input) return ap_get_brigade(f->next, bb, mode, block, readbytes); else return ap_pass_brigade(f->next, bb); } /* get configuration */ conf = (py_config *) ap_get_module_config(req->per_dir_config, &python_module); req_config = (py_req_config *) ap_get_module_config(req->request_config, &python_module); /* the name of python function to call */ if (ctx->name) { if (is_input) fh = apr_hash_get(req_config->in_filters, ctx->name, APR_HASH_KEY_STRING); else fh = apr_hash_get(req_config->out_filters, ctx->name, APR_HASH_KEY_STRING); } else { if (is_input) fh = apr_hash_get(conf->in_filters, f->frec->name, APR_HASH_KEY_STRING); else fh = apr_hash_get(conf->out_filters, f->frec->name, APR_HASH_KEY_STRING); } if (!fh) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "python_filter: Could not find registered filter."); return HTTP_INTERNAL_SERVER_ERROR; } /* determine interpreter to use */ interp_name = select_interp_name(req, NULL, conf, NULL, fh); /* get/create interpreter */ idata = get_interpreter(interp_name); if (!idata) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "python_filter: Can't get/create interpreter."); return HTTP_INTERNAL_SERVER_ERROR; } /* create/acquire request object */ request_obj = python_get_request_object(req, 0); /* create filter */ filter = (filterobject *)MpFilter_FromFilter(f, bb, is_input, mode, readbytes, fh->handler, fh->callable, fh->directory, fh->parent); Py_INCREF(request_obj); filter->request_obj = request_obj; /* * Here is where we call into Python! * This is the C equivalent of * >>> resultobject = obCallBack.FilterDispatch(filter_object) */ resultobject = PyObject_CallMethod(idata->obcallback, "FilterDispatch", "O", filter); /* clean up */ Py_XDECREF(resultobject); /* release interpreter */ release_interpreter(); return filter->rc; } /** ** python_input_filter ** * input filter */ static apr_status_t python_input_filter(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes) { return python_filter(1, f, bb, mode, block, readbytes); } /** ** python_output_filter ** * output filter */ static apr_status_t python_output_filter(ap_filter_t *f, apr_bucket_brigade *bb) { return python_filter(0, f, bb, 0, 0, 0); } /** ** handle_python ** * handler function for mod_include tag * * The mod_include tag handler interface changed at: * * 20030821 (2.1.0-dev) bumped mod_include's entire API * * Provide a completely separate implementation for now until * it is determined whether the new SSI_CREATE_ERROR_BUCKET * macro can simply be copied to allow backward compatibility. */ #if AP_MODULE_MAGIC_AT_LEAST(20030821,0) static apr_status_t handle_python(include_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *bb) { py_config *conf; const char *interp_name = NULL; interpreterdata *idata; requestobject *request_obj; PyObject *resultobject = NULL; filterobject *filter; apr_bucket *tmp_buck; char *file = f->r->filename; char *tag = NULL; char *tag_val = NULL; PyObject *tagobject = NULL; PyObject *codeobject = NULL; request_rec *req = f->r; if (!(ctx->flags & SSI_FLAG_PRINTING)) { return APR_SUCCESS; } if (ctx->flags & SSI_FLAG_NO_EXEC) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "#python used but not allowed in %s", file); SSI_CREATE_ERROR_BUCKET(ctx, f, bb); return APR_SUCCESS; } /* process tags */ while (1) { optfn_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); if (!tag || !tag_val) break; if (!strlen(tag_val)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "empty value for '%s' parameter to tag 'python' in %s", tag, file); SSI_CREATE_ERROR_BUCKET(ctx, f, bb); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return APR_SUCCESS; } if (!strcmp(tag, "eval") || !strcmp(tag, "exec")) { if (tagobject) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "multiple 'eval/exec' parameters to tag 'python' in %s", file); SSI_CREATE_ERROR_BUCKET(ctx, f, bb); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return APR_SUCCESS; } tagobject = PyString_FromString(tag); codeobject = PyString_FromString(tag_val); } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "unexpected '%s' parameter to tag 'python' in %s", tag, file); SSI_CREATE_ERROR_BUCKET(ctx, f, bb); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return APR_SUCCESS; } } if (!tagobject) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "missing 'eval/exec' parameter to tag 'python' in %s", file); SSI_CREATE_ERROR_BUCKET(ctx, f, bb); return APR_SUCCESS; } /* get configuration */ conf = (py_config *) ap_get_module_config(req->per_dir_config, &python_module); /* determine interpreter to use */ interp_name = select_interp_name(req, NULL, conf, NULL, NULL); /* get/create interpreter */ idata = get_interpreter(interp_name); if (!idata) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "handle_python: Can't get/create interpreter."); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return HTTP_INTERNAL_SERVER_ERROR; } /* create/acquire request object */ request_obj = python_get_request_object(req, 0); /* create filter */ filter = (filterobject *)MpFilter_FromFilter(f, bb, 0, 0, 0, 0, 0, 0, 0); Py_INCREF(request_obj); filter->request_obj = request_obj; /* * Here is where we call into Python! */ resultobject = PyObject_CallMethod(idata->obcallback, "IncludeDispatch", "OOO", filter, tagobject, codeobject); if (!resultobject) { SSI_CREATE_ERROR_BUCKET(ctx, f, bb); release_interpreter(); return APR_SUCCESS; } /* clean up */ Py_XDECREF(resultobject); /* release interpreter */ release_interpreter(); return filter->rc; } #else static apr_status_t handle_python(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r_bogus, ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head) { py_config *conf; const char *interp_name = NULL; interpreterdata *idata; requestobject *request_obj; PyObject *resultobject = NULL; filterobject *filter; apr_bucket *tmp_buck; char *file = f->r->filename; char *tag = NULL; char *tag_val = NULL; PyObject *tagobject = NULL; PyObject *codeobject = NULL; request_rec *req = f->r; if (!(ctx->flags & FLAG_PRINTING)) { return APR_SUCCESS; } if (ctx->flags & FLAG_NO_EXEC) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "#python used but not allowed in %s", file); CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); return APR_SUCCESS; } /* process tags */ while (1) { optfn_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1); if (!tag || !tag_val) break; if (!strlen(tag_val)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "empty value for '%s' parameter to tag 'python' in %s", tag, file); CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return APR_SUCCESS; } if (!strcmp(tag, "eval") || !strcmp(tag, "exec")) { if (tagobject) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "multiple 'eval/exec' parameters to tag 'python' in %s", file); CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return APR_SUCCESS; } tagobject = PyString_FromString(tag); codeobject = PyString_FromString(tag_val); } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "unexpected '%s' parameter to tag 'python' in %s", tag, file); CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return APR_SUCCESS; } } if (!tagobject) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "missing 'eval/exec' parameter to tag 'python' in %s", file); CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); return APR_SUCCESS; } /* get configuration */ conf = (py_config *) ap_get_module_config(req->per_dir_config, &python_module); /* determine interpreter to use */ interp_name = select_interp_name(req, NULL, conf, NULL, NULL); /* get/create interpreter */ idata = get_interpreter(interp_name); if (!idata) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, req, "handle_python: Can't get/create interpreter."); Py_XDECREF(tagobject); Py_XDECREF(codeobject); return HTTP_INTERNAL_SERVER_ERROR; } /* create/acquire request object */ request_obj = python_get_request_object(req, 0); /* create filter */ filter = (filterobject *)MpFilter_FromFilter(f, *bb, 0, 0, 0, 0, 0, 0, 0); Py_INCREF(request_obj); filter->request_obj = request_obj; /* * Here is where we call into Python! */ resultobject = PyObject_CallMethod(idata->obcallback, "IncludeDispatch", "OOO", filter, tagobject, codeobject); if (!resultobject) { CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head); release_interpreter(); return APR_SUCCESS; } /* clean up */ Py_XDECREF(resultobject); /* release interpreter */ release_interpreter(); return filter->rc; } #endif /** ** directive_PythonImport ** * This function called whenever PythonImport directive * is encountered. Note that this function does not actually * import anything, it just remembers what needs to be imported. * The actual importing is done later * in the ChildInitHandler. This is because this function here * is called before the python_init and before the suid and fork. * */ static const char *directive_PythonImport(cmd_parms *cmd, void *mconfig, const char *module, const char *interp_name) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); if (!conf->imports) conf->imports = apr_table_make(cmd->pool, 4); apr_table_add(conf->imports, interp_name, module); return NULL; } /** ** directive_PythonPath ** * This function called whenever PythonPath directive * is encountered. */ static const char *directive_PythonPath(cmd_parms *cmd, void *mconfig, const char *val) { const char *rc = python_directive(cmd, mconfig, "PythonPath", val); if (!cmd->path) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); return python_directive(cmd, conf, "PythonPath", val); } return rc; } /** ** directive_PythonInterpreter ** * This function called whenever PythonInterpreter directive * is encountered. */ static const char *directive_PythonInterpreter(cmd_parms *cmd, void *mconfig, const char *val) { const char *rc = python_directive(cmd, mconfig, "PythonInterpreter", val); if (!cmd->path) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); return python_directive(cmd, conf, "PythonInterpreter", val); } return rc; } /** ** directive_PythonDebug ** * This function called whenever PythonDebug directive * is encountered. */ static const char *directive_PythonDebug(cmd_parms *cmd, void *mconfig, int val) { const char *rc = python_directive_flag(mconfig, "PythonDebug", val); if (!cmd->path) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); return python_directive_flag(conf, "PythonDebug", val); } return rc; } /** ** directive_PythonEnablePdb ** * This function called whenever PythonEnablePdb directive * is encountered. */ static const char *directive_PythonEnablePdb(cmd_parms *cmd, void *mconfig, int val) { const char *rc = python_directive_flag(mconfig, "PythonEnablePdb", val); if (!cmd->path) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); return python_directive_flag(conf, "PythonEnablePdb", val); } return rc; } /** ** directive_PythonInterpPerDirective ** * This function called whenever PythonInterpPerDirective directive * is encountered. */ static const char *directive_PythonInterpPerDirective(cmd_parms *cmd, void *mconfig, int val) { const char *rc = python_directive_flag(mconfig, "PythonInterpPerDirective", val); if (!cmd->path) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); return python_directive_flag(conf, "PythonInterpPerDirective", val); } return rc; } /** ** directive_PythonInterpPerDirectory ** * This function called whenever PythonInterpPerDirectory directive * is encountered. */ static const char *directive_PythonInterpPerDirectory(cmd_parms *cmd, void *mconfig, int val) { return python_directive_flag(mconfig, "PythonInterpPerDirectory", val); } /** ** directive_PythonAutoReload ** * This function called whenever PythonAutoReload directive * is encountered. */ static const char *directive_PythonAutoReload(cmd_parms *cmd, void *mconfig, int val) { const char *rc = python_directive_flag(mconfig, "PythonAutoReload", val); if (!cmd->path) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); return python_directive_flag(conf, "PythonAutoReload", val); } return rc; } /** ** directive_PythonOption ** * This function is called every time PythonOption directive * is encountered. It sticks the option into a table containing * a list of options. This table is part of the local config structure. */ static const char *directive_PythonOption(cmd_parms *cmd, void * mconfig, const char *key, const char *val) { py_config *conf; conf = (py_config *) mconfig; if(val!=NULL) { apr_table_set(conf->options, key, val); if (!cmd->path) { conf = ap_get_module_config(cmd->server->module_config, &python_module); apr_table_set(conf->options, key, val); } } else { /** We don't remove the value, but set it to an empty string. There is no possibility of colliding with an actual value, since an entry string precisely means 'remove the value' */ apr_table_set(conf->options, key, ""); if (!cmd->path) { conf = ap_get_module_config(cmd->server->module_config, &python_module); apr_table_set(conf->options, key, ""); } } return NULL; } /** ** directive_PythonOptimize ** * This function called whenever PythonOptimize directive * is encountered. */ static const char *directive_PythonOptimize(cmd_parms *cmd, void *mconfig, int val) { if ((val) && (Py_OptimizeFlag != 2)) Py_OptimizeFlag = 2; return NULL; } /** ** Python*Handler directives ** */ static const char *directive_PythonAccessHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonAccessHandler", val, NOTSILENT); } static const char *directive_PythonAuthenHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonAuthenHandler", val, NOTSILENT); } static const char *directive_PythonAuthzHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonAuthzHandler", val, NOTSILENT); } static const char *directive_PythonCleanupHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonCleanupHandler", val, NOTSILENT); } static const char *directive_PythonConnectionHandler(cmd_parms *cmd, void *mconfig, const char *val) { py_config *conf = ap_get_module_config(cmd->server->module_config, &python_module); return python_directive_handler(cmd, conf, "PythonConnectionHandler", val, NOTSILENT); } static const char *directive_PythonFixupHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonFixupHandler", val, NOTSILENT); } static const char *directive_PythonHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonHandler", val, NOTSILENT); } static const char *directive_PythonHeaderParserHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonHeaderParserHandler", val, NOTSILENT); } static const char *directive_PythonInitHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonInitHandler", val, NOTSILENT); } static const char *directive_PythonHandlerModule(cmd_parms *cmd, void *mconfig, const char *val) { /* * This handler explodes into all other handlers, but their absense will be * silently ignored. */ /* * XXX Not used at present. See problems noted against connection * handler below. * py_config *srv_conf = ap_get_module_config(cmd->server->module_config, &python_module); */ python_directive_handler(cmd, mconfig, "PythonPostReadRequestHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonTransHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonHeaderParserHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonAccessHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonAuthenHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonAuthzHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonTypeHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonFixupHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonInitHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonLogHandler", val, SILENT); python_directive_handler(cmd, mconfig, "PythonCleanupHandler", val, SILENT); /* * XXX There is a bug here with PythonConnectionHandler which can * cause an infinite loop when the handler is added to the handler * list. Cause is unknown so simply disable it for now. If someone * really needs a connection handler, they can use the directive * PythonConnectionHandler explicitly still and not rely on the * PythonHandlerModule directive doing it automatically. * python_directive_handler(cmd, srv_conf, "PythonConnectionHandler", val, SILENT); */ return NULL; } static const char *directive_PythonPostReadRequestHandler(cmd_parms *cmd, void * mconfig, const char *val) { if (strchr((char *)val, '|')) return "PythonPostReadRequestHandler does not accept \"| .ext\" syntax."; return python_directive_handler(cmd, mconfig, "PythonPostReadRequestHandler", val,NOTSILENT); } static const char *directive_PythonTransHandler(cmd_parms *cmd, void *mconfig, const char *val) { if (strchr((char *)val, '|')) return "PythonTransHandler does not accept \"| .ext\" syntax."; return python_directive_handler(cmd, mconfig, "PythonTransHandler", val, NOTSILENT); } static const char *directive_PythonTypeHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonTypeHandler", val, NOTSILENT); } static const char *directive_PythonLogHandler(cmd_parms *cmd, void *mconfig, const char *val) { return python_directive_handler(cmd, mconfig, "PythonLogHandler", val, NOTSILENT); } static const char *directive_PythonInputFilter(cmd_parms *cmd, void *mconfig, const char *handler, const char *name) { py_config *conf; py_handler *fh; ap_filter_rec_t *frec; char *directory = 0; int d_is_fnmatch = 0; ap_regex_t *d_regex = 0; char *location = 0; int l_is_fnmatch = 0; ap_regex_t *l_regex = 0; if (!name) name = apr_pstrdup(cmd->pool, handler); /* register the filter NOTE - this only works so long as the directive is only allowed in the main config. For .htaccess we would have to make sure not to duplicate this */ frec = ap_register_input_filter(name, python_input_filter, NULL, AP_FTYPE_RESOURCE); conf = (py_config *) mconfig; determine_context(cmd->pool, cmd, &directory, &d_is_fnmatch, &d_regex, &location, &l_is_fnmatch, &l_regex); fh = (py_handler *) apr_pcalloc(cmd->pool, sizeof(py_handler)); fh->handler = (char *)handler; fh->directory = directory; fh->d_is_fnmatch = d_is_fnmatch; fh->d_regex = d_regex; fh->location = location; fh->l_is_fnmatch = l_is_fnmatch; fh->l_regex = l_regex; apr_hash_set(conf->in_filters, frec->name, APR_HASH_KEY_STRING, fh); return NULL; } static const char *directive_PythonOutputFilter(cmd_parms *cmd, void *mconfig, const char *handler, const char *name) { py_config *conf; py_handler *fh; ap_filter_rec_t *frec; char *directory = 0; int d_is_fnmatch = 0; ap_regex_t *d_regex = 0; char *location = 0; int l_is_fnmatch = 0; ap_regex_t *l_regex = 0; if (!name) name = apr_pstrdup(cmd->pool, handler); /* register the filter NOTE - this only works so long as the directive is only allowed in the main config. For .htaccess we would have to make sure not to duplicate this */ frec = ap_register_output_filter(name, python_output_filter, NULL, AP_FTYPE_RESOURCE); determine_context(cmd->pool, cmd, &directory, &d_is_fnmatch, &d_regex, &location, &l_is_fnmatch, &l_regex); conf = (py_config *) mconfig; fh = (py_handler *) apr_pcalloc(cmd->pool, sizeof(py_handler)); fh->handler = (char *)handler; fh->directory = directory; fh->d_is_fnmatch = d_is_fnmatch; fh->d_regex = d_regex; fh->location = location; fh->l_is_fnmatch = l_is_fnmatch; fh->l_regex = l_regex; apr_hash_set(conf->out_filters, frec->name, APR_HASH_KEY_STRING, fh); return NULL; } /** ** python_finalize ** * We create a thread state just so we can run Py_Finalize() */ static apr_status_t python_finalize(void *data) { interpreterdata *idata; idata = get_interpreter(NULL); if (idata) { Py_Finalize(); #ifdef WITH_THREAD PyEval_ReleaseLock(); #endif } return APR_SUCCESS; } /** ** Handlers ** */ static void PythonChildInitHandler(apr_pool_t *p, server_rec *s) { const apr_array_header_t *ah; apr_table_entry_t *elts; int i; py_config *conf = ap_get_module_config(s->module_config, &python_module); py_global_config *glb; PyObject *resultobject = NULL; /* accordig Py C Docs we must do this after forking */ #ifdef WITH_THREAD PyEval_AcquireLock(); #endif PyOS_AfterFork(); save_interpreter(MAIN_INTERPRETER, PyThreadState_Get()->interp); PyThreadState_Swap(NULL); #ifdef WITH_THREAD PyEval_ReleaseLock(); #endif /* * Cleanups registered first will be called last. This will * end the Python interpreter *after* all other cleanups. */ /* * XXX Trying to cleanup Python on process shutdown causes * problems. This seems to mainly be an issue where there * are user created threads which are running in parallel as * the environment they are running in will be destroyed * from underneath them potentially resulting in crashes, * process hangs or simply Python errors. There is also a * small chance that finalization code can be called within * a signal handler in some configurations which could cause * problems as well. Thus disable cleanup of Python when * child processes are being shutdown. (MODPYTHON-109) * apr_pool_cleanup_register(p, NULL, python_finalize, apr_pool_cleanup_null); */ /* * Reinit mutexes */ /* this will return it if it already exists */ glb = python_create_global_config(s); reinit_mutexes(s, p, glb); /* * remember the pool in a global var. we may use it * later in server.register_cleanup() */ child_init_pool = p; /* register python handler for mod_include. could probably * also have done this in python_init() instead */ optfn_register_include_handler = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler); optfn_ssi_get_tag_and_value = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value); optfn_ssi_parse_string = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string); if (optfn_register_include_handler && optfn_ssi_get_tag_and_value && optfn_ssi_parse_string) { optfn_register_include_handler("python", handle_python); } /* * Now run PythonImports */ if (conf->imports) { ah = apr_table_elts (conf->imports); elts = (apr_table_entry_t *) ah->elts; i = ah->nelts; while (i--) { if (elts[i].key) { interpreterdata *idata; const char *interp_name = elts[i].key; const char *module_name = elts[i].val; /* get interpreter */ idata = get_interpreter(interp_name); if (!idata) return; /* * Call into Python to do import. * This is the C equivalent of * >>> resultobject = obCallBack.ImportDispatch(module_name) */ resultobject = PyObject_CallMethod(idata->obcallback, "ImportDispatch", "s", module_name); if (!resultobject) { if (PyErr_Occurred()) { PyErr_Print(); fflush(stderr); } ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, s, "directive_PythonImport: error importing %s", (!module_name) ? "" : module_name); } /* clean up */ Py_XDECREF(resultobject); /* release interpreter */ release_interpreter(); } } } } static int PythonConnectionHandler(conn_rec *con) { return python_connection(con); } static int PythonAccessHandler(request_rec *req) { return python_handler(req, "PythonAccessHandler"); } static int PythonAuthenHandler(request_rec *req) { return python_handler(req, "PythonAuthenHandler"); } static int PythonAuthzHandler(request_rec *req) { return python_handler(req, "PythonAuthzHandler"); } static int PythonFixupHandler(request_rec *req) { return python_handler(req, "PythonFixupHandler"); } static int PythonHandler(request_rec *req) { /* * In Apache 2.0, all handlers receive a request and have * a chance to process them. Therefore, we need to only * handle those that we explicitly agreed to handle (see * above). */ if (!req->handler || (strcmp(req->handler, "mod_python") && strcmp(req->handler, "python-program"))) return DECLINED; return python_handler(req, "PythonHandler"); } static int PythonHeaderParserHandler(request_rec *req) { int rc; /* run PythonInitHandler, if not already */ if (! apr_table_get(req->notes, "python_init_ran")) { rc = python_handler(req, "PythonInitHandler"); if ((rc != OK) && (rc != DECLINED)) return rc; } return python_handler(req, "PythonHeaderParserHandler"); } static int PythonLogHandler(request_rec *req) { return python_handler(req, "PythonLogHandler"); } static int PythonPostReadRequestHandler(request_rec *req) { int rc; /* run PythonInitHandler */ rc = python_handler(req, "PythonInitHandler"); apr_table_set(req->notes, "python_init_ran", "1"); if ((rc != OK) && (rc != DECLINED)) return rc; return python_handler(req, "PythonPostReadRequestHandler"); } static int PythonTransHandler(request_rec *req) { return python_handler(req, "PythonTransHandler"); } static int PythonTypeHandler(request_rec *req) { return python_handler(req, "PythonTypeHandler"); } static void python_register_hooks(apr_pool_t *p) { /* module initializer */ ap_hook_post_config(python_init, NULL, NULL, APR_HOOK_MIDDLE); /* [0] raw connection handling */ ap_hook_process_connection(PythonConnectionHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [1] post read_request handling */ ap_hook_post_read_request(PythonPostReadRequestHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [2] filename-to-URI translation */ ap_hook_translate_name(PythonTransHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [3] header parser */ ap_hook_header_parser(PythonHeaderParserHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [4] check access by host address */ ap_hook_access_checker(PythonAccessHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [5] check/validate user_id */ ap_hook_check_user_id(PythonAuthenHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [6] check user_id is valid *here* */ ap_hook_auth_checker(PythonAuthzHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [7] MIME type checker/setter */ ap_hook_type_checker(PythonTypeHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [8] fixups */ ap_hook_fixups(PythonFixupHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [9] filter insert opportunity */ /* ap_hook_insert_filter(PythonInsertFilter, NULL, NULL, APR_HOOK_MIDDLE); */ /* [10] is for the handlers; see below */ ap_hook_handler(PythonHandler, NULL, NULL, APR_HOOK_MIDDLE); /* [11] logger */ ap_hook_log_transaction(PythonLogHandler, NULL, NULL, APR_HOOK_MIDDLE); /* dynamic input/output filter entry points */ ap_register_input_filter(FILTER_NAME, python_input_filter, NULL, AP_FTYPE_RESOURCE); ap_register_output_filter(FILTER_NAME, python_output_filter, NULL, AP_FTYPE_RESOURCE); /* process initializer */ ap_hook_child_init(PythonChildInitHandler, NULL, NULL, APR_HOOK_MIDDLE); } /* command table */ command_rec python_commands[] = { AP_INIT_RAW_ARGS( "PythonAccessHandler", directive_PythonAccessHandler, NULL, OR_ALL, "Python access by host address handlers."), AP_INIT_RAW_ARGS( "PythonAuthenHandler", directive_PythonAuthenHandler, NULL, OR_ALL, "Python authentication handlers."), AP_INIT_FLAG( "PythonAutoReload", directive_PythonAutoReload, NULL, OR_ALL, "Set to Off if you don't want changed modules to reload."), AP_INIT_RAW_ARGS( "PythonAuthzHandler", directive_PythonAuthzHandler, NULL, OR_ALL, "Python authorization handlers."), AP_INIT_RAW_ARGS( "PythonCleanupHandler", directive_PythonCleanupHandler, NULL, OR_ALL, "Python clean up handlers."), AP_INIT_RAW_ARGS( "PythonConnectionHandler", directive_PythonConnectionHandler, NULL, RSRC_CONF, "Python connection handlers."), AP_INIT_FLAG( "PythonDebug", directive_PythonDebug, NULL, OR_ALL, "Send (most) Python error output to the client rather than logfile."), AP_INIT_FLAG( "PythonEnablePdb", directive_PythonEnablePdb, NULL, OR_ALL, "Run handlers in PDB (Python Debugger). Use with -DONE_PROCESS."), AP_INIT_RAW_ARGS( "PythonFixupHandler", directive_PythonFixupHandler, NULL, OR_ALL, "Python fixups handlers."), AP_INIT_RAW_ARGS( "PythonHandler", directive_PythonHandler, NULL, OR_ALL, "Python request handlers."), AP_INIT_RAW_ARGS( "PythonHeaderParserHandler", directive_PythonHeaderParserHandler, NULL, OR_ALL, "Python header parser handlers."), AP_INIT_TAKE2( "PythonImport", directive_PythonImport, NULL, RSRC_CONF, "Module and interpreter name to be imported at server/child init time."), AP_INIT_RAW_ARGS( "PythonInitHandler", directive_PythonInitHandler, NULL, OR_ALL, "Python request initialization handler."), AP_INIT_FLAG( "PythonInterpPerDirective", directive_PythonInterpPerDirective, NULL, OR_ALL, "Create subinterpreters per directive."), AP_INIT_FLAG( "PythonInterpPerDirectory", directive_PythonInterpPerDirectory, NULL, OR_ALL, "Create subinterpreters per directory."), AP_INIT_TAKE1( "PythonInterpreter", directive_PythonInterpreter, NULL, OR_ALL, "Forces a specific Python interpreter name to be used here."), AP_INIT_RAW_ARGS( "PythonLogHandler", directive_PythonLogHandler, NULL, OR_ALL, "Python logger handlers."), AP_INIT_RAW_ARGS( "PythonHandlerModule", directive_PythonHandlerModule, NULL, OR_ALL, "A Python module containing handlers to be executed."), AP_INIT_FLAG( "PythonOptimize", directive_PythonOptimize, NULL, RSRC_CONF, "Set the equivalent of the -O command-line flag on the interpreter."), AP_INIT_TAKE12( "PythonOption", directive_PythonOption, NULL, OR_ALL, "Useful to pass custom configuration information to scripts."), AP_INIT_TAKE1( "PythonPath", directive_PythonPath, NULL, OR_ALL, "Python path, specified in Python list syntax."), AP_INIT_RAW_ARGS( "PythonPostReadRequestHandler", directive_PythonPostReadRequestHandler, NULL, RSRC_CONF, "Python post read-request handlers."), AP_INIT_RAW_ARGS( "PythonTransHandler", directive_PythonTransHandler, NULL, RSRC_CONF, "Python filename to URI translation handlers."), AP_INIT_RAW_ARGS( "PythonTypeHandler", directive_PythonTypeHandler, NULL, OR_ALL, "Python MIME type checker/setter handlers."), AP_INIT_TAKE12( "PythonInputFilter", directive_PythonInputFilter, NULL, RSRC_CONF|ACCESS_CONF, "Python input filter."), AP_INIT_TAKE12( "PythonOutputFilter", directive_PythonOutputFilter, NULL, RSRC_CONF|ACCESS_CONF, "Python output filter."), {NULL} }; module python_module = { STANDARD20_MODULE_STUFF, python_create_dir_config, /* per-directory config creator */ python_merge_config, /* dir config merger */ python_create_srv_config, /* server config creator */ python_merge_config, /* server config merger */ python_commands, /* command table */ python_register_hooks /* register hooks */ }; mod_python-3.3.1/src/hlist.c0000644000175000017500000001057710517305602014105 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * hlist.c * * $Id: hlist.c 467228 2006-10-24 03:41:54Z grahamd $ * * See accompanying documentation and source code comments * for details. * */ #include "mod_python.h" /** ** hlist_new ** * Start a new list. */ hl_entry *hlist_new(apr_pool_t *p, const char *h, PyObject *o, const char *d, int d_is_fnmatch, ap_regex_t *d_regex, const char *l, int l_is_fnmatch, ap_regex_t *l_regex, const int s, hl_entry* parent) { hl_entry *hle; hle = (hl_entry *)apr_pcalloc(p, sizeof(hl_entry)); hle->handler = h; hle->callable = o; hle->directory = d; hle->d_is_fnmatch = d_is_fnmatch; hle->d_regex = d_regex; hle->location = l; hle->l_is_fnmatch = l_is_fnmatch; hle->l_regex = l_regex; hle->silent = s; hle->parent = parent; return hle; } /** ** hlist_append ** * Appends an hl_entry to a list identified by hle, * and returns the new tail. This func will skip * to the tail of the list. * If hle is NULL, a new list is created. */ hl_entry *hlist_append(apr_pool_t *p, hl_entry *hle, const char * h, PyObject *o, const char *d, int d_is_fnmatch, ap_regex_t *d_regex, const char *l, int l_is_fnmatch, ap_regex_t *l_regex, const int s, hl_entry *parent) { hl_entry *nhle; /* find tail */ while (hle && hle->next) hle = hle->next; nhle = (hl_entry *)apr_pcalloc(p, sizeof(hl_entry)); nhle->handler = h; nhle->callable = o; nhle->directory = d; nhle->d_is_fnmatch = d_is_fnmatch; nhle->d_regex = d_regex; nhle->location = l; nhle->l_is_fnmatch = l_is_fnmatch; nhle->l_regex = l_regex; nhle->silent = s; nhle->parent = parent; if (hle) hle->next = nhle; return nhle; } /** ** hlist_copy ** */ hl_entry *hlist_copy(apr_pool_t *p, const hl_entry *hle) { hl_entry *nhle; hl_entry *head; head = (hl_entry *)apr_pcalloc(p, sizeof(hl_entry)); head->handler = hle->handler; head->callable = hle->callable; head->directory = hle->directory; head->d_is_fnmatch = hle->d_is_fnmatch; head->d_regex = hle->d_regex; head->location = hle->location; head->l_is_fnmatch = hle->l_is_fnmatch; head->l_regex = hle->l_regex; head->silent = hle->silent; head->parent = hle->parent; hle = hle->next; nhle = head; while (hle) { nhle->next = (hl_entry *)apr_pcalloc(p, sizeof(hl_entry)); nhle = nhle->next; nhle->handler = hle->handler; nhle->callable = hle->callable; nhle->directory = hle->directory; nhle->d_is_fnmatch = hle->d_is_fnmatch; nhle->d_regex = hle->d_regex; nhle->location = hle->location; nhle->l_is_fnmatch = hle->l_is_fnmatch; nhle->l_regex = hle->l_regex; nhle->silent = hle->silent; nhle->parent = hle->parent; hle = hle->next; } return head; } /** ** hlist_extend ** */ void hlist_extend(apr_pool_t *p, hl_entry *hle1, const hl_entry *hle2) { if (!hle2) return; /* find tail */ while (hle1 && hle1->next) hle1 = hle1->next; while (hle2) { hle1->next = (hl_entry *)apr_pcalloc(p, sizeof(hl_entry)); hle1 = hle1->next; hle1->handler = hle2->handler; hle1->callable = hle2->callable; hle1->directory = hle2->directory; hle1->d_is_fnmatch = hle2->d_is_fnmatch; hle1->d_regex = hle2->d_regex; hle1->location = hle2->location; hle1->l_is_fnmatch = hle2->l_is_fnmatch; hle1->l_regex = hle2->l_regex; hle1->silent = hle2->silent; hle1->parent = hle2->parent; hle2 = hle2->next; } } mod_python-3.3.1/src/connobject.c0000644000175000017500000002775510534452125015116 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * connobject.c * * $Id: connobject.c 481717 2006-12-03 04:36:37Z grahamd $ * */ /* * This is a mapping of a Python object to an Apache conn_rec. * */ #include "mod_python.h" /** ** MpConn_FromConn ** * This routine creates a Python connobject given an Apache * conn_rec pointer. * */ PyObject * MpConn_FromConn(conn_rec *c) { connobject *result; result = PyObject_New(connobject, &MpConn_Type); if (! result) return PyErr_NoMemory(); result->conn = c; result->base_server = NULL; result->notes = MpTable_FromTable(c->notes); result->hlo = NULL; return (PyObject *)result; } /** ** conn.log_error(conn self, string message, int level) ** * calls ap_log_cerror */ static PyObject * conn_log_error(connobject *self, PyObject *args) { int level = 0; char *message = NULL; if (! PyArg_ParseTuple(args, "z|i", &message, &level)) return NULL; /* error */ if (message) { if (! level) level = APLOG_NOERRNO|APLOG_ERR; #if AP_MODULE_MAGIC_AT_LEAST(20020903,10) ap_log_cerror(APLOG_MARK, level, 0, self->conn, "%s", message); #else ap_log_error(APLOG_MARK, level, 0, self->conn->base_server, "%s", message); #endif } Py_INCREF(Py_None); return Py_None; } /** ** conn.read(conn self, int bytes) ** */ static PyObject * _conn_read(conn_rec *c, ap_input_mode_t mode, long len) { apr_bucket *b; apr_bucket_brigade *bb; apr_status_t rc; long bytes_read; PyObject *result; char *buffer; long bufsize; bb = apr_brigade_create(c->pool, c->bucket_alloc); bufsize = len == 0 ? HUGE_STRING_LEN : len; while (APR_BRIGADE_EMPTY(bb)) { Py_BEGIN_ALLOW_THREADS; rc = ap_get_brigade(c->input_filters, bb, mode, APR_BLOCK_READ, bufsize); Py_END_ALLOW_THREADS; if (rc != APR_SUCCESS) { PyErr_SetObject(PyExc_IOError, PyString_FromString("Connection read error")); return NULL; } } /* * loop through the brigade reading buckets into the string */ b = APR_BRIGADE_FIRST(bb); if (APR_BUCKET_IS_EOS(b)) { apr_bucket_delete(b); Py_INCREF(Py_None); return Py_None; } /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ result = PyString_FromStringAndSize(NULL, bufsize); /* possibly no more memory */ if (result == NULL) return PyErr_NoMemory(); buffer = PyString_AS_STRING((PyStringObject *) result); bytes_read = 0; while ((bytes_read < len || len == 0) && !(b == APR_BRIGADE_SENTINEL(b) || APR_BUCKET_IS_EOS(b) || APR_BUCKET_IS_FLUSH(b))) { const char *data; apr_size_t size; apr_bucket *old; if (apr_bucket_read(b, &data, &size, APR_BLOCK_READ) != APR_SUCCESS) { PyErr_SetObject(PyExc_IOError, PyString_FromString("Connection read error")); return NULL; } if (bytes_read + size > bufsize) { apr_bucket_split(b, bufsize - bytes_read); size = bufsize - bytes_read; /* now the bucket is the exact size we need */ } memcpy(buffer, data, size); buffer += size; bytes_read += size; /* time to grow destination string? */ if (len == 0 && bytes_read == bufsize) { /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ _PyString_Resize(&result, bufsize + HUGE_STRING_LEN); buffer = PyString_AS_STRING((PyStringObject *) result); buffer += bufsize; bufsize += HUGE_STRING_LEN; } if (mode == AP_MODE_GETLINE || len == 0) { apr_bucket_delete(b); break; } old = b; b = APR_BUCKET_NEXT(b); apr_bucket_delete(old); } /* resize if necessary */ if (bytes_read < len || len == 0) /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ if(_PyString_Resize(&result, bytes_read)) return NULL; return result; } /** ** conn.read(conn self, int bytes) ** */ static PyObject * conn_read(connobject *self, PyObject *args) { long len = 0; if (! PyArg_ParseTuple(args, "|l", &len)) return NULL; if (len == -1) return _conn_read(self->conn, AP_MODE_EXHAUSTIVE, 0); else return _conn_read(self->conn, AP_MODE_READBYTES, len); } /** ** conn.readline(conn self, int bytes) ** */ static PyObject * conn_readline(connobject *self, PyObject *args) { long len = 0; if (! PyArg_ParseTuple(args, "|l", &len)) return NULL; return _conn_read(self->conn, AP_MODE_GETLINE, len); } /** ** conn.write(conn self, int bytes) ** */ static PyObject * conn_write(connobject *self, PyObject *args) { char *buff; int len; apr_bucket_brigade *bb; apr_bucket *b; PyObject *s; conn_rec *c = self->conn; if (! PyArg_ParseTuple(args, "O", &s)) return NULL; if (! PyString_Check(s)) { PyErr_SetString(PyExc_TypeError, "Argument to write() must be a string"); return NULL; } /* PYTHON 2.5: 'PyString_Size' uses Py_ssize_t for return values (may need overflow check) */ len = PyString_Size(s); if (len) { buff = apr_pmemdup(c->pool, PyString_AS_STRING(s), len); bb = apr_brigade_create(c->pool, c->bucket_alloc); b = apr_bucket_pool_create(buff, len, c->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); /* Make sure the data is flushed to the client */ b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); ap_pass_brigade(c->output_filters, bb); } Py_INCREF(Py_None); return Py_None; } static PyMethodDef connobjectmethods[] = { {"log_error", (PyCFunction) conn_log_error, METH_VARARGS}, {"read", (PyCFunction) conn_read, METH_VARARGS}, {"readline", (PyCFunction) conn_readline, METH_VARARGS}, {"write", (PyCFunction) conn_write, METH_VARARGS}, { NULL, NULL } /* sentinel */ }; #define OFF(x) offsetof(conn_rec, x) static struct memberlist conn_memberlist[] = { {"base_server", T_OBJECT, 0, RO}, /* XXX vhost_lookup_data? */ /* XXX client_socket? */ {"local_addr", T_OBJECT, 0, RO}, {"remote_addr", T_OBJECT, 0, RO}, {"remote_ip", T_STRING, OFF(remote_ip), RO}, {"remote_host", T_STRING, OFF(remote_host), RO}, {"remote_logname", T_STRING, OFF(remote_logname), RO}, {"aborted", T_INT, 0, RO}, {"keepalive", T_INT, 0, RO}, {"double_reverse", T_INT, 0, RO}, {"keepalives", T_INT, OFF(keepalives), RO}, {"local_ip", T_STRING, OFF(local_ip), RO}, {"local_host", T_STRING, OFF(local_host), RO}, {"id", T_LONG, OFF(id), RO}, /* XXX conn_config? */ {"notes", T_OBJECT, 0, RO}, /* XXX filters ? */ /* XXX document remain */ /*{"remain", T_LONG, OFF(remain), RO},*/ {NULL} /* Sentinel */ }; /** ** conn_dealloc ** * */ static void conn_dealloc(connobject *self) { Py_XDECREF(self->base_server); Py_XDECREF(self->notes); Py_XDECREF(self->hlo); PyObject_Del(self); } /** ** makeipaddr ** * utility func to make an ip address */ static PyObject *makeipaddr(struct apr_sockaddr_t *addr) { char *str = NULL; apr_status_t rc; PyObject *ret = NULL; rc = apr_sockaddr_ip_get( &str, addr ); if (rc==APR_SUCCESS) { ret = PyString_FromString( str ); } else { PyErr_SetString(PyExc_SystemError,"apr_sockaddr_ip_get failure"); } return ret; } /** ** makesockaddr ** * utility func to make a socket address */ static PyObject *makesockaddr(struct apr_sockaddr_t *addr) { PyObject *addrobj = makeipaddr(addr); PyObject *ret = NULL; /* apr_sockaddr_port_get was deprecated and removed in apr 1.x * Access the port directly instead */ if (addrobj) { apr_port_t port; port = addr->port; ret = Py_BuildValue("Oi", addrobj, port ); Py_DECREF(addrobj); } return ret; } /** ** conn_getattr ** * Get conn object attributes * */ static PyObject * conn_getattr(connobject *self, char *name) { PyObject *res; res = Py_FindMethod(connobjectmethods, (PyObject *)self, name); if (res != NULL) return res; PyErr_Clear(); if (strcmp(name, "base_server") == 0) { /* base_server serverobject is created as needed */ if (self->base_server == NULL) { if (self->conn->base_server == NULL) { Py_INCREF(Py_None); return Py_None; } else { self->base_server = MpServer_FromServer(self->conn->base_server); Py_INCREF(self->base_server); return self->base_server; } } else { Py_INCREF(self->base_server); return self->base_server; } } else if (strcmp(name, "aborted") == 0) { return PyInt_FromLong(self->conn->aborted); } else if (strcmp(name, "keepalive") == 0) { return PyInt_FromLong(self->conn->keepalive); } else if (strcmp(name, "double_reverse") == 0) { return PyInt_FromLong(self->conn->double_reverse); } else if (strcmp(name, "local_addr") == 0) { return makesockaddr(self->conn->local_addr); } else if (strcmp(name, "remote_addr") == 0) { return makesockaddr(self->conn->remote_addr); } else if (strcmp(name, "notes") == 0) { Py_INCREF(self->notes); return (PyObject *) self->notes; } else if (strcmp(name, "hlist") == 0) { Py_INCREF(self->hlo); return (PyObject *)self->hlo; } else if (strcmp(name, "_conn_rec") == 0) { return PyCObject_FromVoidPtr(self->conn, 0); } else return PyMember_Get((char *)self->conn, conn_memberlist, name); } /** ** conn_setattr ** * Set connection object attribute */ static int conn_setattr(connobject *self, char* name, PyObject* value) { if (value == NULL) { PyErr_SetString(PyExc_AttributeError, "can't delete connection attributes"); return -1; } else return PyMember_Set((char *)self->conn, conn_memberlist, name, value); } PyTypeObject MpConn_Type = { PyObject_HEAD_INIT(NULL) 0, "mp_conn", sizeof(connobject), 0, (destructor) conn_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc) conn_getattr, /*tp_getattr*/ (setattrfunc) conn_setattr, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; mod_python-3.3.1/src/_apachemodule.c0000644000175000017500000005370710531163204015546 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * _apachemodule.c * * $Id: _apachemodule.c 478403 2006-11-23 00:08:36Z grahamd $ * */ #include "mod_python.h" /* A referende to the _apache.SERVER_RETURN */ PyObject *Mp_ServerReturn; /** ** mp_log_error ** * A wrapper to ap_log_error * * mp_log_error(string message, int level, server server) * */ static PyObject * mp_log_error(PyObject *self, PyObject *args) { int level = 0; char *message = NULL; serverobject *server = NULL; server_rec *serv_rec; if (! PyArg_ParseTuple(args, "z|iO", &message, &level, &server)) return NULL; /* error */ if (message) { if (! level) level = APLOG_NOERRNO|APLOG_ERR; if (!server || (PyObject *)server == Py_None) serv_rec = NULL; else { if (! MpServer_Check(server)) { PyErr_BadArgument(); return NULL; } serv_rec = server->server; } ap_log_error(APLOG_MARK, level, 0, serv_rec, "%s", message); } Py_INCREF(Py_None); return Py_None; } /** ** parse_qs ** * This is a C version of cgi.parse_qs */ static PyObject *parse_qs(PyObject *self, PyObject *args) { PyObject *pairs, *dict; int i, n, len, lsize; char *qs; int keep_blank_values = 0; int strict_parsing = 0; /* XXX not implemented */ if (! PyArg_ParseTuple(args, "s|ii", &qs, &keep_blank_values, &strict_parsing)) return NULL; /* error */ /* split query string by '&' and ';' into a list of pairs */ /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ pairs = PyList_New(0); if (pairs == NULL) return NULL; i = 0; len = strlen(qs); while (i < len) { PyObject *pair; char *cpair; int j = 0; /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ pair = PyString_FromStringAndSize(NULL, len); if (pair == NULL) return NULL; /* split by '&' or ';' */ cpair = PyString_AS_STRING(pair); while ((qs[i] != '&') && (qs[i] != ';') && (i < len)) { /* replace '+' with ' ' */ cpair[j] = (qs[i] == '+') ? ' ' : qs[i]; i++; j++; } if (j) { /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ _PyString_Resize(&pair, j); if (pair) PyList_Append(pairs, pair); } Py_XDECREF(pair); i++; } /* * now we have a list of "abc=def" string (pairs), let's split * them all by '=' and put them in a dictionary. */ dict = PyDict_New(); if (dict == NULL) return NULL; /* PYTHON 2.5: 'PyList_Size' uses Py_ssize_t for input parameters */ lsize = PyList_Size(pairs); n = 0; while (n < lsize) { PyObject *pair, *key, *val; char *cpair, *ckey, *cval; int k, v; pair = PyList_GET_ITEM(pairs, n); cpair = PyString_AS_STRING(pair); len = strlen(cpair); /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ key = PyString_FromStringAndSize(NULL, len); if (key == NULL) return NULL; /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ val = PyString_FromStringAndSize(NULL, len); if (val == NULL) return NULL; ckey = PyString_AS_STRING(key); cval = PyString_AS_STRING(val); i = 0; k = 0; v = 0; while (i < len) { if (cpair[i] != '=') { ckey[k] = cpair[i]; k++; i++; } else { i++; /* skip '=' */ while (i < len) { cval[v] = cpair[i]; v++; i++; } } } ckey[k] = '\0'; cval[v] = '\0'; if (keep_blank_values || (v > 0)) { ap_unescape_url(ckey); ap_unescape_url(cval); /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ _PyString_Resize(&key, strlen(ckey)); /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ _PyString_Resize(&val, strlen(cval)); if (key && val) { ckey = PyString_AS_STRING(key); cval = PyString_AS_STRING(val); if (PyMapping_HasKeyString(dict, ckey)) { PyObject *list; list = PyDict_GetItem(dict, key); PyList_Append(list, val); /* PyDict_GetItem is a borrowed ref, no decref */ } else { PyObject *list; list = Py_BuildValue("[O]", val); PyDict_SetItem(dict, key, list); Py_DECREF(list); } } } Py_XDECREF(key); Py_XDECREF(val); n++; } Py_DECREF(pairs); return dict; } /** ** parse_qsl ** * This is a C version of cgi.parse_qsl */ static PyObject *parse_qsl(PyObject *self, PyObject *args) { PyObject *pairs; int i, len; char *qs; int keep_blank_values = 0; int strict_parsing = 0; /* XXX not implemented */ if (! PyArg_ParseTuple(args, "s|ii", &qs, &keep_blank_values, &strict_parsing)) return NULL; /* error */ /* split query string by '&' and ';' into a list of pairs */ /* PYTHON 2.5: 'PyList_New' uses Py_ssize_t for input parameters */ pairs = PyList_New(0); if (pairs == NULL) return NULL; i = 0; len = strlen(qs); while (i < len) { PyObject *pair, *key, *val; char *cpair, *ckey, *cval; int plen, j, p, k, v; /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ pair = PyString_FromStringAndSize(NULL, len); if (pair == NULL) return NULL; /* split by '&' or ';' */ cpair = PyString_AS_STRING(pair); j = 0; while ((qs[i] != '&') && (qs[i] != ';') && (i < len)) { /* replace '+' with ' ' */ cpair[j] = (qs[i] == '+') ? ' ' : qs[i]; i++; j++; } if (j == 0) { Py_XDECREF(pair); i++; continue; } cpair[j] = '\0'; /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ _PyString_Resize(&pair, j); cpair = PyString_AS_STRING(pair); /* split the "abc=def" pair */ plen = strlen(cpair); /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ key = PyString_FromStringAndSize(NULL, plen); if (key == NULL) return NULL; /* PYTHON 2.5: 'PyString_FromStringAndSize' uses Py_ssize_t for input parameters */ val = PyString_FromStringAndSize(NULL, plen); if (val == NULL) return NULL; ckey = PyString_AS_STRING(key); cval = PyString_AS_STRING(val); p = 0; k = 0; v = 0; while (p < plen) { if (cpair[p] != '=') { ckey[k] = cpair[p]; k++; p++; } else { p++; /* skip '=' */ while (p < plen) { cval[v] = cpair[p]; v++; p++; } } } ckey[k] = '\0'; cval[v] = '\0'; if (keep_blank_values || (v > 0)) { ap_unescape_url(ckey); ap_unescape_url(cval); /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ _PyString_Resize(&key, strlen(ckey)); /* PYTHON 2.5: '_PyString_Resize' uses Py_ssize_t for input parameters */ _PyString_Resize(&val, strlen(cval)); if (key && val) { PyObject* listitem = Py_BuildValue("(O,O)", key, val); if(listitem) { PyList_Append(pairs, listitem); Py_DECREF(listitem); } } } Py_XDECREF(pair); Py_XDECREF(key); Py_XDECREF(val); i++; } return pairs; } /** ** config_tree ** * Returns a copy of the config tree */ static PyObject *config_tree(void) { return cfgtree_walk(ap_conftree); } /** ** server_root ** * Returns ServerRoot */ static PyObject *server_root(void) { return PyString_FromString(ap_server_root); } /** ** _global_lock ** * Lock one of our global_mutexes */ static PyObject *_global_lock(PyObject *self, PyObject *args) { PyObject *server; PyObject *key; server_rec *s; py_global_config *glb; int index = -1; apr_status_t rv; if (! PyArg_ParseTuple(args, "OO|i", &server, &key, &index)) return NULL; if (! MpServer_Check(server)) { PyErr_SetString(PyExc_TypeError, "First argument must be a server object"); return NULL; } s = ((serverobject *)server)->server; apr_pool_userdata_get((void **)&glb, MP_CONFIG_KEY, s->process->pool); if ((index >= (glb->nlocks)) || (index < -1)) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Index %d is out of range for number of global mutex locks", index); PyErr_SetString(PyExc_ValueError, "Lock index is out of range for number of global mutex locks"); return NULL; } if (index == -1) { int hash = PyObject_Hash(key); if (hash == -1) { return NULL; } else { hash = abs(hash); } /* note that this will never result in 0, * which is reserved for things like dbm * locking (see Session.py) */ index = (hash % (glb->nlocks-1)+1); } /* ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, */ /* "_global_lock at index %d from pid %d", index, getpid()); */ Py_BEGIN_ALLOW_THREADS rv = apr_global_mutex_lock(glb->g_locks[index]); Py_END_ALLOW_THREADS if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, "Failed to acquire global mutex lock at index %d", index); PyErr_SetString(PyExc_ValueError, "Failed to acquire global mutex lock"); return NULL; } /* ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, */ /* "_global_lock DONE at index %d from pid %d", index, getpid()); */ Py_INCREF(Py_None); return Py_None; } /** ** _global_trylock ** * Try to lock one of our global_mutexes */ static PyObject *_global_trylock(PyObject *self, PyObject *args) { PyObject *server; PyObject *key; server_rec *s; py_global_config *glb; int index = -1; apr_status_t rv; if (! PyArg_ParseTuple(args, "OO|i", &server, &key, &index)) return NULL; if (! MpServer_Check(server)) { PyErr_SetString(PyExc_TypeError, "First argument must be a server object"); return NULL; } s = ((serverobject *)server)->server; apr_pool_userdata_get((void **)&glb, MP_CONFIG_KEY, s->process->pool); if ((index >= (glb->nlocks)) || (index < -1)) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Index %d is out of range for number of global mutex locks", index); PyErr_SetString(PyExc_ValueError, "Lock index is out of range for number of global mutex locks"); return NULL; } if (index == -1) { int hash = PyObject_Hash(key); if (hash == -1) { return NULL; } else { hash = abs(hash); } /* note that this will never result in 0, * which is reserved for things like dbm * locking (see Session.py) */ index = (hash % (glb->nlocks-1)+1); } /* * ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, * "_global_trylock at index %d from pid %d", index, getpid()); */ Py_BEGIN_ALLOW_THREADS rv = apr_global_mutex_trylock(glb->g_locks[index]); Py_END_ALLOW_THREADS if (rv == APR_SUCCESS) { /* * ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, * "_global_trylock DONE at index %d from pid %d", index, getpid()); */ Py_INCREF(Py_True); return Py_True; } else if(APR_STATUS_IS_EBUSY(rv)) { /* * ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, * "_global_trylock BUSY at index %d from pid %d", index, getpid()); */ Py_INCREF(Py_False); return Py_False; } else { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, "Failed to acquire global mutex lock at index %d", index); PyErr_SetString(PyExc_ValueError, "Failed to acquire global mutex lock"); return NULL; } } /** ** _global_unlock ** * Unlock one of our global_mutexes */ static PyObject *_global_unlock(PyObject *self, PyObject *args) { PyObject *server; PyObject *key; server_rec *s; py_global_config *glb; int index = -1; apr_status_t rv; if (! PyArg_ParseTuple(args, "OO|i", &server, &key, &index)) return NULL; if (! MpServer_Check(server)) { PyErr_SetString(PyExc_TypeError, "First argument must be a server object"); return NULL; } s = ((serverobject *)server)->server; apr_pool_userdata_get((void **)&glb, MP_CONFIG_KEY, s->process->pool); if ((index >= (glb->nlocks)) || (index < -1)) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Index %d is out of range for number of global mutex locks", index); PyErr_SetString(PyExc_ValueError, "Lock index is out of range for number of global mutex locks"); return NULL; } if (index == -1) { int hash = PyObject_Hash(key); if (hash == -1) { return NULL; } else { hash = abs(hash); } /* note that this will never result in 0, * which is reserved for things like dbm * locking (see Session.py) */ index = (hash % (glb->nlocks-1)+1); } /* ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, */ /* "_global_unlock at index %d from pid %d", index, getpid()); */ if ((rv = apr_global_mutex_unlock(glb->g_locks[index])) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, "Failed to release global mutex lock at index %d", index); PyErr_SetString(PyExc_ValueError, "Failed to release global mutex lock"); return NULL; } Py_INCREF(Py_None); return Py_None; } /** ** mpm_query ** * ap_mpm_query interface */ static PyObject *mpm_query(PyObject *self, PyObject *code) { int result; if (!PyInt_Check(code)) { PyErr_SetString(PyExc_TypeError, "The argument must be an integer"); return NULL; } ap_mpm_query(PyInt_AS_LONG(code), &result); return PyInt_FromLong(result); } /** ** register_cleanup(interpreter, server, handler, data) ** * more low level version of request.register_cleanup where it is * necessary to specify the actual interpreter name. the server pool * is used. the server pool gets destroyed before the child dies or * when the whole process dies in multithreaded situations. */ static PyObject *register_cleanup(PyObject *self, PyObject *args) { cleanup_info *ci; char *interpreter = NULL; serverobject *server = NULL; PyObject *handler = NULL; PyObject *data = NULL; if (! PyArg_ParseTuple(args, "sOO|O", &interpreter, &server, &handler, &data)) return NULL; if (! MpServer_Check(server)) { PyErr_SetString(PyExc_ValueError, "second argument must be a server object"); return NULL; } else if(!PyCallable_Check(handler)) { PyErr_SetString(PyExc_ValueError, "third argument must be a callable object"); return NULL; } ci = (cleanup_info *)malloc(sizeof(cleanup_info)); ci->request_rec = NULL; ci->server_rec = server->server; Py_INCREF(handler); ci->handler = handler; ci->interpreter = strdup(interpreter); if (data) { Py_INCREF(data); ci->data = data; } else { Py_INCREF(Py_None); ci->data = Py_None; } apr_pool_cleanup_register(child_init_pool, ci, python_cleanup, apr_pool_cleanup_null); Py_INCREF(Py_None); return Py_None; } /** ** exists_config_define(name) ** * Check for a definition from the server command line. */ static PyObject *exists_config_define(PyObject *self, PyObject *args) { char *name = NULL; if (! PyArg_ParseTuple(args, "s", &name)) return NULL; if(ap_exists_config_define(name)) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } } /** ** mp_stat(fname, wanted) ** * Wrapper for apr_stat(). */ static PyObject *mp_stat(PyObject *self, PyObject *args) { char *fname = NULL; apr_int32_t wanted = 0; finfoobject* finfo; apr_status_t result; if (! PyArg_ParseTuple(args, "si", &fname, &wanted)) return NULL; finfo = (finfoobject *)MpFinfo_New(); fname = apr_pstrdup(finfo->pool, fname); result = apr_stat(finfo->finfo, fname, wanted, finfo->pool); if (result == APR_INCOMPLETE || result == APR_SUCCESS) return (PyObject *)finfo; if (result == APR_ENOENT) return (PyObject *)finfo; Py_DECREF(finfo); PyErr_SetObject(PyExc_OSError, Py_BuildValue("is", result, "apr_stat() failed")); return NULL; } /* methods of _apache */ struct PyMethodDef _apache_module_methods[] = { {"config_tree", (PyCFunction)config_tree, METH_NOARGS}, {"log_error", (PyCFunction)mp_log_error, METH_VARARGS}, {"mpm_query", (PyCFunction)mpm_query, METH_O}, {"parse_qs", (PyCFunction)parse_qs, METH_VARARGS}, {"parse_qsl", (PyCFunction)parse_qsl, METH_VARARGS}, {"server_root", (PyCFunction)server_root, METH_NOARGS}, {"register_cleanup", (PyCFunction)register_cleanup, METH_VARARGS}, {"exists_config_define", (PyCFunction)exists_config_define, METH_VARARGS}, {"stat", (PyCFunction)mp_stat, METH_VARARGS}, {"_global_lock", (PyCFunction)_global_lock, METH_VARARGS}, {"_global_trylock", (PyCFunction)_global_trylock, METH_VARARGS}, {"_global_unlock", (PyCFunction)_global_unlock, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; /* Module initialization */ DL_EXPORT(void) init_apache() { PyObject *m, *d, *o; /* initialize types XXX break windows? */ MpTable_Type.ob_type = &PyType_Type; MpTableIter_Type.ob_type = &PyType_Type; MpServer_Type.ob_type = &PyType_Type; MpConn_Type.ob_type = &PyType_Type; MpRequest_Type.ob_type = &PyType_Type; MpFilter_Type.ob_type = &PyType_Type; MpHList_Type.ob_type = &PyType_Type; m = Py_InitModule("_apache", _apache_module_methods); d = PyModule_GetDict(m); Mp_ServerReturn = PyErr_NewException("_apache.SERVER_RETURN", NULL, NULL); if (Mp_ServerReturn == NULL) return; PyDict_SetItemString(d, "SERVER_RETURN", Mp_ServerReturn); PyDict_SetItemString(d, "table", (PyObject *)&MpTable_Type); o = PyInt_FromLong(AP_CONN_UNKNOWN); PyDict_SetItemString(d, "AP_CONN_UNKNOWN", o); Py_DECREF(o); o = PyInt_FromLong(AP_CONN_CLOSE); PyDict_SetItemString(d, "AP_CONN_CLOSE", o); Py_DECREF(o); o = PyInt_FromLong(AP_CONN_KEEPALIVE); PyDict_SetItemString(d, "AP_CONN_KEEPALIVE", o); Py_DECREF(o); o = PyInt_FromLong(APR_NOFILE); PyDict_SetItemString(d, "APR_NOFILE", o); Py_DECREF(o); o = PyInt_FromLong(APR_REG); PyDict_SetItemString(d, "APR_REG", o); Py_DECREF(o); o = PyInt_FromLong(APR_DIR); PyDict_SetItemString(d, "APR_DIR", o); Py_DECREF(o); o = PyInt_FromLong(APR_CHR); PyDict_SetItemString(d, "APR_CHR", o); Py_DECREF(o); o = PyInt_FromLong(APR_BLK); PyDict_SetItemString(d, "APR_BLK", o); Py_DECREF(o); o = PyInt_FromLong(APR_PIPE); PyDict_SetItemString(d, "APR_PIPE", o); Py_DECREF(o); o = PyInt_FromLong(APR_LNK); PyDict_SetItemString(d, "APR_LNK", o); Py_DECREF(o); o = PyInt_FromLong(APR_SOCK); PyDict_SetItemString(d, "APR_SOCK", o); Py_DECREF(o); o = PyInt_FromLong(APR_UNKFILE); PyDict_SetItemString(d, "APR_UNKFILE", o); Py_DECREF(o); } PyObject *get_ServerReturn() { return Mp_ServerReturn; } mod_python-3.3.1/src/psp_parser.l0000644000175000017500000001251710424736222015150 0ustar jimjim%{ /* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * $Id: psp_parser.l 398222 2006-04-29 19:20:50Z jgallacher $ * * This file originally written by Sterling Hughes. * */ /* NOTE The seemingly unusual generated Python code (sometime using * ";" to separate statements, newline placement, etc) is such that * for vast majority of cases the line number of the input file will * match the line number of the output! */ #include "psp_parser.h" #define OUTPUT_WHITESPACE(__wsstring) \ psp_string_0((__wsstring)); \ psp_string_append(&PSP_PG(pycode), (__wsstring)->blob) #define CLEAR_WHITESPACE(__wsstring) psp_string_clear((__wsstring)); %} %option noyywrap nounistd %x TEXT %x PYCODE %x INDENT %x DIR %x COMMENT %% \r\n|\n { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("req.write(\"\"\"")); yyless(0); BEGIN TEXT; } . { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("req.write(\"\"\"")); yyless(0); BEGIN TEXT; } "\\n" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\\n")); } "\\r" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\\r")); } "\\t" { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\\t")); } "<%=" { /* expression */ psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\"\"\",0); req.write(str(")); PSP_PG(is_psp_echo) = 1; BEGIN PYCODE; } "<%" { /* python code */ psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\"\"\",0);")); CLEAR_WHITESPACE(&PSP_PG(whitespace)); PSP_PG(seen_newline) = 0; BEGIN PYCODE; } "<%@" { /* directive */ BEGIN DIR; } "<%--" { /* comment */ BEGIN COMMENT; } \r\n|\n { psp_string_appendc(&PSP_PG(pycode), '\n'); } . { if (yytext[0] == '"') { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\\\"")); } else { psp_string_appendc(&PSP_PG(pycode), yytext[0]); } } <> { yypop_buffer_state(yyscanner); if (!YY_CURRENT_BUFFER) { /* this is really the end */ psp_string_appendl(&PSP_PG(pycode), STATIC_STR("\"\"\",0)\n")); yyterminate(); } else { /* we are inside include, continue scanning */ BEGIN DIR; } } \r\n|\n|\r { psp_string_appendc(&PSP_PG(pycode), '\n'); PSP_PG(seen_newline) = 1; BEGIN INDENT; } "%>" { if (PSP_PG(is_psp_echo)) { psp_string_appendl(&PSP_PG(pycode), STATIC_STR("),0); req.write(\"\"\"")); PSP_PG(is_psp_echo) = 0; } else { if (!PSP_PG(seen_newline)) { /* this will happen is you have <%%> */ psp_string_appendc(&PSP_PG(pycode), ';'); } if (PSP_PG(after_colon)) { /* this is dumb mistake-proof measure, if %> is immediately following where there should be an indent */ psp_string_appendc(&PSP_PG(whitespace), '\t'); PSP_PG(after_colon) = 0; } OUTPUT_WHITESPACE(&PSP_PG(whitespace)); psp_string_appendl(&PSP_PG(pycode), STATIC_STR("req.write(\"\"\"")); } BEGIN TEXT; } ":" { psp_string_appendc(&PSP_PG(pycode), yytext[0]); PSP_PG(after_colon) = 1; } . { psp_string_appendc(&PSP_PG(pycode), yytext[0]); PSP_PG(after_colon) = 0; } ^[\t ]* { CLEAR_WHITESPACE(&PSP_PG(whitespace)); psp_string_appendl(&PSP_PG(whitespace), yytext, yyleng); psp_string_appendl(&PSP_PG(pycode), yytext, yyleng); BEGIN PYCODE; } "%>" { yyless(0); BEGIN PYCODE; } \r\n|\n { CLEAR_WHITESPACE(&PSP_PG(whitespace)); yyless(0); BEGIN PYCODE; } . { CLEAR_WHITESPACE(&PSP_PG(whitespace)); yyless(0); BEGIN PYCODE; } "include"[ ]+"file"[ ]?=[ ]?"\""[^ ]+"\"" { char *filename; char *path; FILE *f; /* find a quote */ filename = strchr(yytext, '"') + 1; filename[strchr(filename, '"')-filename] = '\0'; /* XXX The absolute path check won't work on Windows, * needs to be corrected */ if (PSP_PG(dir) && filename[0] != '/') { path = malloc(strlen(filename)+strlen(PSP_PG(dir))+1); if (path == NULL) { PyErr_NoMemory(); yyterminate(); } strcpy(path, PSP_PG(dir)); strcat(path, filename); } else { path = filename; } Py_BEGIN_ALLOW_THREADS f = fopen(path, "rb"); Py_END_ALLOW_THREADS if (f == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, path); } else { yypush_buffer_state(yy_create_buffer(f, YY_BUF_SIZE, yyscanner), yyscanner); BEGIN(TEXT); } if (PSP_PG(dir)) free(path); } "%>" { BEGIN TEXT; } "--%>" { BEGIN TEXT; } %% /* this is for emacs Local Variables: mode:C End: */ mod_python-3.3.1/src/psp_string.c0000644000175000017500000000421410376731517015154 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * $Id: psp_string.c 379638 2006-02-22 00:41:51Z jgallacher $ * * See accompanying documentation and source code comments * for details. * */ #include "psp_string.h" #define psp_string_alloc(__pspstring, __length) \ if ((__length) > (__pspstring)->allocated) { \ (__pspstring)->blob = realloc((__pspstring)->blob, (__length) + PSP_STRING_BLOCK); \ (__pspstring)->allocated = (__length) + PSP_STRING_BLOCK; \ } void psp_string_0(psp_string *s) { if (!s->length) { return; } s->blob[s->length] = '\0'; } void psp_string_appendl(psp_string *s, char *text, size_t length) { int newlen = s->length + length; if (text == NULL) { return; } psp_string_alloc(s, newlen); memcpy(s->blob + s->length, text, length); s->length = newlen; } void psp_string_append(psp_string *s, char *text) { if (text == NULL) { return; } psp_string_appendl(s, text, strlen(text)); } void psp_string_appendc(psp_string *s, char c) { int newlen = s->length + 1; psp_string_alloc(s, newlen); s->blob[s->length] = c; s->length = newlen; } void psp_string_clear(psp_string *s) { memset(s->blob, 0, s->length); s->length = 0; } void psp_string_free(psp_string *s) { free(s->blob); s->blob = NULL; s->length = 0; s->allocated = 0; } mod_python-3.3.1/src/finfoobject.c0000644000175000017500000002604510516147342015253 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * finfoobject.c * * $Id: finfoobject.c 466105 2006-10-20 13:28:02Z jgallacher $ * */ #include "mod_python.h" /** ** MpFinfo_FromFinfo ** * This routine creates a Python finfoobject given an Apache * finfo pointer. * */ PyObject * MpFinfo_FromFinfo(apr_finfo_t *f) { finfoobject *result; result = PyObject_New(finfoobject, &MpFinfo_Type); if (! result) return PyErr_NoMemory(); result->finfo = f; result->pool = NULL; return (PyObject *)result; } /** ** MpFinfo_New ** * This returns a new object of built-in type finfo. * * NOTE: The apr_finfo_t gets greated in its own pool, which lives * throught the life of the finfoobject. * */ PyObject * MpFinfo_New() { finfoobject *f; apr_pool_t *p; /* XXX need second arg abort function to report mem error */ apr_pool_create_ex(&p, NULL, NULL, NULL); f = (finfoobject *)MpFinfo_FromFinfo(apr_pcalloc(p, sizeof(apr_finfo_t))); /* remember the pointer to our own pool */ f->pool = p; return (PyObject *)f; } /** ** finfo_dealloc ** * Frees finfo's memory */ static void finfo_dealloc(register finfoobject *self) { if (MpFinfo_Check(self)) { if (self->pool) apr_pool_destroy(self->pool); PyObject_Del(self); } else self->ob_type->tp_free((PyObject *)self); } /** ** finfo_getattr ** * Get finfo object attributes * */ static PyObject * finfo_getattr(finfoobject *self, char *name) { if (strcmp(name, "fname") == 0) { if (self->finfo->fname) return PyString_FromString(self->finfo->fname); } else if (strcmp(name, "filetype") == 0) { return PyInt_FromLong(self->finfo->filetype); } else if (strcmp(name, "valid") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } return PyInt_FromLong(self->finfo->valid); } else if (strcmp(name, "protection") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_PROT) return PyInt_FromLong(self->finfo->protection); } else if (strcmp(name, "user") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_USER) return PyInt_FromLong(self->finfo->user); } else if (strcmp(name, "group") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_GROUP) return PyInt_FromLong(self->finfo->group); } else if (strcmp(name, "inode") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_INODE) return PyInt_FromLong(self->finfo->inode); } else if (strcmp(name, "device") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_DEV) return PyInt_FromLong(self->finfo->device); } else if (strcmp(name, "nlink") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_NLINK) return PyInt_FromLong(self->finfo->nlink); } else if (strcmp(name, "size") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_SIZE) { if (sizeof(apr_off_t) == sizeof(LONG_LONG)) { return PyLong_FromLongLong(self->finfo->size); } else { return PyLong_FromLong(self->finfo->size); } } } else if (strcmp(name, "atime") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_ATIME) return PyInt_FromLong(self->finfo->atime*0.000001); } else if (strcmp(name, "mtime") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_MTIME) return PyInt_FromLong(self->finfo->mtime*0.000001); } else if (strcmp(name, "ctime") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_CTIME) return PyInt_FromLong(self->finfo->ctime*0.000001); } else if (strcmp(name, "name") == 0) { if (self->finfo->filetype == APR_NOFILE) { Py_INCREF(Py_None); return Py_None; } if (self->finfo->valid & APR_FINFO_NAME) return PyString_FromString(self->finfo->name); } else { PyErr_Format(PyExc_AttributeError, "class 'mp_finfo' has no attribute '%.400s'", name); return NULL; } Py_INCREF(Py_None); return Py_None; } static PyObject* finfoseq_item(finfoobject *self, int i) { if (i < 0 || i >= 12) { PyErr_SetString(PyExc_IndexError, "tuple index out of range"); return NULL; } switch (i) { case 0: { return finfo_getattr(self, "protection"); } case 1: { return finfo_getattr(self, "inode"); } case 2: { return finfo_getattr(self, "device"); } case 3: { return finfo_getattr(self, "nlink"); } case 4: { return finfo_getattr(self, "user"); } case 5: { return finfo_getattr(self, "group"); } case 6: { return finfo_getattr(self, "size"); } case 7: { return finfo_getattr(self, "atime"); } case 8: { return finfo_getattr(self, "mtime"); } case 9: { return finfo_getattr(self, "ctime"); } case 10: { return finfo_getattr(self, "fname"); } case 11: { return finfo_getattr(self, "name"); } case 12: { return finfo_getattr(self, "filetype"); } } Py_INCREF(Py_None); return Py_None; } static PySequenceMethods finfoseq_as_sequence = { 0, 0, /* sq_concat */ 0, /* sq_repeat */ /* PYTHON 2.5: WARNING: 'intargfunc' must be replaced with 'ssizeargfunc' */ (intargfunc)finfoseq_item, /* sq_item */ 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ 0, /* sq_contains */ }; /** ** finfo_repr ** * */ static PyObject *finfo_repr(finfoobject *self) { PyObject *s = PyString_FromString("{"); PyObject *t = NULL; PyString_ConcatAndDel(&s, PyString_FromString("'fname': ")); t = finfo_getattr(self, "fname"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'filetype': ")); t = finfo_getattr(self, "filetype"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'valid': ")); t = finfo_getattr(self, "valid"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'protection': ")); t = finfo_getattr(self, "protection"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'user': ")); t = finfo_getattr(self, "user"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'group': ")); t = finfo_getattr(self, "group"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'size': ")); t = finfo_getattr(self, "size"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'inode': ")); t = finfo_getattr(self, "inode"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'device': ")); t = finfo_getattr(self, "device"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'nlink': ")); t = finfo_getattr(self, "nlink"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'atime': ")); t = finfo_getattr(self, "atime"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'mtime': ")); t = finfo_getattr(self, "mtime"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'ctime': ")); t = finfo_getattr(self, "ctime"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString(", 'name': ")); t = finfo_getattr(self, "name"); PyString_ConcatAndDel(&s, PyObject_Repr(t)); Py_XDECREF(t); PyString_ConcatAndDel(&s, PyString_FromString("}")); return s; } PyTypeObject MpFinfo_Type = { PyObject_HEAD_INIT(NULL) 0, "mp_finfo", sizeof(finfoobject), 0, (destructor)finfo_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc)finfo_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /* tp_compare */ (reprfunc)finfo_repr, /*tp_repr*/ 0, /* tp_as_number */ &finfoseq_as_sequence, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ }; mod_python-3.3.1/src/serverobject.c0000644000175000017500000003216710534452125015460 0ustar jimjim/* * Copyright 2004 Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * Originally developed by Gregory Trubetskoy. * * * serverobject.c * * $Id: serverobject.c 481717 2006-12-03 04:36:37Z grahamd $ * */ #include "mod_python.h" /** ** MpServer_FromServer ** * This routine creates a Python serverobject given an Apache * server_rec pointer. * */ PyObject * MpServer_FromServer(server_rec *s) { serverobject *result; result = PyObject_New(serverobject, &MpServer_Type); if (! result) return PyErr_NoMemory(); result->dict = PyDict_New(); if (!result->dict) return PyErr_NoMemory(); result->server = s; result->next = NULL; return (PyObject *)result; } /** ** server.get_config(server self) ** * Returns the config directives set through Python* apache directives. * unlike req.get_config, this one returns the per-server config */ static PyObject * server_get_config(serverobject *self) { py_config *conf = (py_config *) ap_get_module_config(self->server->module_config, &python_module); return MpTable_FromTable(conf->directives); } /** ** server.get_options(server self) ** * Returns the options set through PythonOption directives. * unlike req.get_options, this one returns the per-server config */ static PyObject * server_get_options(serverobject *self) { py_config *conf = (py_config *) ap_get_module_config(self->server->module_config, &python_module); return MpTable_FromTable(conf->options); } /** ** server.log_error(server self, string message, int level) ** * calls ap_log_error */ static PyObject * server_log_error(serverobject *self, PyObject *args) { int level = 0; char *message = NULL; if (! PyArg_ParseTuple(args, "z|i", &message, &level)) return NULL; /* error */ if (message) { if (! level) level = APLOG_NOERRNO|APLOG_ERR; ap_log_error(APLOG_MARK, level, 0, self->server, "%s", message); } Py_INCREF(Py_None); return Py_None; } /** ** server.register_cleanup(req, handler, data) ** * same as request.register_cleanup, except the server pool is used. * the server pool gets destroyed before the child dies or when the * whole process dies in multithreaded situations. */ static PyObject *server_register_cleanup(serverobject *self, PyObject *args) { cleanup_info *ci; PyObject *handler = NULL; PyObject *data = NULL; requestobject *req = NULL; PyObject *name_obj = NULL; char *name = NULL; if (! PyArg_ParseTuple(args, "OO|O", &req, &handler, &data)) return NULL; if (! MpRequest_Check(req)) { PyErr_SetString(PyExc_ValueError, "first argument must be a request object"); return NULL; } else if(!PyCallable_Check(handler)) { PyErr_SetString(PyExc_ValueError, "second argument must be a callable object"); return NULL; } ci = (cleanup_info *)malloc(sizeof(cleanup_info)); ci->request_rec = NULL; ci->server_rec = self->server; Py_INCREF(handler); ci->handler = handler; name_obj = python_interpreter_name(); name = (char *)malloc(strlen(PyString_AsString(name_obj))+1); strcpy(name, PyString_AsString(name_obj)); ci->interpreter = name; if (data) { Py_INCREF(data); ci->data = data; } else { Py_INCREF(Py_None); ci->data = Py_None; } apr_pool_cleanup_register(child_init_pool, ci, python_cleanup, apr_pool_cleanup_null); Py_INCREF(Py_None); return Py_None; } static PyMethodDef server_methods[] = { {"get_config", (PyCFunction) server_get_config, METH_NOARGS}, {"get_options", (PyCFunction) server_get_options, METH_NOARGS}, {"log_error", (PyCFunction) server_log_error, METH_VARARGS}, {"register_cleanup", (PyCFunction) server_register_cleanup, METH_VARARGS}, { NULL, NULL } /* sentinel */ }; /* These are offsets into the Apache server_rec structure. They are accessed via getset functions. Note that the types specified here are irrelevant if a function other than getreq_recmbr() is used. E.g. bytes_sent is a long long, and is retrieved via getreq_recmbr_off() which ignores what's here. */ #define OFF(x) offsetof(server_rec, x) static struct PyMemberDef server_rec_mbrs[] = { {"defn_name", T_STRING, OFF(defn_name)}, {"defn_line_number", T_INT, OFF(defn_line_number)}, {"server_admin", T_STRING, OFF(server_admin)}, {"server_hostname", T_STRING, OFF(server_hostname)}, {"port", T_SHORT, OFF(port)}, {"error_fname", T_STRING, OFF(error_fname)}, {"loglevel", T_INT, OFF(loglevel)}, {"is_virtual", T_INT, OFF(is_virtual)}, /* XXX implement module_config ? */ /* XXX implement lookup_defaults ? */ /* XXX implement server_addr_rec ? */ {"timeout", T_LONG, OFF(timeout)}, {"keep_alive_timeout", T_LONG, OFF(keep_alive_timeout)}, {"keep_alive_max", T_INT, OFF(keep_alive_max)}, {"keep_alive", T_INT, OFF(keep_alive)}, /* XXX send_buffer_size gone. where? document */ /*{"send_buffer_size", T_INT, OFF(send_buffer_size), RO},*/ {"path", T_STRING, OFF(path)}, {"pathlen", T_INT, OFF(pathlen)}, {"names", T_OBJECT, OFF(names)}, {"wild_names", T_OBJECT, OFF(wild_names)}, /* XXX server_uid and server_gid seem gone. Where? Document. */ /*{"server_uid", T_INT, OFF(server_uid), RO},*/ /*{"server_gid", T_INT, OFF(server_gid), RO},*/ /* XXX Document limit* below. Make RW? */ {"limit_req_line", T_INT, OFF(limit_req_line)}, {"limit_req_fieldsize", T_INT, OFF(limit_req_fieldsize)}, {"limit_req_fields", T_INT, OFF(limit_req_fields)}, {NULL} /* Sentinel */ }; /** ** getsrv_recmbr ** * Retrieves server_rec structure members */ static PyObject *getsrv_recmbr(serverobject *self, void *name) { if (strcmp(name, "_server_rec") == 0) { return PyCObject_FromVoidPtr(self->server, 0); } return PyMember_GetOne((char*)self->server, find_memberdef(server_rec_mbrs, name)); } /* we don't need setsrv_recmbr for now */ /** ** getsrv_recmbr_time ** * Retrieves apr_time_t server_rec members */ static PyObject *getsrv_recmbr_time(serverobject *self, void *name) { PyMemberDef *md = find_memberdef(server_rec_mbrs, name); char *addr = (char *)self->server + md->offset; apr_time_t time = *(apr_time_t*)addr; return PyFloat_FromDouble(time*0.000001); } /** ** getsrv_rec_ah ** * For array headers that will get converted to tuple */ static PyObject *getsrv_recmbr_ah(serverobject *self, void *name) { const PyMemberDef *md = find_memberdef(server_rec_mbrs, name); apr_array_header_t *ah = *(apr_array_header_t **)((char *)self->server + md->offset); return tuple_from_array_header(ah); } /** ** getmakeobj ** * A getter func that creates an object as needed. */ static PyObject *getmakeobj(serverobject* self, void *objname) { char *name = (char *)objname; PyObject *result = NULL; if (strcmp(name, "next") == 0) { if (!self->next && self->server->next) self->next = MpServer_FromServer(self->server->next); result = self->next; } if (!result) result = Py_None; Py_INCREF(result); return result; } static PyObject *my_generation(serverobject *self, void *objname) { return PyInt_FromLong((long)ap_my_generation); } static PyObject *restart_time(serverobject *self, void *objname) { return PyFloat_FromDouble(ap_scoreboard_image->global->restart_time*0.000001); } static PyGetSetDef server_getsets[] = { /* XXX process */ {"next", (getter)getmakeobj, NULL, "The next server in the list", "next"}, {"defn_name", (getter)getsrv_recmbr, NULL, "The name of the server", "defn_name"}, {"defn_line_number", (getter)getsrv_recmbr, NULL, "The line of the config file that the server was defined on", "defn_line_number"}, {"server_admin", (getter)getsrv_recmbr, NULL, "The admin's contact information", "server_admin"}, {"server_hostname", (getter)getsrv_recmbr, NULL, "The server hostname", "server_hostname"}, {"port", (getter)getsrv_recmbr, NULL, " for redirects, etc.", "port"}, {"error_fname", (getter)getsrv_recmbr, NULL, "The name of the error log", "error_fname"}, /* XXX error_log apr_file_t */ {"loglevel", (getter)getsrv_recmbr, NULL, "The log level for this server", "loglevel"}, {"is_virtual", (getter)getsrv_recmbr, NULL, "true if this is the virtual server", "is_virtual"}, {"timeout", (getter)getsrv_recmbr_time, NULL, "Timeout, as interval, before we give up", "timeout"}, {"keep_alive_timeout", (getter)getsrv_recmbr_time, NULL, "The apr interval we will wait for another request", "keep_alive_timeout"}, {"keep_alive_max", (getter)getsrv_recmbr, NULL, "Maximum requests per connection", "keep_alive_max"}, {"keep_alive", (getter)getsrv_recmbr, NULL, "Use persistent connections?", "keep_alive"}, {"path", (getter)getsrv_recmbr, NULL, "Pathname for ServerPath", "path"}, {"pathlen", (getter)getsrv_recmbr, NULL, "Length of path", "pathlen"}, {"names", (getter)getsrv_recmbr_ah, NULL, "Normal names for ServerAlias servers", "names"}, {"wild_names", (getter)getsrv_recmbr_ah, NULL, "Wildcarded names for ServerAlias servers", "wild_names"}, {"limit_req_line", (getter)getsrv_recmbr, NULL, "limit on size of the HTTP request line", "limit_req_line"}, {"limit_req_fieldsize", (getter)getsrv_recmbr, NULL, "limit on size of any request header field", "limit_req_fieldsize"}, {"limit_req_fields", (getter)getsrv_recmbr, NULL, "limit on number of request header fields", "limit_req_fields"}, {"my_generation", (getter)my_generation, NULL, "Generation of this child", "my_generation"}, {"restart_time", (getter)restart_time, NULL, "Server restart time", "restart_time"}, {"_server_rec", (getter)getsrv_recmbr, NULL, "Actual server_rec struct", "_server_rec"}, {NULL} /* Sentinel */ }; /** ** server_dealloc ** * */ static void server_dealloc(serverobject *self) { Py_XDECREF(self->dict); Py_XDECREF(self->next); PyObject_Del(self); } static char server_doc[] = "Apache server_rec structure\n"; PyTypeObject MpServer_Type = { PyObject_HEAD_INIT(NULL) 0, "mp_server", sizeof(serverobject), 0, (destructor) server_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ server_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ server_methods, /* tp_methods */ 0, /* tp_members */ server_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(serverobject, dict), /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ (destructor)server_dealloc, /* tp_free */ }; mod_python-3.3.1/dist/0000755000175000017500000000000010557377762013004 5ustar jimjimmod_python-3.3.1/dist/build_installer.bat0000644000175000017500000000373310454200010016615 0ustar jimjim@echo off rem Copyright 2004 Apache Software Foundation rem rem Licensed under the Apache License, Version 2.0 (the "License"); rem you may not use this file except in compliance with the License. rem You may obtain a copy of the License at rem rem http://www.apache.org/licenses/LICENSE-2.0 rem rem Unless required by applicable law or agreed to in writing, software rem distributed under the License is distributed on an "AS IS" BASIS, rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. rem See the License for the specific language governing permissions and rem limitations under the License. rem rem Originally developed by Gregory Trubetskoy. rem rem $Id: build_installer.bat 420292 2006-07-09 13:09:28Z nlehuen $ rem rem This script builds the installer for Windows rem Test for APACHESRC if "%APACHESRC%"=="" GOTO NOAPACHESRC if not exist "%APACHESRC%\include" GOTO BADAPACHESRC rem Cleanup rmdir /s /q build del /s ..\src\*.obj ..\src\*.lib ..\src\*.exp ..\src\*.res rem Build python setup.py.in bdist_wininst --install-script win32_postinstall.py GOTO END rem Use this instead of the previous line to create a debug build rem For this you need a Python debug build. The .py files will be installed rem directly in the Python debug build's site-packages. The .so file will remain rem in build/lib.win32-2.4, so you'll have to make sure your testconf.py file rem points to it instead of the copy that may already reside in LIBEXECDIR. rem python_d setup.py.in build --debug install rem GOTO END rem Compress the installer if possible upx.exe --no-color --no-progress --best dist\*.exe GOTO END :BADAPACHESRC echo Currently APACHESRC points to %APACHESRC% echo This value seems wrong as we could not find a proper echo Apache installation here. :NOAPACHESRC echo Please set the APACHESRC variable to point to your Apache setup echo E.g. set APACHESRC=c:\apache echo This can be a binary distribution, no need for the Apache sources. GOTO END :END mod_python-3.3.1/dist/Makefile.in0000644000175000017500000000312210324221647015025 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Originally developed by Gregory Trubetskoy. # # $Id: Makefile.in 321360 2005-10-15 15:43:35Z jgallacher $ # PYTHON_BIN=@PYTHON_BIN@ MP_VERSION=@MP_VERSION@ build: mod_python src @cd src; $(MAKE) psp_parser.c $(PYTHON_BIN) setup.py build # this one requires at least python 2.3 windist: mod_python.so $(PYTHON_BIN) setup.py bdist_wininst --install-script=win32_postinstall.py install: install_py_lib # this may require root priviledges install_py_lib: mod_python src @cd src; $(MAKE) psp_parser.c if test -z "$(DESTDIR)" ; then \ $(PYTHON_BIN) setup.py install --optimize 2 --force ; \ else \ $(PYTHON_BIN) setup.py install --optimize 2 --force --root $(DESTDIR) ; \ fi mod_python.so: @echo "Please place a WIN32 compiled mod_python.so in this directory" exit 1 mod_python: ln -s ../lib/python/mod_python mod_python src: ln -s ../src src clean: rm -rf mod_python build dist distclean: rm -rf mod_python src build dist mod_python.so setup.py Makefile MANIFEST MANIFSET.in mod_python-3.3.1/dist/win32_postinstall.py0000644000175000017500000001442610226547024016742 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Originally developed by Gregory Trubetskoy. # # $Id: win32_postinstall.py 160939 2005-04-11 19:20:52Z nlehuen $ # # this script runs at the end of windows install import sys, os, shutil import distutils.sysconfig def getApacheDirOptions(): """find potential apache directories in the registry...""" try: import win32api, win32con class nullregkey: """a registry key that doesn't exist...""" def childkey(self, subkeyname): return nullregkey() def subkeynames(self): return [] def getvalue(self, valuename): raise AttributeError("Cannot access registry value %r: key does not exist" % (valuename)) class regkey: """simple wrapper for registry functions that closes keys nicely...""" def __init__(self, parent, subkeyname): self.key = win32api.RegOpenKey(parent, subkeyname) def childkey(self, subkeyname): try: return regkey(self.key, subkeyname) except win32api.error: return nullregkey() def subkeynames(self): numsubkeys = win32api.RegQueryInfoKey(self.key)[0] return [win32api.RegEnumKey(self.key, index) for index in range(numsubkeys)] def getvalue(self, valuename): try: return win32api.RegQueryValueEx(self.key, valuename) except win32api.error: raise AttributeError("Cannot access registry value %r" % (valuename)) def __del__(self): if hasattr(self, "key"): win32api.RegCloseKey(self.key) except ImportError: return {} versions = {} hklm_key = regkey(win32con.HKEY_LOCAL_MACHINE, "Software").childkey("Apache Group").childkey("Apache") hkcu_key = regkey(win32con.HKEY_CURRENT_USER, "Software").childkey("Apache Group").childkey("Apache") for apachekey in (hklm_key, hkcu_key): for versionname in apachekey.subkeynames(): try: serverroot = apachekey.childkey(versionname).getvalue("ServerRoot") except AttributeError: continue versions[versionname] = serverroot[0] return versions def askForApacheDir(apachediroptions): # try to ask for Apache directory if len(apachediroptions) > 0: # get the most recent version... versionnames = apachediroptions.keys() versionnames.sort() initialdir = apachediroptions[versionnames[-1]] else: initialdir="C:/Program Files/Apache Group/Apache2" # TODO: let the user select the name from a list, or click browse to choose... try: from tkFileDialog import askdirectory from Tkinter import Tk root = Tk() root.withdraw() path = askdirectory(title="Where is Apache installed?", initialdir=initialdir, mustexist=1, master=root) root.quit() root.destroy() return path except ImportError: try: from win32com.shell import shell pidl, displayname, imagelist = shell.SHBrowseForFolder(0, None, "Where is Apache installed?") path = shell.SHGetPathFromIDList(pidl) return path except ImportError: return "" # if we're called during removal, just exit if len(sys.argv) == 1 or (len(sys.argv) > 1 and sys.argv[1] != "-remove"): mp = os.path.join(distutils.sysconfig.get_python_lib(), "mod_python_so.pyd") apachediroptions = getApacheDirOptions() apachedir = askForApacheDir(apachediroptions) if apachedir: # put mod_python.so there mod_python_so_path = os.path.join(apachedir, "modules", "mod_python.so") mod_python_uninstall_log = os.path.join(distutils.sysconfig.get_python_lib(), 'mod_python_uninstall.log') shutil.copy2(mp, mod_python_so_path) f = file(mod_python_uninstall_log, 'wb') f.write(mod_python_so_path) f.close() os.remove(mp) print """Important Note for Windows users, PLEASE READ!!! 1. This script does not attempt to modify Apache configuration, you must do it manually: Edit %s, find where other LoadModule lines are and add this: LoadModule python_module modules/mod_python.so 2. Now test your installation using the instructions at this link: http://www.modpython.org/live/current/doc-html/inst-testing.html """ % os.path.join(apachedir, "conf", "httpd.conf") else: print """Important Note for Windows users, PLEASE READ!!! 1. It appears that you do not have Tkinter installed, which is required for a part of this installation. Therefore you must manually take "%s" and copy it to your Apache modules directory. 2. This script does not attempt to modify Apache configuration, you must do it manually: Edit %s, find where other LoadModule lines and add this: LoadModule python_module modules/mod_python.so 3. Now test your installation using the instructions at this link: http://www.modpython.org/live/current/doc-html/inst-testing.html """ % (mp, os.path.join(apachedir, "conf", "httpd.conf")) elif len(sys.argv) > 1 and sys.argv[1] == "-remove": mod_python_uninstall_log = os.path.join(distutils.sysconfig.get_python_lib(), 'mod_python_uninstall.log') f = file(mod_python_uninstall_log, 'rb') mod_python_so_path = f.read() f.close() os.remove(mod_python_so_path) os.remove(mod_python_uninstall_log) mod_python-3.3.1/dist/setup.py.in0000644000175000017500000001660510526735410015113 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # # $Id: setup.py.in 475516 2006-11-16 01:12:40Z grahamd $ from distutils.core import setup, Extension import sys import re import os.path try: __file__ except NameError: __file__ = '.' def getmp_rootdir(): """gets the root directory of the mod_python source tree...""" return os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) def getmp_srcdir(): """gets the src subdirectory of the mod_python source tree...""" return os.path.join(getmp_rootdir(), 'src') def getmp_includedir(): """gets the src subdirectory of the mod_python source tree...""" return os.path.join(getmp_rootdir(), 'src', 'include') def getconfigure_option(option_name): """gets an option from the config.status file""" config_status_file = os.path.join(getmp_rootdir(), 'config.status') if not os.path.exists(config_status_file): raise AssertionError("config.status not found in expected location (%s)" % config_status_file) header = open(config_status_file, 'r') r = re.compile(r's,\s*@%s@,\s*(?P[^,]+),\s*' % (option_name)) for line in header.readlines(): m = r.search(line) if m is not None: return m.group('OPTION_STRING') raise AssertionError("unable to find @%s@ definition in %s", (option_name, config_status_file)) def getmp_version(): """finds out the version of mod_python""" # if that fails, read it from the source file ourselves... mpversion_file = os.path.join(getmp_includedir(), 'mpversion.h') if not os.path.exists(mpversion_file): raise AssertionError("mpversion.h not found in expected location (%s)" % mpversion_file) header = open(mpversion_file, 'r') r = re.compile('#define\s+MPV_STRING\s+"(?P[^"]+)"') for line in header.readlines(): m = r.search(line) if m is not None: return m.group('MPV_STRING') raise AssertionError("unable to find MPV_STRING in %s", mpversion_file) def getapxs_location(): """finds the location of apxs from the config.status file""" return getconfigure_option("APXS") def getapxs_option(option): APXS = getapxs_location() import commands return commands.getoutput("%s -q %s" % (APXS, option)) def getapache_srcdir(): """returns apache src directory""" return os.getenv("APACHESRC") def getapache_includedir(): """returns apache include directory""" apache_srcdir = getapache_srcdir() if apache_srcdir is None: return getapxs_option("INCLUDEDIR") else: return os.path.join(getapache_srcdir(), "include") def getapache_libdir(): """returns apache lib directory""" apache_srcdir = getapache_srcdir() if apache_srcdir is None: return getapxs_option("LIBDIR") else: return os.path.join(apache_srcdir, "lib") VER = getmp_version() # TODO: improve the intelligence here... winbuild = ("bdist_wininst" in sys.argv) or (os.name == "nt") class PSPExtension(Extension): """a class that helps build the PSP extension""" def __init__(self, source_dir, include_dirs): Extension.__init__(self, "mod_python._psp", [os.path.join(source_dir, source_file) for source_file in ("psp_string.c", "psp_parser.c", "_pspmodule.c")], include_dirs=include_dirs ) if winbuild: self.define_macros.extend([('WIN32', None), ('NDEBUG', None), ('_WINDOWS', None)]) PSPModule = PSPExtension(getmp_srcdir(), [getmp_includedir()]) modpy_src_files = ("mod_python.c", "_apachemodule.c", "connobject.c", "filterobject.c", "hlist.c", "hlistobject.c", "requestobject.c", "serverobject.c", "tableobject.c", "util.c", "finfoobject.c") class finallist(list): """this represents a list that cannot be appended to...""" def append(self, object): return class ModPyExtension(Extension): """a class that actually builds the mod_python.so extension for Apache (yikes)""" def __init__(self, source_dir, include_dirs, library_dirs): if winbuild: apr1 = 0 for dir in library_dirs: if os.path.exists(os.path.join(dir, 'libapr-1.lib')): apr1 = 1 if apr1: libraries = ['libhttpd', 'libapr-1', 'libaprutil-1', 'ws2_32'] else: libraries = ['libhttpd', 'libapr', 'libaprutil', 'ws2_32'] else: libraries = ['apr-0', 'aprutil-0'] Extension.__init__(self, "mod_python_so", sources = [os.path.join(source_dir, source_file) for source_file in modpy_src_files], include_dirs=include_dirs, libraries = libraries, library_dirs=library_dirs ) if winbuild: self.define_macros.extend([('WIN32', None),('NDEBUG', None),('_WINDOWS', None)]) self.sources.append(os.path.join(source_dir, "Version.rc")) else: # TODO: fix this to autodetect if required... self.include_dirs.append("/usr/include/apr-0") # this is a hack to prevent build_ext from trying to append "initmod_python" to the export symbols self.export_symbols = finallist(self.export_symbols) if winbuild: # build mod_python.so ModPyModule = ModPyExtension(getmp_srcdir(), [getmp_includedir(), getapache_includedir()], [getapache_libdir()]) scripts = ["win32_postinstall.py"] # put the mod_python.so file in the Python root ... # win32_postinstall.py will pick it up from there... # data_files = [("", [(os.path.join(getmp_srcdir(), 'Release', 'mod_python.so'))])] data_files = [] ext_modules = [ModPyModule, PSPModule] else: scripts = [] data_files = [] ext_modules = [PSPModule] import string from distutils import sysconfig if sys.platform == "darwin": if not '-undefined' in sysconfig.get_config_var("LDSHARED").split(): sysconfig._config_vars["LDSHARED"] = \ string.replace(sysconfig.get_config_var("LDSHARED"), \ " -bundle "," -bundle -flat_namespace -undefined suppress ") sysconfig._config_vars["BLDSHARED"] = \ string.replace(sysconfig.get_config_var("BLDSHARED"), \ " -bundle "," -bundle -flat_namespace -undefined suppress ") setup(name="mod_python", version=VER, description="Apache/Python Integration", author="Gregory Trubetskoy et al", author_email="mod_python@modpython.org", url="http://www.modpython.org/", packages=["mod_python"], package_dir={'mod_python': os.path.join(getmp_rootdir(), 'lib', 'python', 'mod_python')}, scripts=scripts, data_files=data_files, ext_modules=ext_modules) # makes emacs go into python mode ### Local Variables: ### mode:python ### End: mod_python-3.3.1/dist/README0000644000175000017500000000017610151454154013645 0ustar jimjim$Id: README 106619 2004-11-25 22:10:52Z nd $ This directory contains files necessary for building mod_python distributions. mod_python-3.3.1/configure0000755000175000017500000037045410404444054013741 0ustar jimjim#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="src/mod_python.c" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT AR INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE APXS DSO ALL LIBEXECDIR SOLARIS_HACKS HTTPD AP_SRC AP_SRC_OWN AP_SRC_GRP STATIC PYTHON_BIN PY_STD_LIB INCLUDES TEST_SERVER_ROOT MOD_PYTHON_SO MP_VERSION PYTHON_SRC MUTEX_DIR MAX_LOCKS LEX LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-apxs=PATH Path to apxs --with-apache=DIR Path to Apache sources --with-python=PATH Path to specific Python binary --with-python-src=DIR Path to python sources - required if you want to generate the documenation --with-mutex-dir=DIR Mutex directory --with-max-locks=INTEGER Maximum number of locks --with-flex=PATH Path to specific flex binary. Flex Version 2.5.31 or greater is required to regenerate psp_parser.c from psp_parse.l. A prepared psp_parser.c file is included with the source, so you will only need flex if you make changes to psp_parser.l See the README for more information. Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd "$ac_popdir" done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # includes INCLUDES="-I`pwd`/src/include" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std1 is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std1. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu for ac_prog in ar aal do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_AR+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then echo "$as_me:$LINENO: result: $AR" >&5 echo "${ECHO_T}$AR" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$AR" && break done test -n "$AR" || AR="ar" ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi echo "$as_me:$LINENO: checking for main in -lm" >&5 echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6 if test "${ac_cv_lib_m_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_m_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_m_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5 echo "${ECHO_T}$ac_cv_lib_m_main" >&6 if test $ac_cv_lib_m_main = yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 if test "${ac_cv_c_const+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { /* FIXME: Include the comments suggested by Paul. */ #ifndef __cplusplus /* Ultrix mips cc rejects this. */ typedef int charset[2]; const charset x; /* SunOS 4.1.1 cc rejects this. */ char const *const *ccp; char **p; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; ccp = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++ccp; p = (char**) ccp; ccp = (char const *const *) p; { /* SCO 3.2v4 cc rejects this. */ char *t; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; }; struct s *b; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_const=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_const=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 echo "${ECHO_T}$ac_cv_c_const" >&6 if test $ac_cv_c_const = no; then cat >>confdefs.h <<\_ACEOF #define const _ACEOF fi ### humor lowers blood pressure echo "$as_me:$LINENO: checking your blood pressure" >&5 echo $ECHO_N "checking your blood pressure... $ECHO_C" >&6 echo "$as_me:$LINENO: result: a bit high, but we can proceed" >&5 echo "${ECHO_T}a bit high, but we can proceed" >&6 ## The goal is to find apxs { echo "$as_me:$LINENO: checking whether apxs is available..." >&5 echo "$as_me: checking whether apxs is available..." >&6;} # check for --with-apxs echo "$as_me:$LINENO: checking for --with-apxs" >&5 echo $ECHO_N "checking for --with-apxs... $ECHO_C" >&6 # Check whether --with-apxs or --without-apxs was given. if test "${with_apxs+set}" = set; then withval="$with_apxs" if test -x "$withval" then echo "$as_me:$LINENO: result: $withval executable, good" >&5 echo "${ECHO_T}$withval executable, good" >&6 APXS=$withval else echo { { echo "$as_me:$LINENO: error: $withval not found or not executable" >&5 echo "$as_me: error: $withval not found or not executable" >&2;} { (exit 1); exit 1; }; } fi else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi; # if no apxs found yet, check /usr/local/apache/sbin # since it's the default Apache location if test -z "$APXS"; then echo "$as_me:$LINENO: checking for apxs in /usr/local/apache/sbin" >&5 echo $ECHO_N "checking for apxs in /usr/local/apache/sbin... $ECHO_C" >&6 if test -x /usr/local/apache/sbin/apxs; then APXS=/usr/local/apache/sbin/apxs echo "$as_me:$LINENO: result: found, we'll use this. Use --with-apxs to specify another." >&5 echo "${ECHO_T}found, we'll use this. Use --with-apxs to specify another." >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi # second last resort if test -z "$APXS"; then echo "$as_me:$LINENO: checking for apxs in your PATH" >&5 echo $ECHO_N "checking for apxs in your PATH... $ECHO_C" >&6 # Extract the first word of "apxs", so it can be a program name with args. set dummy apxs; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_APXS+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $APXS in [\\/]* | ?:[\\/]*) ac_cv_path_APXS="$APXS" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_APXS="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi APXS=$ac_cv_path_APXS if test -n "$APXS"; then echo "$as_me:$LINENO: result: $APXS" >&5 echo "${ECHO_T}$APXS" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -n "$APXS"; then echo "$as_me:$LINENO: result: found $APXS, we'll use this. Use --with-apxs to specify another." >&5 echo "${ECHO_T}found $APXS, we'll use this. Use --with-apxs to specify another." >&6 fi fi # last resort # some linux distributions use apxs2 for apache2 installations, # so check for apxs2 before we give up. if test -z "$APXS"; then echo "$as_me:$LINENO: checking for apxs2 in your PATH" >&5 echo $ECHO_N "checking for apxs2 in your PATH... $ECHO_C" >&6 # Extract the first word of "apxs2", so it can be a program name with args. set dummy apxs2; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_APXS+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $APXS in [\\/]* | ?:[\\/]*) ac_cv_path_APXS="$APXS" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_APXS="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi APXS=$ac_cv_path_APXS if test -n "$APXS"; then echo "$as_me:$LINENO: result: $APXS" >&5 echo "${ECHO_T}$APXS" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -n "$APXS"; then echo "$as_me:$LINENO: result: found $APXS, we'll use this. Use --with-apxs to specify another." >&5 echo "${ECHO_T}found $APXS, we'll use this. Use --with-apxs to specify another." >&6 fi fi # if apxs was still not found, then no DSO if test -z "$APXS"; then { echo "$as_me:$LINENO: WARNING: **** apxs was not found, DSO compilation will not be available." >&5 echo "$as_me: WARNING: **** apxs was not found, DSO compilation will not be available." >&2;} { echo "$as_me:$LINENO: WARNING: **** You can use --with-apxs to specify where your apxs is." >&5 echo "$as_me: WARNING: **** You can use --with-apxs to specify where your apxs is." >&2;} DSO="no_dso" ALL="static" else DSO="do_dso" ALL="dso" # check Apache version echo "$as_me:$LINENO: checking Apache version" >&5 echo $ECHO_N "checking Apache version... $ECHO_C" >&6 HTTPD="`${APXS} -q SBINDIR`/`${APXS} -q TARGET`" ver=`$HTTPD -v | awk '/version/ {print $3}' | awk -F/ '{print $2}'` echo "$as_me:$LINENO: result: $ver" >&5 echo "${ECHO_T}$ver" >&6 # make sure version begins with 2 if test -z "`echo $ver | egrep \^2`"; then { { echo "$as_me:$LINENO: error: This version of mod_python only works with Apache 2. The one you have seems to be $ver." >&5 echo "$as_me: error: This version of mod_python only works with Apache 2. The one you have seems to be $ver." >&2;} { (exit 1); exit 1; }; } fi # determine LIBEXEC echo "$as_me:$LINENO: checking for Apache libexec directory" >&5 echo $ECHO_N "checking for Apache libexec directory... $ECHO_C" >&6 LIBEXECDIR=`${APXS} -q LIBEXECDIR` echo "$as_me:$LINENO: result: $LIBEXECDIR" >&5 echo "${ECHO_T}$LIBEXECDIR" >&6 # determine INCLUDES echo "$as_me:$LINENO: checking for Apache include directory" >&5 echo $ECHO_N "checking for Apache include directory... $ECHO_C" >&6 AP_INCLUDES="-I`${APXS} -q INCLUDEDIR`" echo "$as_me:$LINENO: result: $AP_INCLUDES" >&5 echo "${ECHO_T}$AP_INCLUDES" >&6 if test "`uname`" = "SunOS"; then echo "$as_me:$LINENO: checking for gcc on Solaris possible missing _eprintf problem" >&5 echo $ECHO_N "checking for gcc on Solaris possible missing _eprintf problem... $ECHO_C" >&6 if test "$CC" = "gcc"; then SOLARIS_HACKS="_eprintf.o _floatdidf.o _muldi3.o" fi echo "$as_me:$LINENO: result: \"done\"" >&5 echo "${ECHO_T}\"done\"" >&6 fi fi # check for --with-apache ## static is disabled, thus no --with-apache ##AC_MSG_CHECKING(for --with-apache) # Check whether --with-apache or --without-apache was given. if test "${with_apache+set}" = set; then withval="$with_apache" # temporarily disable static on 2.0 until I figure out how to # do it right { { echo "$as_me:$LINENO: error: Sorry, --with-apache (static compilation) is not supported at this time!" >&5 echo "$as_me: error: Sorry, --with-apache (static compilation) is not supported at this time!" >&2;} { (exit 1); exit 1; }; } AP_SRC=`cd $withval; pwd` if test ! -f "$AP_SRC/include/httpd.h"; then { { echo "$as_me:$LINENO: error: $withval does not look like an Apache 2.0 source directory." >&5 echo "$as_me: error: $withval does not look like an Apache 2.0 source directory." >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: result: $AP_SRC" >&5 echo "${ECHO_T}$AP_SRC" >&6 AP_INCLUDES="-I${AP_SRC}/src/include -I${AP_SRC}/src/os/unix" # note who owns the apache source directory AP_SRC_OWN="`ls -ld $AP_SRC | awk '{print $3}'`" AP_SRC_GRP="`ls -ld $AP_SRC | awk '{print $4}'`" fi; ##AC_MSG_RESULT(no)) if test -z "$AP_SRC"; then ## AC_MSG_WARN([**** No apache sources specified, static compilation will not be available.]) ## AC_MSG_WARN([**** You can use --with-apache to specify where your Apache sources are.]) STATIC="no_static" else STATIC="do_static" fi if test "$STATIC" = "no_static" -a "$DSO" = "no_dso"; then { { echo "$as_me:$LINENO: error: Neither static nor DSO option available, there is no point in continuing." >&5 echo "$as_me: error: Neither static nor DSO option available, there is no point in continuing." >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:$LINENO: checking for --with-python" >&5 echo $ECHO_N "checking for --with-python... $ECHO_C" >&6 # Check whether --with-python or --without-python was given. if test "${with_python+set}" = set; then withval="$with_python" PYTHON_BIN="$withval" echo "$as_me:$LINENO: result: $PYTHON_BIN" >&5 echo "${ECHO_T}$PYTHON_BIN" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi; # check for Python executable if test -z "$PYTHON_BIN"; then # Extract the first word of "python", so it can be a program name with args. set dummy python; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_PYTHON_BIN+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $PYTHON_BIN in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON_BIN="$PYTHON_BIN" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON_BIN="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi PYTHON_BIN=$ac_cv_path_PYTHON_BIN if test -n "$PYTHON_BIN"; then echo "$as_me:$LINENO: result: $PYTHON_BIN" >&5 echo "${ECHO_T}$PYTHON_BIN" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi if test -z "$PYTHON_BIN"; then { { echo "$as_me:$LINENO: error: python binary not found in path" >&5 echo "$as_me: error: python binary not found in path" >&2;} { (exit 1); exit 1; }; } fi fi # find out python version echo "$as_me:$LINENO: checking Python version" >&5 echo $ECHO_N "checking Python version... $ECHO_C" >&6 PyVERSION=`$PYTHON_BIN -c 'import sys; print sys.version[:3]'` PyMAJVERSION=`$PYTHON_BIN -c 'import sys; print sys.version[:1]'` echo "$as_me:$LINENO: result: $PyVERSION" >&5 echo "${ECHO_T}$PyVERSION" >&6 # make sure Python is version 2 if test "$PyMAJVERSION" != "2"; then { { echo "$as_me:$LINENO: error: This version of mod_python only works with Python major version 2. The one you have seems to be $PyVERSION." >&5 echo "$as_me: error: This version of mod_python only works with Python major version 2. The one you have seems to be $PyVERSION." >&2;} { (exit 1); exit 1; }; } fi # find out compiled in install prefix echo "$as_me:$LINENO: checking Python install prefix" >&5 echo $ECHO_N "checking Python install prefix... $ECHO_C" >&6 PyEXEC_INSTALLDIR=`$PYTHON_BIN -c "import sys; print sys.exec_prefix"` echo "$as_me:$LINENO: result: $PyEXEC_INSTALLDIR" >&5 echo "${ECHO_T}$PyEXEC_INSTALLDIR" >&6 # this is where the Python libraries will get installed echo "$as_me:$LINENO: checking checking where python libraries are installed" >&5 echo $ECHO_N "checking checking where python libraries are installed... $ECHO_C" >&6 PY_STD_LIB=`$PYTHON_BIN -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(plat_specific=1, standard_lib=1)'` echo "$as_me:$LINENO: result: $PY_STD_LIB" >&5 echo "${ECHO_T}$PY_STD_LIB" >&6 # set python std library variable PyLIBP=${PY_STD_LIB} PyLIBPL=${PyLIBP}/config PyPYTHONLIBS=${PyLIBPL}/libpython${PyVERSION}.a PyLIBS=`grep "^LIB[SMC]=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyMODLIBS=`grep "^LOCALMODLIBS=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyFRAMEWORK=`grep "^PYTHONFRAMEWORK=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyFRAMEWORKDIR=`grep "^PYTHONFRAMEWORKDIR=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' ' | awk '{print $1}'` save_LDFLAGS="$LDFLAGS" save_LIBS="$LIBS" if test "$PyFRAMEWORKDIR" != "no-framework"; then if test -n "$PyFRAMEWORK"; then PyPYTHONLIBS="-framework $PyFRAMEWORK" LDFLAGS="${LDFLAGS} -Wl,-framework,Python" fi else LDFLAGS="${LDFLAGS} -L${PyLIBPL}" as_ac_Lib=`echo "ac_cv_lib_python${PyVERSION}''_Py_NewInterpreter" | $as_tr_sh` echo "$as_me:$LINENO: checking for Py_NewInterpreter in -lpython${PyVERSION}" >&5 echo $ECHO_N "checking for Py_NewInterpreter in -lpython${PyVERSION}... $ECHO_C" >&6 if eval "test \"\${$as_ac_Lib+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpython${PyVERSION} ${PyLIBS} ${PyMODLIBS} $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char Py_NewInterpreter (); int main () { Py_NewInterpreter (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Lib=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Lib=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Lib'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Lib'}'`" >&6 if test `eval echo '${'$as_ac_Lib'}'` = yes; then PyPYTHONLIBS="-lpython${PyVERSION}" else LDFLAGS="$save_LDFLAGS" if test -f ${PyLIBPL}/libpython${PyVERSION}.a; then PyPYTHONLIBS=${PyLIBPL}/libpython${PyVERSION}.a else { { echo "$as_me:$LINENO: error: Can not link to python" >&5 echo "$as_me: error: Can not link to python" >&2;} { (exit 1); exit 1; }; } fi fi fi LIBS="$save_LIBS" # (actually this check already just happened above) echo "$as_me:$LINENO: checking what libraries Python was linked with" >&5 echo $ECHO_N "checking what libraries Python was linked with... $ECHO_C" >&6 PY_LIBS="${PyPYTHONLIBS} ${PyLIBS} ${PyMODLIBS}" ## XXX this is a small work around for a weird RedHat problem ## erase -lieee from library list if test -f /etc/redhat-release; then PY_LIBS="`echo $PY_LIBS | sed s/-lieee//`" fi LIBS="${LIBS} ${PY_LIBS}" echo "$as_me:$LINENO: result: $PY_LIBS" >&5 echo "${ECHO_T}$PY_LIBS" >&6 echo "$as_me:$LINENO: checking linker flags used to link Python" >&5 echo $ECHO_N "checking linker flags used to link Python... $ECHO_C" >&6 PyLFS=`grep "^LINKFORSHARED=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyLDFLAGS=`grep "^LDFLAGS=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` LDFLAGS="${LDFLAGS} ${PyLFS} ${PyLDFLAGS}" LDFLAGS="${LDFLAGS} ${PY_LDFLAGS}" echo "$as_me:$LINENO: result: $PY_LDFLAGS" >&5 echo "${ECHO_T}$PY_LDFLAGS" >&6 echo "$as_me:$LINENO: checking where Python include files are" >&5 echo $ECHO_N "checking where Python include files are... $ECHO_C" >&6 PY_INCLUDES="-I${PyEXEC_INSTALLDIR}/include/python${PyVERSION}" INCLUDES="${INCLUDES} ${AP_INCLUDES} ${PY_INCLUDES}" echo "$as_me:$LINENO: result: $PY_INCLUDES" >&5 echo "${ECHO_T}$PY_INCLUDES" >&6 # this for the test.py script TEST_SERVER_ROOT="`pwd`/test" MOD_PYTHON_SO="`pwd`/src/mod_python.so" # get the mod_python version MP_VERSION=`awk '/MPV_STRING/ {print $3}' src/include/mpversion.h` MP_VERSION=`echo $MP_VERSION | sed 's/"//g'` # get --with-python-src. The python src is required to generate the documentation # It is not required to compile or install mod_python itself echo "$as_me:$LINENO: checking for --with-python-src" >&5 echo $ECHO_N "checking for --with-python-src... $ECHO_C" >&6 # Check whether --with-python-src or --without-python-src was given. if test "${with_python_src+set}" = set; then withval="$with_python_src" PYTHON_SRC="$withval" echo "$as_me:$LINENO: result: $PYTHON_SRC" >&5 echo "${ECHO_T}$PYTHON_SRC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi; if test -z "$PYTHON_SRC"; then PYTHON_SRC="" fi # configure the MUTEX_DIR for location of mutex locks echo "$as_me:$LINENO: checking for --with-mutex-dir" >&5 echo $ECHO_N "checking for --with-mutex-dir... $ECHO_C" >&6 # Check whether --with-mutex-dir or --without-mutex-dir was given. if test "${with_mutex_dir+set}" = set; then withval="$with_mutex_dir" MUTEX_DIR="$withval" echo "$as_me:$LINENO: result: $MUTEX_DIR" >&5 echo "${ECHO_T}$MUTEX_DIR" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi; if test -z "$MUTEX_DIR"; then MUTEX_DIR="/tmp" fi # TODO - check if MUTEX_DIR is an absolute path echo "$as_me:$LINENO: result: Using MUTEX_DIR $MUTEX_DIR" >&5 echo "${ECHO_T}Using MUTEX_DIR $MUTEX_DIR" >&6 # configure the MAX_LOCKS for number of mutex locks echo "$as_me:$LINENO: checking for --with-max-locks" >&5 echo $ECHO_N "checking for --with-max-locks... $ECHO_C" >&6 # Check whether --with-max-locks or --without-max-locks was given. if test "${with_max_locks+set}" = set; then withval="$with_max_locks" MAX_LOCKS="$withval" echo "$as_me:$LINENO: result: $MAX_LOCKS" >&5 echo "${ECHO_T}$MAX_LOCKS" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi; if test -z "$MAX_LOCKS"; then MAX_LOCKS="8" fi echo "$as_me:$LINENO: result: Using $MAX_LOCKS MAX_LOCKS." >&5 echo "${ECHO_T}Using $MAX_LOCKS MAX_LOCKS." >&6 # Check for correct flex version # Requires flex 2.5.31 for reentrant support # See README for more details echo "$as_me:$LINENO: checking for --with-flex" >&5 echo $ECHO_N "checking for --with-flex... $ECHO_C" >&6 # Check whether --with-flex or --without-flex was given. if test "${with_flex+set}" = set; then withval="$with_flex" LEX="$withval" echo "$as_me:$LINENO: result: $LEX" >&5 echo "${ECHO_T}$LEX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi; # check for flex executable if test -z "$LEX"; then # Extract the first word of "flex", so it can be a program name with args. set dummy flex; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_LEX+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $LEX in [\\/]* | ?:[\\/]*) ac_cv_path_LEX="$LEX" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_LEX="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done ;; esac fi LEX=$ac_cv_path_LEX if test -n "$LEX"; then echo "$as_me:$LINENO: result: $LEX" >&5 echo "${ECHO_T}$LEX" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test "$LEX" && test -x "$LEX"; then echo "$as_me:$LINENO: result: found $LEX, we'll use this. Use --with-flex to specify another." >&5 echo "${ECHO_T}found $LEX, we'll use this. Use --with-flex to specify another." >&6 echo "$as_me:$LINENO: checking flex version" >&5 echo $ECHO_N "checking flex version... $ECHO_C" >&6 FlexVERSION=`$LEX --version | sed 's/version//g' | awk '/flex/ {print $2}'` Flex_MAJOR=`echo $FlexVERSION| awk -F . '{print $1}'` Flex_MINOR=`echo $FlexVERSION| awk -F . '{print $2}'` Flex_PATCH=`echo $FlexVERSION| awk -F . '{print $3}'` if test "$Flex_MAJOR" -eq "2" && test "$Flex_MINOR" -eq "5" && test "$Flex_PATCH" -ge "31"; then echo "$as_me:$LINENO: result: $FlexVERSION. Good" >&5 echo "${ECHO_T}$FlexVERSION. Good" >&6 else { echo "$as_me:$LINENO: WARNING: Flex version $FlexVERSION found. Version 2.5.31 or greater is required. You can generally ignore this warning unless you need to regenerate psp_parser.c from psp_parse.l. If you do need regenerate psp_parser.c, use --with-flex to specify the location of the correct flex version. See the README for more information." >&5 echo "$as_me: WARNING: Flex version $FlexVERSION found. Version 2.5.31 or greater is required. You can generally ignore this warning unless you need to regenerate psp_parser.c from psp_parse.l. If you do need regenerate psp_parser.c, use --with-flex to specify the location of the correct flex version. See the README for more information." >&2;} fi else { echo "$as_me:$LINENO: WARNING: flex $LEX not found You can generally ignore this warning unless you need to regenerate psp_parser.c from psp_parse.l. If you do need regenerate psp_parser.c, use --with-flex to specify the location of flex. See the README for more information." >&5 echo "$as_me: WARNING: flex $LEX not found You can generally ignore this warning unless you need to regenerate psp_parser.c from psp_parse.l. If you do need regenerate psp_parser.c, use --with-flex to specify the location of flex. See the README for more information." >&2;} fi ac_config_files="$ac_config_files Makefile src/Makefile Doc/Makefile src/include/mod_python.h test/Makefile test/testconf.py dist/setup.py dist/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "Doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES Doc/Makefile" ;; "src/include/mod_python.h" ) CONFIG_FILES="$CONFIG_FILES src/include/mod_python.h" ;; "test/Makefile" ) CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; "test/testconf.py" ) CONFIG_FILES="$CONFIG_FILES test/testconf.py" ;; "dist/setup.py" ) CONFIG_FILES="$CONFIG_FILES dist/setup.py" ;; "dist/Makefile" ) CONFIG_FILES="$CONFIG_FILES dist/Makefile" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@AR@,$AR,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@APXS@,$APXS,;t t s,@DSO@,$DSO,;t t s,@ALL@,$ALL,;t t s,@LIBEXECDIR@,$LIBEXECDIR,;t t s,@SOLARIS_HACKS@,$SOLARIS_HACKS,;t t s,@HTTPD@,$HTTPD,;t t s,@AP_SRC@,$AP_SRC,;t t s,@AP_SRC_OWN@,$AP_SRC_OWN,;t t s,@AP_SRC_GRP@,$AP_SRC_GRP,;t t s,@STATIC@,$STATIC,;t t s,@PYTHON_BIN@,$PYTHON_BIN,;t t s,@PY_STD_LIB@,$PY_STD_LIB,;t t s,@INCLUDES@,$INCLUDES,;t t s,@TEST_SERVER_ROOT@,$TEST_SERVER_ROOT,;t t s,@MOD_PYTHON_SO@,$MOD_PYTHON_SO,;t t s,@MP_VERSION@,$MP_VERSION,;t t s,@PYTHON_SRC@,$PYTHON_SRC,;t t s,@MUTEX_DIR@,$MUTEX_DIR,;t t s,@MAX_LOCKS@,$MAX_LOCKS,;t t s,@LEX@,$LEX,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi mod_python-3.3.1/NOTICE0000644000175000017500000000065310151454154012726 0ustar jimjimThis product includes software developed by The Apache Software Foundation (http://www.apache.org/). Mod_python was originally developed by Gregory Trubetskoy. This software is based on the original concept as published in the book "Internet Programming with Python" by Aaron Watters, Guido van Rossum and James C. Ahlstrom, 1996 M&T Books, ISBN: 1-55851-484-8. The book and original software is Copyright 1996 by M&T Books. mod_python-3.3.1/Makefile.in0000644000175000017500000000437310404341634014071 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Originally developed by Gregory Trubetskoy. # @SET_MAKE@ LIBEXECDIR=@LIBEXECDIR@ AP_SRC=@AP_SRC@ AP_SRC_OWN=@AP_SRC_OWN@ AP_SRC_GRP=@AP_SRC_GRP@ INSTALL=@INSTALL@ PYTHON_BIN=@PYTHON_BIN@ PY_STD_LIB=@PY_STD_LIB@ all: @ALL@ dso: @DSO@ do_dso: @cd src && $(MAKE) @cd dist && $(MAKE) build @echo @echo 'Now su and make install' @echo ' (or, if you only want to perform a partial install,' @echo ' you can use make install_dso and make install_py_lib)' @echo no_dso: @echo @echo "DSO compilation not available. (Probably because apxs could not be found)." @echo static: @STATIC@ no_static: @echo @echo "Static compilation not available. (Probably because --with-apache was not specified)." @echo install: src/.install @if test "`cat src/.install`" = "dso"; then \ $(MAKE) install_dso; \ $(MAKE) install_py_lib; \ else $(MAKE) install_static; fi install_dso: dso @echo @echo "Performing DSO installation." @echo $(INSTALL) -d $(DESTDIR)$(LIBEXECDIR) $(INSTALL) src/mod_python.so $(DESTDIR)$(LIBEXECDIR) @echo @echo "Now don't forget to edit your main config and add" @echo " LoadModule python_module $(LIBEXECDIR)/mod_python.so" @echo "and if your configuration uses ClearModuleList, then also" @echo " AddModule mod_python.c" @echo install_py_lib: cd dist && $(MAKE) install_py_lib clean: cd src && $(MAKE) clean cd dist && $(MAKE) clean cd test && $(MAKE) clean rm -f core distclean: clean cd src && $(MAKE) distclean cd Doc && $(MAKE) distclean cd dist && $(MAKE) distclean cd test && $(MAKE) distclean rm -rf Makefile config.h config.status config.cache config.log \ test/testconf.py check: cd test && $(MAKE) check mod_python-3.3.1/LICENSE0000644000175000017500000002613610151454154013033 0ustar jimjim Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. mod_python-3.3.1/configure.in0000644000175000017500000002770010404444054014334 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Originally developed by Gregory Trubetskoy. # dnl Process this file with autoconf to produce a configure script. AC_INIT(src/mod_python.c) # includes INCLUDES="-I`pwd`/src/include" dnl Checks for programs. AC_PROG_CC AC_SUBST(AR) AC_CHECK_PROGS(AR, ar aal, ar) AC_PROG_INSTALL AC_PROG_MAKE_SET dnl Replace `main' with a function in -lm: AC_CHECK_LIB(m, main) dnl Checks for header files. dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST ### humor lowers blood pressure AC_MSG_CHECKING(your blood pressure) AC_MSG_RESULT([a bit high, but we can proceed]) ## The goal is to find apxs AC_CHECKING(whether apxs is available) AC_SUBST(APXS) AC_SUBST(DSO) AC_SUBST(ALL) # check for --with-apxs AC_MSG_CHECKING(for --with-apxs) AC_ARG_WITH(apxs, [--with-apxs=PATH Path to apxs], [ if test -x "$withval" then AC_MSG_RESULT([$withval executable, good]) APXS=$withval else echo AC_MSG_ERROR([$withval not found or not executable]) fi ], AC_MSG_RESULT(no)) # if no apxs found yet, check /usr/local/apache/sbin # since it's the default Apache location if test -z "$APXS"; then AC_MSG_CHECKING(for apxs in /usr/local/apache/sbin) if test -x /usr/local/apache/sbin/apxs; then APXS=/usr/local/apache/sbin/apxs AC_MSG_RESULT([found, we'll use this. Use --with-apxs to specify another.]) else AC_MSG_RESULT(no) fi fi # second last resort if test -z "$APXS"; then AC_MSG_CHECKING(for apxs in your PATH) AC_PATH_PROG(APXS, apxs) if test -n "$APXS"; then AC_MSG_RESULT([found $APXS, we'll use this. Use --with-apxs to specify another.]) fi fi # last resort # some linux distributions use apxs2 for apache2 installations, # so check for apxs2 before we give up. if test -z "$APXS"; then AC_MSG_CHECKING(for apxs2 in your PATH) AC_PATH_PROG(APXS, apxs2) if test -n "$APXS"; then AC_MSG_RESULT([found $APXS, we'll use this. Use --with-apxs to specify another.]) fi fi # if apxs was still not found, then no DSO AC_SUBST(LIBEXECDIR) AC_SUBST(SOLARIS_HACKS) AC_SUBST(HTTPD) if test -z "$APXS"; then AC_MSG_WARN([**** apxs was not found, DSO compilation will not be available.]) AC_MSG_WARN([**** You can use --with-apxs to specify where your apxs is.]) DSO="no_dso" ALL="static" else DSO="do_dso" ALL="dso" # check Apache version AC_MSG_CHECKING(Apache version) HTTPD="`${APXS} -q SBINDIR`/`${APXS} -q TARGET`" ver=`$HTTPD -v | awk '/version/ {print $3}' | awk -F/ '{print $2}'` AC_MSG_RESULT($ver) # make sure version begins with 2 if test -z "`echo $ver | egrep \^2`"; then AC_MSG_ERROR([This version of mod_python only works with Apache 2. The one you have seems to be $ver.]) fi # determine LIBEXEC AC_MSG_CHECKING(for Apache libexec directory) LIBEXECDIR=`${APXS} -q LIBEXECDIR` AC_MSG_RESULT($LIBEXECDIR) # determine INCLUDES AC_MSG_CHECKING([for Apache include directory]) AP_INCLUDES="-I`${APXS} -q INCLUDEDIR`" AC_MSG_RESULT($AP_INCLUDES) dnl Small hack to work around _eprintf.o problem on Solaris if test "`uname`" = "SunOS"; then AC_MSG_CHECKING([for gcc on Solaris possible missing _eprintf problem]) if test "$CC" = "gcc"; then SOLARIS_HACKS="_eprintf.o _floatdidf.o _muldi3.o" fi AC_MSG_RESULT("done") fi fi # check for --with-apache AC_SUBST(AP_SRC) AC_SUBST(AP_SRC_OWN) AC_SUBST(AP_SRC_GRP) ## static is disabled, thus no --with-apache ##AC_MSG_CHECKING(for --with-apache) AC_ARG_WITH(apache, [--with-apache=DIR Path to Apache sources], [ # temporarily disable static on 2.0 until I figure out how to # do it right AC_MSG_ERROR([Sorry, --with-apache (static compilation) is not supported at this time!]) AP_SRC=`cd $withval; pwd` dnl Make sure this looks like Apache source if test ! -f "$AP_SRC/include/httpd.h"; then AC_MSG_ERROR([$withval does not look like an Apache 2.0 source directory.]) fi AC_MSG_RESULT($AP_SRC) AP_INCLUDES="-I${AP_SRC}/src/include -I${AP_SRC}/src/os/unix" # note who owns the apache source directory AP_SRC_OWN="`ls -ld $AP_SRC | awk '{print $3}'`" AP_SRC_GRP="`ls -ld $AP_SRC | awk '{print $4}'`" ],) ##AC_MSG_RESULT(no)) AC_SUBST(STATIC) if test -z "$AP_SRC"; then ## AC_MSG_WARN([**** No apache sources specified, static compilation will not be available.]) ## AC_MSG_WARN([**** You can use --with-apache to specify where your Apache sources are.]) STATIC="no_static" else STATIC="do_static" fi if test "$STATIC" = "no_static" -a "$DSO" = "no_dso"; then AC_MSG_ERROR([Neither static nor DSO option available, there is no point in continuing.]) fi AC_SUBST(PYTHON_BIN) AC_MSG_CHECKING(for --with-python) AC_ARG_WITH(python, [--with-python=PATH Path to specific Python binary], [ PYTHON_BIN="$withval" AC_MSG_RESULT($PYTHON_BIN) ], AC_MSG_RESULT(no)) # check for Python executable if test -z "$PYTHON_BIN"; then AC_PATH_PROG(PYTHON_BIN, python) if test -z "$PYTHON_BIN"; then AC_MSG_ERROR(python binary not found in path) fi fi # find out python version AC_MSG_CHECKING(Python version) PyVERSION=`$PYTHON_BIN -c ['import sys; print sys.version[:3]'`] PyMAJVERSION=`$PYTHON_BIN -c ['import sys; print sys.version[:1]'`] AC_MSG_RESULT($PyVERSION) # make sure Python is version 2 if test "$PyMAJVERSION" != "2"; then AC_MSG_ERROR([This version of mod_python only works with Python major version 2. The one you have seems to be $PyVERSION.]) fi # find out compiled in install prefix AC_MSG_CHECKING(Python install prefix) PyEXEC_INSTALLDIR=`$PYTHON_BIN -c "import sys; print sys.exec_prefix"` AC_MSG_RESULT($PyEXEC_INSTALLDIR) # this is where the Python libraries will get installed AC_SUBST(PY_STD_LIB) AC_MSG_CHECKING(checking where python libraries are installed) PY_STD_LIB=`$PYTHON_BIN -c 'import distutils.sysconfig; print distutils.sysconfig.get_python_lib(plat_specific=1, standard_lib=1)'` AC_MSG_RESULT($PY_STD_LIB) # set python std library variable AC_SUBST(LIBS) PyLIBP=${PY_STD_LIB} PyLIBPL=${PyLIBP}/config PyPYTHONLIBS=${PyLIBPL}/libpython${PyVERSION}.a PyLIBS=`grep "^LIB[[SMC]]=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyMODLIBS=`grep "^LOCALMODLIBS=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyFRAMEWORK=`grep "^PYTHONFRAMEWORK=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyFRAMEWORKDIR=`grep "^PYTHONFRAMEWORKDIR=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' ' | awk '{print $1}'` save_LDFLAGS="$LDFLAGS" save_LIBS="$LIBS" if test "$PyFRAMEWORKDIR" != "no-framework"; then if test -n "$PyFRAMEWORK"; then PyPYTHONLIBS="-framework $PyFRAMEWORK" LDFLAGS="${LDFLAGS} -Wl,-framework,Python" fi else LDFLAGS="${LDFLAGS} -L${PyLIBPL}" AC_CHECK_LIB(python${PyVERSION}, Py_NewInterpreter, [ PyPYTHONLIBS="-lpython${PyVERSION}" ], [ LDFLAGS="$save_LDFLAGS" if test -f ${PyLIBPL}/libpython${PyVERSION}.a; then PyPYTHONLIBS=${PyLIBPL}/libpython${PyVERSION}.a else AC_ERROR(Can not link to python) fi ], [ ${PyLIBS} ${PyMODLIBS} ] ) fi LIBS="$save_LIBS" # (actually this check already just happened above) AC_MSG_CHECKING(what libraries Python was linked with) PY_LIBS="${PyPYTHONLIBS} ${PyLIBS} ${PyMODLIBS}" ## XXX this is a small work around for a weird RedHat problem ## erase -lieee from library list if test -f /etc/redhat-release; then PY_LIBS="`echo $PY_LIBS | sed s/-lieee//`" fi LIBS="${LIBS} ${PY_LIBS}" AC_MSG_RESULT($PY_LIBS) AC_MSG_CHECKING(linker flags used to link Python) AC_SUBST(LDFLAGS) PyLFS=`grep "^LINKFORSHARED=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` PyLDFLAGS=`grep "^LDFLAGS=" ${PyLIBPL}/Makefile | cut -f2 -d= | tr '\011\012\015' ' '` LDFLAGS="${LDFLAGS} ${PyLFS} ${PyLDFLAGS}" LDFLAGS="${LDFLAGS} ${PY_LDFLAGS}" AC_MSG_RESULT($PY_LDFLAGS) AC_MSG_CHECKING(where Python include files are) AC_SUBST(INCLUDES) PY_INCLUDES="-I${PyEXEC_INSTALLDIR}/include/python${PyVERSION}" INCLUDES="${INCLUDES} ${AP_INCLUDES} ${PY_INCLUDES}" AC_MSG_RESULT($PY_INCLUDES) # this for the test.py script AC_SUBST(TEST_SERVER_ROOT) TEST_SERVER_ROOT="`pwd`/test" AC_SUBST(MOD_PYTHON_SO) MOD_PYTHON_SO="`pwd`/src/mod_python.so" # get the mod_python version AC_SUBST(MP_VERSION) MP_VERSION=`awk '/MPV_STRING/ {print $3}' src/include/mpversion.h` MP_VERSION=`echo $MP_VERSION | sed 's/["]//g'` # get --with-python-src. The python src is required to generate the documentation # It is not required to compile or install mod_python itself AC_SUBST(PYTHON_SRC) AC_MSG_CHECKING(for --with-python-src) AC_ARG_WITH(python-src, [--with-python-src=DIR Path to python sources - required if you want to generate the documenation], [ PYTHON_SRC="$withval" AC_MSG_RESULT($PYTHON_SRC) ], AC_MSG_RESULT(no)) if test -z "$PYTHON_SRC"; then PYTHON_SRC="" fi # configure the MUTEX_DIR for location of mutex locks AC_SUBST(MUTEX_DIR) AC_MSG_CHECKING(for --with-mutex-dir) AC_ARG_WITH(mutex-dir, [--with-mutex-dir=DIR Mutex directory], [ MUTEX_DIR="$withval" AC_MSG_RESULT($MUTEX_DIR) ], AC_MSG_RESULT(no)) if test -z "$MUTEX_DIR"; then MUTEX_DIR="/tmp" fi # TODO - check if MUTEX_DIR is an absolute path AC_MSG_RESULT([Using MUTEX_DIR $MUTEX_DIR]) # configure the MAX_LOCKS for number of mutex locks AC_SUBST(MAX_LOCKS) AC_MSG_CHECKING(for --with-max-locks) AC_ARG_WITH(max-locks, [--with-max-locks=INTEGER Maximum number of locks], [ MAX_LOCKS="$withval" AC_MSG_RESULT($MAX_LOCKS) ], AC_MSG_RESULT(no)) if test -z "$MAX_LOCKS"; then MAX_LOCKS="8" fi AC_MSG_RESULT([Using $MAX_LOCKS MAX_LOCKS.]) # Check for correct flex version # Requires flex 2.5.31 for reentrant support # See README for more details AC_SUBST(LEX) AC_MSG_CHECKING(for --with-flex) AC_ARG_WITH(flex, [--with-flex=PATH Path to specific flex binary. Flex Version 2.5.31 or greater is required to regenerate psp_parser.c from psp_parse.l. A prepared psp_parser.c file is included with the source, so you will only need flex if you make changes to psp_parser.l See the README for more information.], [ LEX="$withval" AC_MSG_RESULT($LEX) ], AC_MSG_RESULT(no)) # check for flex executable if test -z "$LEX"; then AC_PATH_PROG(LEX, flex) fi if test "$LEX" && test -x "$LEX"; then AC_MSG_RESULT([found $LEX, we'll use this. Use --with-flex to specify another.]) AC_MSG_CHECKING(flex version) FlexVERSION=`$LEX --version | sed 's/version//g' | awk '/flex/ {print $2}'` Flex_MAJOR=`echo $FlexVERSION| awk -F . '{print $1}'` Flex_MINOR=`echo $FlexVERSION| awk -F . '{print $2}'` Flex_PATCH=`echo $FlexVERSION| awk -F . '{print $3}'` if test "$Flex_MAJOR" -eq "2" && test "$Flex_MINOR" -eq "5" && test "$Flex_PATCH" -ge "31"; then AC_MSG_RESULT([$FlexVERSION. Good]) else AC_MSG_WARN([Flex version $FlexVERSION found. Version 2.5.31 or greater is required. You can generally ignore this warning unless you need to regenerate psp_parser.c from psp_parse.l. If you do need regenerate psp_parser.c, use --with-flex to specify the location of the correct flex version. See the README for more information.]) fi else AC_MSG_WARN([flex $LEX not found You can generally ignore this warning unless you need to regenerate psp_parser.c from psp_parse.l. If you do need regenerate psp_parser.c, use --with-flex to specify the location of flex. See the README for more information.]) fi AC_OUTPUT(Makefile src/Makefile Doc/Makefile src/include/mod_python.h test/Makefile test/testconf.py dist/setup.py dist/Makefile) mod_python-3.3.1/Doc/0000755000175000017500000000000010557377762012546 5ustar jimjimmod_python-3.3.1/Doc/modpython.tex0000644000175000017500000000324710402210253015261 0ustar jimjim\documentclass{manual} \title{Mod\_python Manual} \author{Gregory Trubetskoy} % Please at least include a long-lived email address; % the rest is at your discretion. \authoraddress{ E-mail: \email{grisha@apache.org} } % do not mess with the 2 lines below, they are written by make dist \release{3.1.3} \date{February 17, 2004} \makeindex % tell \index to actually write the .idx file \makemodindex % If this contains a lot of module sections. \begin{document} \maketitle % This makes the contents more accessible from the front page of the HTML. \ifhtml \chapter*{Front Matter\label{front}} \fi \input{copyright} \begin{abstract} \noindent Mod_python allows embedding Python within the Apache server for a considerable boost in performance and added flexibility in designing web based applications. This document aims to be the only necessary and authoritative source of information about mod_python, usable as a comprehensive reference, a user guide and a tutorial all-in-one. \begin{seealso} \seetitle[http://www.python.org/] {Python Language Web Site}{for information on the Python language} \seetitle[http://httpd.apache.org/] {Apache Server Web Site}{for information on the Apache server} \end{seealso} \end{abstract} \tableofcontents \input{modpython1} % Introduction \input{modpython2} % Installation \input{modpython3} % Tutorial \input{modpython4} % Python API \input{modpython5} % Apache directives \input{modpython6} % Handlers \input{modpython7} % Security \appendix %\input{appendixa} % Windows Install %\input{appendixb} % VMS Install \input{appendixc} % Changes \input{modpython.ind} \end{document} mod_python-3.3.1/Doc/Makefile.in0000644000175000017500000001044010402176342014566 0ustar jimjim # Copyright 2004 Apache Software Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Originally developed by Gregory Trubetskoy. # # # Makefile for mod_python documentation # --------------------------------- # # See also the README file. # # You need to set this manually # or ./configure --with-python-src=path/to/python/src PYTHON_SRC=@PYTHON_SRC@ # This is the *documentation* release, and is used to construct the file # names of the downloadable tarballs. RELEASE= 2.7 MKHOWTO= $(PYTHON_SRC)/Doc/tools/mkhowto # These must be declared phony since there # are directories with matching names: .PHONY: html # This can be changed to a4 PAPER= letter MPFILES= modpython.tex \ copyright.tex \ modpython1.tex \ modpython2.tex \ modpython3.tex \ modpython5.tex \ modpython6.tex \ modpython7.tex \ appendixa.tex \ appendixb.tex # this target pukes if we don't have PYTHON_SRC set src_set: @if test -z "$(PYTHON_SRC)"; then \ echo; \ echo "Please edit Makefile and set PYTHON_SRC to where Python sources are."; \ echo; \ exit 1; \ fi # Main target all: pdf dvi: $(MPFILES) src_set $(MKHOWTO) --dvi modpython.tex pdf: $(MPFILES) src_set $(MKHOWTO) --pdf --$(PAPER) modpython.tex ps: $(MPFILES) src_set $(MKHOWTO) --ps --$(PAPER) modpython.tex html: $(MPFILES) src_set $(MKHOWTO) --html modpython.tex mkdir -p modpython/icons cp $(PYTHON_SRC)/Doc/html/icons/* modpython/icons/ rm -f modpython/modpython.how # the iconserver option of mkhowto is broken since it writes # it to the end if the init_file where they aren't useful anymore, # so we work around it: for f in `find modpython -type f`; do \ cat $$f | sed s/\.\.\\/icons/icons/g > $${f}2; \ mv $${f}2 $$f; \ done world: ps pdf html tarballs # Release packaging targets: pdf-$(PAPER)-$(RELEASE).tgz: pdf tar cf - *.pdf | gzip -9 >$@ pdf-$(PAPER)-$(RELEASE).tar.bz2: pdf tar cf - *.pdf | bzip2 -9 >$@ pdf-$(PAPER)-$(RELEASE).zip: pdf rm -f $@ zip -q -9 $@ *.pdf postscript-$(PAPER)-$(RELEASE).tar.bz2: ps tar cf - *.ps | bzip2 -9 >$@ postscript-$(PAPER)-$(RELEASE).tgz: ps tar cf - *.ps | gzip -9 >$@ postscript-$(PAPER)-$(RELEASE).zip: ps rm -f $@ zip -q -9 $@ *.ps html-$(RELEASE).tgz: html tar cf - modpython | gzip -9 >$@ html-$(RELEASE).tar.bz2: html tar cf - modpython | bzip2 -9 >$@ html-$(RELEASE).zip: html rm -f $@ zip -q -9 $@ modpython # convenience targets: tarhtml: html-$(RELEASE).tgz tarps: postscript-$(PAPER)-$(RELEASE).tgz tarpdf: pdf-$(PAPER)-$(RELEASE).tgz tarballs: tarpdf tarps tarhtml ziphtml: html-$(RELEASE).zip zipps: postscript-$(PAPER)-$(RELEASE).zip zippdf: pdf-$(PAPER)-$(RELEASE).zip zips: zippdf zipps ziphtml bziphtml: html-$(RELEASE).tar.bz2 bzipps: postscript-$(PAPER)-$(RELEASE).tar.bz2 bzippdf: pdf-$(PAPER)-$(RELEASE).tar.bz2 bzips: bzippdf bzipps bziphtml # Housekeeping targets # Remove temporary files; all except the following: # - sources: .tex, .bib, .sty, *.cls # - useful results: .dvi, .pdf, .ps, .texi, .info clean: rm -f *~ *.aux *.idx *.ilg *.ind *.log *.toc *.bkm *.syn *.pla api.tex # Remove temporaries as well as final products clobber: clean rm -rf modpython rm -f html-$(RELEASE).tgz rm -f pdf-$(RELEASE).tgz postscript-$(RELEASE).tgz rm -f html-$(RELEASE).zip rm -f pdf-$(RELEASE).zip postscript-$(RELEASE).zip realclean: clobber distclean: clobber rm -f Makefile # HTML in the doc directory dist: version html rm -rf ../doc-html mv modpython ../doc-html # Version substitution version: ../src/include/mpversion.h DATE="`date +'%B %d, %Y'`"; \ VERSION="`awk '/MPV_STRING/ {print $$3}' ../src/include/mpversion.h`"; \ VERSION="`echo $$VERSION | sed s/\\"//g`"; \ cat modpython.tex | sed "s/\\\release.*/\\\release\{$$VERSION\}/" >modpython.tex2; \ cat modpython.tex2 | sed s/\\date.*/\\date\{"$$DATE"\}/ >modpython.tex mod_python-3.3.1/Doc/README0000644000175000017500000000311510534600663013406 0ustar jimjim This directory contains the mod_python documentation sources. If you're looking for documentation, go to the ../doc-html directory, or http://www.modpython.org/. This directory is mainly for LaTeX geeks. In order for anything here to be functional, you must have configured mod_python with the --with-python option. You also need to have all the necessary tools installed, see "Documenting Python" by Fred L. Drake. If everything is in place, you should be able to generate PDF, HTML, DVI as well as Postscript file by simply typing one of the following commands: make pdf make html make dvi make ps Good Luck! LaTeX Notes ----------- Using the tilde character in LaTex is a bit of a headache as ~ is used for markup. The obvious solution of escaping it as \~ doesn't work, as this is also used for markup and actually adds a diactrical to the immediately following character. If you want a ~ enclosed in double quotes you can use \character{\~}. So \character{\~} becomes "~" in the generated documentation. If you want a ~ without the quotes you can use \textasciitilde. For example ~/foo/bar should be written as \textasciitilde/foo/bar in the LaTeX source. Using \textasciitilde does not work if there is an alpha-numeric character immediately following. For a url you can hex encode the ~ as %7e. For example: http://people.apache.org/~jgallacher should be written as: http://people.apache.org/\%7ejgallacher Note that the ~ character is handled properly within a {verbatim} section, so the following works without modification: \begin{verbatim} path = "~/foo/bar" \end{verbatim} mod_python-3.3.1/Doc/modpython1.tex0000644000175000017500000001241310470163235015351 0ustar jimjim\chapter{Introduction\label{introduction}} \section{Performance\label{intr-performance}} One of the main advantages of mod_python is the increase in performance over traditional CGI. Below are results of a very crude test. The test was done on a 1.2GHz Pentium machine running Red Hat Linux 7.3. \citetitle[http://httpd.apache.org/docs-2.0/programs/ab.html]{Ab} was used to poll 4 kinds of scripts, all of which imported the standard cgi module (because this is how a typical Python cgi script begins), then output a single word \samp{Hello!}. The results are based on 10000 requests with concurrency of 1. \begin{verbatim} Standard CGI: 23 requests/s Mod_python cgihandler: 385 requests/s Mod_python publisher: 476 requests/s Mod_python handler: 1203 requests/s \end{verbatim} \section{Flexibility\label{intr-flexibility}} Apache processes requests in phases (e.g. read the request, parse headers, check access, etc.). These phases can be implemented by functions called handlers. Traditionally, handlers are written in C and compiled into Apache modules. Mod_python provides a way to extend Apache functionality by writing Apache handlers in Python. For a detailed description of the Apache request processing process, see the \citetitle[http://dev.apache.org/API.html]{Apache API Notes}, as well as the \citetitle[http://www.modpython.org/python10/]{Mod_python - Integrating Python with Apache} paper. To ease migration from CGI, a standard mod_python handler is provided that simulates the CGI environment allowing a user to run legacy scripts under mod_python with no changes to the code (in most cases). \begin{seealso} \seeurl{http://dev.apache.org/}{Apache Developer Resources} \seeurl{http://www.modpython.org/python10/}{Mod_Python - Integrating Python with Apache, presented at Python 10} \end{seealso} \section{History\label{intr-history}} Mod_python originates from a project called \citetitle[http://www.modpython.org/httpdapy/]{Httpdapy} (1997). For a long time Httpdapy was not called mod_python because Httpdapy was not meant to be Apache-specific. Httpdapy was designed to be cross-platform and in fact was initially written for the Netscape server (back then it was called Nsapy (1997). Nsapy itself was based on an original concept and first code by Aaron Watters from "Internet Programming with Python" by Aaron Watters, Guido Van Rossum and James C. Ahlstrom, ISBN 1-55851-484-8. Without Aaron's inspiration, there would be no mod_python. Quoting from the Httpdapy README file: \begin{verbatim} Although Nsapy only worked with Netscape servers, it was very generic in its design and was based on some brilliant ideas that weren't necessarily Netscape specific. Its design is a combination of extensibility, simplicity and efficiency that takes advantage of many of the key benefits of Python and is totally in the spirit of Python. \end{verbatim} This excerpt from the Httpdapy README file describes well the challenges and the solution provided by embedding Python within the HTTP server: \begin{verbatim} While developing my first WWW applications a few years back, I found that using CGI for programs that need to connect to relational databases (commercial or not) is too slow because every hit requires loading of the interpreter executable which can be megabytes in size, any database libraries that can themselves be pretty big, plus, the database connection/authentication process carries a very significant overhead because it involves things like DNS resolutions, encryption, memory allocation, etc.. Under pressure to speed up the application, I nearly gave up the idea of using Python for the project and started researching other tools that claimed to specialize in www database integration. I did not have any faith in MS's ASP; was quite frustrated by Netscape LiveWire's slow performance and bugginess; Cold Fusion seemed promising, but I soon learned that writing in html-like tags makes programs as readable as assembly. Same is true for PHP. Besides, I *really* wanted to write things in Python. Around the same time the Internet Programming With Python book came out and the chapter describing how to embed Python within Netscape server immediately caught my attention. I used the example in my project, and developed an improved version of what I later called Nsapy that compiled on both Windows NT and Solaris. Although Nsapy only worked with Netscape servers, it was a very intelligent generic OO design that, in the spirit of Python, that lent itself for easy portability to other web servers. Incidently, the popularity of Netscape's servers was taking a turn south, and so I set out to port Nsapy to other servers starting with the most popular one, Apache. And so from Nsapy was born Httpdapy. \end{verbatim} ...continuing this saga, yours truly later learned that writing Httpdapy for every server is a task a little bigger and less interesting than I originally imagined. Instead, it seemed like providing a Python counterpart to the popular Perl Apache extension mod_perl that would give Python users the same (or better) capability would be a much more exciting thing to do. And so it was done. The first release of mod_python happened in May of 2000. mod_python-3.3.1/Doc/release-instructions.txt0000644000175000017500000000334010326464753017460 0ustar jimjimRelease Instructions ==================== Notes ----- The following instructions are appropriate for version 3.2.0. Adjust accordingly for a different version. The current version/date is in src/include/version.h You will need to have TeTeX installed and the python source code to produce the documentation. Instructions ------------ REPOS=http://svn.apache.org/repos/asf/httpd/mod_python 1. Create the new branch for the release in svn repository. svn copy --username USER --password PASS $REPOS/trunk $REPOS/tags/release-3-2-0 -m "Tagged for release" 2. Checkout a working copy of the new branch. cd /tmp svn co $REPOS/tags/release-3-2-0 mod_python 3. Update the version information. cd /tmp/mod_python/src/include/ Change the following in mpversion.h: MPV_MAJOR MPV_MINOR MVP_PATCH MVP_STRING cd /tmp/mod_python/lib/python/mod_python In __init__.py change version Once you've update the version information, checkin the changes with cd /tmp/mod_python svn ci -m "updated version infomation" 4. Generate the html docs. cd mod_python ./configure --with-apxs=`which apxs` --with-python-src=/path/to/python/src cd Doc make dist 5. Export a working copy to a release copy. cd /tmp svn export mod_python mod_python-3.2.0 6. Copy the html docs generated in step 3 from your working copy to your release copy. cp -r mod_python/doc-html/ mod_python-3.2.0/ 7. Create a tarball for the release. tar czvf mod_python-3.2.0.tgz mod_python-3.2.0 8. Generate the pdf file for the website cd mod_python/Doc make pdf 9. Send Doc/modpython.pdf to the mod_python.org website admin. Hints ----- To sign: gpg -a -b mod_python-3.2.0.win32-py2.3.exe mod_python-3.3.1/Doc/modpython2.tex0000644000175000017500000004110210536550444015354 0ustar jimjim\chapter{Installation\label{installation}} \indexii{installation}{UNIX} \indexii{mod_python}{mailing list} \begin{notice} By far the best place to get help with installation and other issues is the mod_python mailing list. Please take a moment to join the mod_python mailing list by sending an e-mail with the word \samp{subscribe} in the subject to \email{mod_python-request@modpython.org}. Also check out Graham Dumpleton's assorted articles on mod_python at \citetitle[http://www.dscpl.com.au/wiki/ModPython/Articles]{http://www.dscpl.com.au/wiki/ModPython/Articles}. These include alternate instructions for getting a first mod_python handler working, as well as articles covering problems, short comings and constraints in various versions of mod_python. \end{notice} \section{Prerequisites\label{inst-prerequisites}} \begin{itemize} \item Python 2.3.4 or later. Python versions less than 2.3 will not work. \item Apache 2.0.54 or later. Apache versions 2.0.47 to 2.0.53 may work but have not been tested with this release. (For Apache 1.3.x, use mod_python version 2.7.x). \end{itemize} In order to compile mod_python you will need to have the include files for both Apache and Python, as well as the Python library installed on your system. If you installed Python and Apache from source, then you already have everything needed. However, if you are using prepackaged software (e.g. Red Hat Linux RPM, Debian, or Solaris packages from sunsite, etc) then chances are, you have just the binaries and not the sources on your system. Often, the Apache and Python include files and libraries necessary to compile mod_python are part of separate ``development'' package. If you are not sure whether you have all the necessary files, either compile and install Python and Apache from source, or refer to the documentation for your system on how to get the development packages. \section{Compiling\label{inst-compiling}} \indexii{compiling}{mod_python} There are two ways in which modules can be compiled and linked to Apache - statically, or as a DSO (Dynamic Shared Object). \dfn{DSO} is a more popular approach nowadays and is the recommended one for mod_python. The module gets compiled as a shared library which is dynamically loaded by the server at run time. The advantage of DSO is that a module can be installed without recompiling Apache and used as needed. A more detailed description of the Apache DSO mechanism is available at \url{http://httpd.apache.org/docs-2.0/dso.html}. \emph{At this time only DSO is supported by mod_python.} \dfn{Static} linking is an older approach. With dynamic linking available on most platforms it is used less and less. The main drawback is that it entails recompiling Apache, which in many instances is not a favorable option. \subsection{Running ./configure\label{inst-configure}} \index{./configure} The \program{./configure} script will analyze your environment and create custom Makefiles particular to your system. Aside from all the standard autoconf stuff, \program{./configure} does the following: \begin{itemize} \item \index{apxs} \index{./configure!\longprogramopt{with-apxs}} %\indexii{./configure}{\longprogramopt{with-apxs}} Finds out whether a program called \program{apxs} is available. This program is part of the standard Apache distribution, and is necessary for DSO compilation. If apxs cannot be found in your \envvar{PATH} or in \filenq{/usr/local/apache/bin}, DSO compilation will not be available. You can manually specify the location of apxs by using the \longprogramopt{with-apxs} option, e.g.: \begin{verbatim} $ ./configure --with-apxs=/usr/local/apache/bin/apxs \end{verbatim} %$ keep emacs happy It is recommended that you specify this option. \item \index{libpython.a} Checks your Python version and attempts to figure out where \program{libpython} is by looking at various parameters compiled into your Python binary. By default, it will use the \program{python} program found in your \envvar{PATH}. \index{./configure!\longprogramopt{with-python}} %\indexii{./configure}{\longprogramopt{with-python}} If the first Python binary in the path is not suitable or not the one desired for mod_python, you can specify an alternative location with the \longprogramopt{with-python} option, e.g: \begin{verbatim} $ ./configure --with-python=/usr/local/bin/python2.3 \end{verbatim} %$ keep emacs happy \item \index{./configure!\longprogramopt{with-mutex-dir}} %\indexii{./configure}{\longprogramopt{with-mutex-dir}} Sets the directory for the apache mutex locks. The default is \filenq{/tmp}. The directory must exist and be writable by the owner of the apache process. Use \longprogramopt{with-mutex-dir} option, e.g: \begin{verbatim} $ ./configure --with-mutex-dir=/var/run/mod_python \end{verbatim} The mutex directory can also be specified in using a \citetitle[dir-other-po.html]{PythonOption} directive. See \citetitle[inst-apacheconfig.html]{Configuring Apache}. New in version 3.3.0 \item \index{./configure!\longprogramopt{with-max-locks}} Sets the maximum number of locks reserved by mod_python. The mutexes used for locking are a limited resource on some systems. Increasing the maximum number of locks may increase performance when using session locking. The default is 8. A reasonable number for higher performance would be 32. Use \longprogramopt{with-max-locks} option, e.g: \begin{verbatim} $ ./configure --with-max-locks=32 \end{verbatim} The number of locks can also be specified in using a \citetitle[dir-other-po.html]{PythonOption} directive. See \citetitle[inst-apacheconfig.html]{Configuring Apache}. New in version 3.2.0 \item \index{flex} Attempts to locate \program{flex} and determine its version. If \program{flex} cannot be found in your \envvar{PATH} \program{configure} will fail. If the wrong version is found \program{configure} will generate a warning. You can generally ignore this warning unless you need to re-create \filenq{src/psp_parser.c}. The parser used by psp (See \ref{pyapi-psp}) is written in C generated using \program{flex}. This requires a reentrant version of \program{flex} which at this time is 2.5.31. Most platforms however ship with version 2.5.4 which is not suitable, so a pre-generated copy of psp_parser.c is included with the source. If you do need to compile \filenq{src/psp_parser.c} you must get the correct \program{flex} version. \index{./configure!\longprogramopt{with-flex}} %\indexii{./configure}{\longprogramopt{with-flex}} If the first flex binary in the path is not suitable or not the one desired you can specify an alternative location with the \longprogramopt{with-flex} option, e.g: \begin{verbatim} $ ./configure --with-flex=/usr/local/bin/flex \end{verbatim} %$ keep emacs happy New in version 3.2.0 \item \index{python-src} The python source is required to build the mod_python documentation. \index{./configure!\longprogramopt{with-python-src}} %\indexii{./configure}{\longprogramopt{with-python-src}} You can safely ignore this option unless you want to build the the documentation. If you want to build the documentation, specify the path to your python source with the \longprogramopt{with-python-src} option, eg. \begin{verbatim} $ ./configure --with-python-src=/usr/src/python2.3 \end{verbatim} %$ keep emacs happy New in version 3.2.0 \end{itemize} \subsection{Running make\label{inst-make}} \begin{itemize} \item %If possible, the \program{./configure} script will default to DSO %compilation, otherwise, it will default to static. To stay with %whatever \program{./configure} decided, simply run To start the build process, simply run \begin{verbatim} $ make \end{verbatim} %$ emacs happy \end{itemize} \section{Installing\label{inst-installing}} \subsection{Running make install\label{inst-makeinstall}} \begin{itemize} \item This part of the installation needs to be done as root. \begin{verbatim} $ su # make install \end{verbatim} %$ emacs happy \begin{itemize} \item %For DSO, this will simply copy the library into your Apache \filenq{libexec} This will simply copy the library into your Apache \filenq{libexec} directory, where all the other modules are. %\item %For static, it will copy some files into your Apache source tree. \item Lastly, it will install the Python libraries in \filenq{site-packages} and compile them. \end{itemize} \indexii{make targets}{install_py_lib} %\indexii{make targets}{install_static} \indexii{make targets}{install_dso} \strong{NB:} If you wish to selectively install just the Python libraries %the static library or the DSO (which may not always require superuser or the DSO (which may not always require superuser privileges), you can use the following \program{make} targets: \programopt{install_py_lib} and \programopt{install_dso} %\programopt{install_static} and \programopt{install_dso} \end{itemize} \subsection{Configuring Apache\label{inst-apacheconfig}} \begin{description} \item \strong{LoadModule} \indexii{LoadModule}{apache configuration} If you compiled mod_python as a DSO, you will need to tell Apache to load the module by adding the following line in the Apache configuration file, usually called \filenq{httpd.conf} or \filenq{apache.conf}: \begin{verbatim} LoadModule python_module libexec/mod_python.so \end{verbatim} \index{mod_python.so} The actual path to \program{mod_python.so} may vary, but make install should report at the very end exactly where \program{mod_python.so} was placed and how the \code{LoadModule} directive should appear. \item \strong{Mutex Directory} \indexii{mutex directory}{apache configuration} The default directory for mutex lock files is \filenq{/tmp}. The default value can be be specified at compile time using \citetitle[inst-configure.html]{./configure ----with-mutex-dir}. Alternatively this value can be overriden at apache startup using a \citetitle[dir-other-po.html]{PythonOption}. \begin{verbatim} PythonOption mod_python.mutex_directory "/tmp" \end{verbatim} This may only be used in the server configuration context. It will be ignored if used in a directory, virtual host, htaccess or location context. The most logical place for this directive in your apache configuration file is immediately following the \strong{LoadModule} directive. \emph{New in version 3.3.0} \item \strong{Mutex Locks} \indexii{apache configuration}{mutex locks} Mutexes are used in mod_python for session locking. The default value is 8. On some systems the locking mechanism chosen uses valuable system resources. Notably on RH 8 sysv ipc is used, which by default provides only 128 semaphores system-wide. On many other systems flock is used which may result in a relatively large number of open files. The optimal number of necessary locks is not clear. Increasing the maximum number of locks may increase performance when using session locking. A reasonable number for higher performance might be 32. The maximum number of locks can be specified at compile time using \citetitle[inst-configure.html]{./configure ----with-max-locks}. Alternatively this value can be overriden at apache startup using a \citetitle[dir-other-po.html]{PythonOption}. \begin{verbatim} PythonOption mod_python.mutex_locks 8 \end{verbatim} This may only be used in the server configuration context. It will be ignored if used in a directory, virtual host, htaccess or location context. The most logical place for this directive in your apache configuration file is immediately following the \strong{LoadModule} directive. \emph{New in version 3.3.0} \end{description} \section{Testing\label{inst-testing}} \strong{Warning :} These instructions are meant to be followed if you are using mod_python 3.x or later. If you are using mod_python 2.7.x (namely, if you are using Apache 1.3.x), please refer to the proper documentation. \begin{enumerate} \item Make some directory that would be visible on your web site, for example, htdocs/test. \item Add the following Apache directives, which can appear in either the main server configuration file, or \filenq{.htaccess}. If you are going to be using the \filenq{.htaccess} file, you will not need the \code{} tag below (the directory then becomes the one in which the \filenq{.htaccess} file is located), and you will need to make sure the \code{AllowOverride} directive applicable to this directory has at least \code{FileInfo} specified. (The default is \code{None}, which will not work.) % the above has been verified to be still true for Apache 2.0 \begin{verbatim} AddHandler mod_python .py PythonHandler mptest PythonDebug On \end{verbatim} (Substitute \filenq{/some/directory} above for something applicable to your system, usually your Apache ServerRoot) \item This redirects all requests for URLs ending in \filenq{.py} to the mod_python handler. mod_python receives those requests and looks for an appropriate PythonHandler to handle them. Here, there is a single PythonHandler directive defining mptest as the python handler to use. We'll see next how this python handler is defined. \item At this time, if you made changes to the main configuration file, you will need to restart Apache in order for the changes to take effect. \item Edit \filenq{mptest.py} file in the \filenq{htdocs/test} directory so that is has the following lines (be careful when cutting and pasting from your browser, you may end up with incorrect indentation and a syntax error): \begin{verbatim} from mod_python import apache def handler(req): req.content_type = 'text/plain' req.write("Hello World!") return apache.OK \end{verbatim} \item Point your browser to the URL referring to the \filenq{mptest.py}; you should see \samp{Hello World!}. If you didn't - refer to the troubleshooting section next. \item Note that according to the configuration written above, you can also point your browser to any URL ending in .py in the test directory. You can for example point your browser to \filenq{/test/foobar.py} and it will be handled by \filenq{mptest.py}. That's because you explicitely set the handler to always be \filenq{mptest}, whatever the requested file was. If you want to have many handler files named \filenq{handler1.py}, \filenq{handler2.py} and so on, and have them accessible on \filenq{/test/handler1.py}, \filenq{/test/handler2.py}, etc., then you have to use a higher level handler system such as the mod_python publisher (see \ref{tut-pub}), mpservlets or Vampire. Those are just special mod_python handler that know how to map requests to a dynamically loaded handler. \item If everything worked well, move on to Chapter \ref{tutorial}, \citetitle[tutorial.html]{Tutorial}. \end{enumerate} \begin{seealso} \seeurl{http://www.astro.umass.edu/\%7edpopowich/python/mpservlets/}{mpservlets} \seeurl{http://www.dscpl.com.au/projects/vampire}{Vampire} \end{seealso} \section{Troubleshooting\label{inst-trouble}} There are a few things you can try to identify the problem: \begin{itemize} \item Carefully study the error output, if any. \item Check the server error log file, it may contain useful clues. \item Try running Apache from the command line in single process mode: \begin{verbatim} ./httpd -X \end{verbatim} This prevents it from backgrounding itself and may provide some useful information. \item Beginning with mod_python 3.2.0, you can use the mod_python.testhandler to diagnose your configuration. Add this to your \filenq{httpd.conf} file : \begin{verbatim} SetHandler mod_python PythonHandler mod_python.testhandler \end{verbatim} Now point your browser to the \filenq{/mpinfo} URL (e.g. \filenq{http://localhost/mpinfo}) and note down the information given. This will help you reporting your problem to the mod_python list. \item Ask on the mod_python list. Make sure to provide specifics such as: \begin{itemize} \item Mod_python version. \item Your operating system type, name and version. \item Your Python version, and any unusual compilation options. \item Your Apache version. \item Relevant parts of the Apache config, .htaccess. \item Relevant parts of the Python code. \end{itemize} \end{itemize} mod_python-3.3.1/Doc/modpython3.tex0000644000175000017500000004161110520321730015345 0ustar jimjim\chapter{Tutorial\label{tutorial}} \begin{flushright} \emph{So how can I make this work?} \end{flushright} \emph{This is a quick guide to getting started with mod_python programming once you have it installed. This is \textbf{not} an installation manual!} \emph{It is also highly recommended to read (at least the top part of) Section \ref{pythonapi}, \citetitle[pythonapi.html]{Python API} after completing this tutorial.} \section{A Quick Start with the Publisher Handler\label{tut-pub}} This section provides a quick overview of the Publisher handler for those who would like to get started without getting into too much detail. A more thorough explanation of how mod_python handlers work and what a handler actually is follows on in the later sections of the tutorial. The \code{publisher} handler is provided as one of the standard mod_python handlers. To get the publisher handler working, you will need the following lines in your config: \begin{verbatim} AddHandler mod_python .py PythonHandler mod_python.publisher PythonDebug On \end{verbatim} The following example will demonstrate a simple feedback form. The form will ask for the name, e-mail address and a comment and construct an e-mail to the webmaster using the information submitted by the user. This simple application consists of two files: \filenq{form.html} - the form to collect the data, and \filenq{form.py} - the target of the form's action. Here is the html for the form: \begin{verbatim} Please provide feedback below:

Name:
Email:
Comment:
\end{verbatim} Note the \code{action} element of the \code{
} tag points to \code{form.py/email}. We are going to create a file called \filenq{form.py}, like this: \begin{verbatim} import smtplib WEBMASTER = "webmaster" # webmaster e-mail SMTP_SERVER = "localhost" # your SMTP server def email(req, name, email, comment): # make sure the user provided all the parameters if not (name and email and comment): return "A required parameter is missing, \ please go back and correct the error" # create the message text msg = """\ From: %s Subject: feedback To: %s I have the following comment: %s Thank You, %s """ % (email, WEBMASTER, comment, name) # send it out conn = smtplib.SMTP(SMTP_SERVER) conn.sendmail(email, [WEBMASTER], msg) conn.quit() # provide feedback to the user s = """\ Dear %s,
Thank You for your kind comments, we will get back to you shortly. """ % name return s \end{verbatim} When the user clicks the Submit button, the publisher handler will load the \function{email} function in the \module{form} module, passing it the form fields as keyword arguments. It will also pass the request object as \code{req}. Note that you do not have to have \code{req} as one of the arguments if you do not need it. The publisher handler is smart enough to pass your function only those arguments that it will accept. The data is sent back to the browser via the return value of the function. Even though the Publisher handler simplifies mod_python programming a great deal, all the power of mod_python is still available to this program, since it has access to the request object. You can do all the same things you can do with a ``native'' mod_python handler, e.g. set custom headers via \code{req.headers_out}, return errors by raising \exception{apache.SERVER_ERROR} exceptions, write or read directly to and from the client via \method{req.write()} and \method{req.read()}, etc. Read Section \ref{hand-pub} \citetitle[hand-pub.html]{Publisher Handler} for more information on the publisher handler. \section{Quick Overview of how Apache Handles Requests\label{tut-overview}} If you would like delve in deeper into the functionality of mod_python, you need to understand what a handler is. Apache processes requests in \dfn{phases}. For example, the first phase may be to authenticate the user, the next phase to verify whether that user is allowed to see a particular file, then (next phase) read the file and send it to the client. A typical static file request involves three phases: (1) translate the requested URI to a file location (2) read the file and send it to the client, then (3) log the request. Exactly which phases are processed and how varies greatly and depends on the configuration. A \dfn{handler} is a function that processes one phase. There may be more than one handler available to process a particular phase, in which case they are called by Apache in sequence. For each of the phases, there is a default Apache handler (most of which by default perform only very basic functions or do nothing), and then there are additional handlers provided by Apache modules, such as mod_python. Mod_python provides every possible handler to Apache. Mod_python handlers by default do not perform any function, unless specifically told so by a configuration directive. These directives begin with \samp{Python} and end with \samp{Handler} (e.g. \code{PythonAuthenHandler}) and associate a phase with a Python function. So the main function of mod_python is to act as a dispatcher between Apache handlers and Python functions written by a developer like you. The most commonly used handler is \code{PythonHandler}. It handles the phase of the request during which the actual content is provided. Because it has no name, it is sometimes referred to as as \dfn{generic} handler. The default Apache action for this handler is to read the file and send it to the client. Most applications you will write will override this one handler. To see all the possible handlers, refer to Section \ref{directives}, \citetitle[directives.html]{Apache Directives}. \section{So what Exactly does Mod-python do?\label{tut-what-it-do}} Let's pretend we have the following configuration: \begin{verbatim} AddHandler mod_python .py PythonHandler myscript PythonDebug On \end{verbatim} \strong{NB:} \filenq{/mywebdir} is an absolute physical path. And let's say that we have a python program (Windows users: substitute forward slashes for backslashes) \file{/mywedir/myscript.py} that looks like this: \begin{verbatim} from mod_python import apache def handler(req): req.content_type = "text/plain" req.write("Hello World!") return apache.OK \end{verbatim} Here is what's going to happen: The \code{AddHandler} directive tells Apache that any request for any file ending with \file{.py} in the \file{/mywebdir} directory or a subdirectory thereof needs to be processed by mod_python. The \samp{PythonHandler myscript} directive tells mod_python to process the generic handler using the \code{myscript} script. The \samp{PythonDebug On} directive instructs mod_python in case of an Python error to send error output to the client (in addition to the logs), very useful during development. When a request comes in, Apache starts stepping through its request processing phases calling handlers in mod_python. The mod_python handlers check whether a directive for that handler was specified in the configuration. (Remember, it acts as a dispatcher.) In our example, no action will be taken by mod_python for all handlers except for the generic handler. When we get to the generic handler, mod_python will notice \samp{PythonHandler myscript} directive and do the following: \begin{enumerate} \item If not already done, prepend the directory in which the \code{PythonHandler} directive was found to \code{sys.path}. \item Attempt to import a module by name \code{myscript}. (Note that if \code{myscript} was in a subdirectory of the directory where \code{PythonHandler} was specified, then the import would not work because said subdirectory would not be in the \code{sys.path}. One way around this is to use package notation, e.g. \samp{PythonHandler subdir.myscript}.) \item Look for a function called \code{handler} in \code{myscript}. \item Call the function, passing it a request object. (More on what a request object is later) \item At this point we're inside the script: \begin{itemize} \item \begin{verbatim} from mod_python import apache \end{verbatim} This imports the apache module which provides us the interface to Apache. With a few rare exceptions, every mod_python program will have this line. \item \begin{verbatim} def handler(req): \end{verbatim} \index{handler} This is our \dfn{handler} function declaration. It is called \samp{handler} because mod_python takes the name of the directive, converts it to lower case and removes the word \samp{python}. Thus \samp{PythonHandler} becomes \samp{handler}. You could name it something else, and specify it explicitly in the directive using \samp{::}. For example, if the handler function was called \samp{spam}, then the directive would be \samp{PythonHandler myscript::spam}. Note that a handler must take one argument - the request object. The request object is an object that provides all of the information about this particular request - such as the IP of client, the headers, the URI, etc. The communication back to the client is also done via the request object, i.e. there is no ``response'' object. \item \begin{verbatim} req.content_type = "text/plain" \end{verbatim} This sets the content type to \samp{text/plain}. The default is usually \samp{text/html}, but since our handler doesn't produce any html, \samp{text/plain} is more appropriate. \strong{Important:} you should \strong{always} make sure this is set \strong{before} any call to \samp{req.write}. When you first call \samp{req.write}, the response HTTP header is sent to the client and all subsequent changes to the content type (or other HTTP headers) are simply lost. \item \begin{verbatim} req.write("Hello World!") \end{verbatim} This writes the \samp{Hello World!} string to the client. (Did I really have to explain this one?) \item \begin{verbatim} return apache.OK \end{verbatim} This tells Apache that everything went OK and that the request has been processed. If things did not go OK, that line could be return \constant{apache.HTTP_INTERNAL_SERVER_ERROR} or return \constant{apache.HTTP_FORBIDDEN}. When things do not go OK, Apache will log the error and generate an error message for the client. \end{itemize} \end{enumerate} \strong{Some food for thought:} If you were paying attention, you noticed that the text above didn't specify that in order for the handler code to be executed, the URL needs to refer to \filenq{myscript.py}. The only requirement was that it refers to a \filenq{.py} file. In fact the name of the file doesn't matter, and the file referred to in the URL doesn't have to exist. So, given the above configuration, \samp{http://myserver/mywebdir/myscript.py} and \samp{http://myserver/mywebdir/montypython.py} would give the exact same result. The important thing to understand here is that a handler augments the server behaviour when processing a specific type of file, not an individual file. \emph{At this point, if you didn't understand the above paragraph, go back and read it again, until you do.} \section{Now something More Complicated - Authentication\label{tut-more-complicated}} Now that you know how to write a primitive handler, let's try something more complicated. Let's say we want to password-protect this directory. We want the login to be \samp{spam}, and the password to be \samp{eggs}. First, we need to tell Apache to call our \emph{authentication} handler when authentication is needed. We do this by adding the \code{PythonAuthenHandler}. So now our config looks like this: \begin{verbatim} AddHandler mod_python .py PythonHandler myscript PythonAuthenHandler myscript PythonDebug On \end{verbatim} Notice that the same script is specified for two different handlers. This is fine, because if you remember, mod_python will look for different functions within that script for the different handlers. Next, we need to tell Apache that we are using Basic HTTP authentication, and only valid users are allowed (this is fairly basic Apache stuff, so we're not going to go into details here). Our config looks like this now: \begin{verbatim} AddHandler mod_python .py PythonHandler myscript PythonAuthenHandler myscript PythonDebug On AuthType Basic AuthName "Restricted Area" require valid-user \end{verbatim} Note that depending on which version of Apache is being used, you may need to set either the \code{AuthAuthoritative} or \code{AuthBasicAuthoritative} directive to \code{Off} to tell Apache that you want allow the task of performing basic authentication to fall through to your handler. Now we need to write an authentication handler function in \file{myscript.py}. A basic authentication handler would look like this: \begin{verbatim} from mod_python import apache def authenhandler(req): pw = req.get_basic_auth_pw() user = req.user if user == "spam" and pw == "eggs": return apache.OK else: return apache.HTTP_UNAUTHORIZED \end{verbatim} Let's look at this line by line: \begin{itemize} \item \begin{verbatim} def authenhandler(req): \end{verbatim} This is the handler function declaration. This one is called \code{authenhandler} because, as we already described above, mod_python takes the name of the directive (\code{PythonAuthenHandler}), drops the word \samp{Python} and converts it lower case. \item \begin{verbatim} pw = req.get_basic_auth_pw() \end{verbatim} This is how we obtain the password. The basic HTTP authentication transmits the password in base64 encoded form to make it a little bit less obvious. This function decodes the password and returns it as a string. Note that we have to call this function before obtaining the user name. \item \begin{verbatim} user = req.user \end{verbatim} This is how you obtain the username that the user entered. \item \begin{verbatim} if user == "spam" and pw == "eggs": return apache.OK \end{verbatim} We compare the values provided by the user, and if they are what we were expecting, we tell Apache to go ahead and proceed by returning \constant{apache.OK}. Apache will then consider this phase of the request complete, and proceed to the next phase. (Which in this case would be \function{handler()} if it's a \code{.py} file). \item \begin{verbatim} else: return apache.HTTP_UNAUTHORIZED \end{verbatim} Else, we tell Apache to return \constant{HTTP_UNAUTHORIZED} to the client, which usually causes the browser to pop a dialog box asking for username and password. \end{itemize} \section{Your Own 404 Handler\label{tut-404-handler}} In some cases, you may wish to return a 404 (\constant{HTTP_NOT_FOUND}) or other non-200 result from your handler. There is a trick here. if you return \constant{HTTP_NOT_FOUND} from your handler, Apache will handle rendering an error page. This can be problematic if you wish your handler to render it's own error page. In this case, you need to set \code{req.status = apache.HTTP_NOT_FOUND}, render your page, and then \code{return(apache.OK)}: \begin{verbatim} from mod_python import apache def handler(req): if req.filename[-17:] == 'apache-error.html': # make Apache report an error and render the error page return(apache.HTTP_NOT_FOUND) if req.filename[-18:] == 'handler-error.html': # use our own error page req.status = apache.HTTP_NOT_FOUND pagebuffer = 'Page not here. Page left, not know where gone.' else: # use the contents of a file pagebuffer = open(req.filename, 'r').read() # fall through from the latter two above req.write(pagebuffer) return(apache.OK) \end{verbatim} Note that if wishing to returning an error page from a handler phase other than the response handler, the value \code{apache.DONE} must be returned instead of \code{apache.OK}. If this is not done, subsequent handler phases will still be run. The value of \code{apache.DONE} indicates that processing of the request should be stopped immediately. If using stacked response handlers, then \code{apache.DONE} should also be returned in that situation to prevent subsequent handlers registered for that phase being run if appropriate. mod_python-3.3.1/Doc/modpython4.tex0000644000175000017500000040121410545500237015355 0ustar jimjim \chapter{Python API\label{pythonapi}} \section{Multiple Interpreters\label{pyapi-interps}} When working with mod_python, it is important to be aware of a feature of Python that is normally not used when using the language for writing scripts to be run from command line. This feature is not available from within Python itself and can only be accessed through the \citetitle[http://www.python.org/doc/current/api/api.html]{C language API}. Python C API provides the ability to create \dfn{subinterpreters}. A more detailed description of a subinterpreter is given in the documentation for the \citetitle[http://www.python.org/doc/current/api/initialization.html]{\cfunction{Py_NewInterpreter()}} function. For this discussion, it will suffice to say that each subinterpreter has its own separate namespace, not accessible from other subinterpreters. Subinterpreters are very useful to make sure that separate programs running under the same Apache server do not interfere with one another. At server start-up or mod_python initialization time, mod_python initializes an interpreter called \dfn{main} interpreter. The main interpreter contains a dictionary of subinterpreters. Initially, this dictionary is empty. With every request, as needed, subinterpreters are created, and references to them are stored in this dictionary. The dictionary is keyed on a string, also known as \emph{interpreter name}. This name can be any string. The main interpreter is named \samp{main_interpreter}. The way all other interpreters are named can be controlled by \code{PythonInterp*} directives. Default behaviour is to name interpreters using the Apache virtual server name (\code{ServerName} directive). This means that all scripts in the same virtual server execute in the same subinterpreter, but scripts in different virtual servers execute in different subinterpreters with completely separate namespaces. \citetitle[dir-other-ipd.html]{\code{PythonInterpPerDirectory}} and \citetitle[dir-other-ipdv.html]{\code{PythonInterpPerDirective}} directives alter the naming convention to use the absolute path of the directory being accessed, or the directory in which the \code{Python*Handler} was encountered, respectively. \citetitle[dir-other-pi.html]{\code{PythonInterpreter}} can be used to force the interpreter name to a specific string overriding any naming conventions. Once created, a subinterpreter will be reused for subsequent requests. It is never destroyed and exists until the Apache process dies. You can find out the name of the interpreter under which you're running by peeking at \member{req.interpreter}. Note that if any third party module is being used which has a C code component that uses the simplified API for access to the Global Interpreter Lock (GIL) for Python extension modules, then the interpreter name must be forcibly set to be \samp{main_interpreter}. This is necessary as such a module will only work correctly if run within the context of the first Python interpreter created by the process. If not forced to run under the \samp{main_interpreter}, a range of Python errors can arise, each typically referring to code being run in \emph{restricted mode}. \begin{seealso} \seetitle[http://www.python.org/doc/current/api/api.html] {Python C Language API}{Python C Language API} \seetitle[http://www.python.org/peps/pep-0311.html] {PEP 0311 - Simplified Global Interpreter Lock Acquisition for Extensions}{PEP 0311 - Simplified Global Interpreter Lock Acquisition for Extensions} \end{seealso} \section{Overview of a Request Handler\label{pyapi-handler}} \indexii{request}{handler} A \dfn{handler} is a function that processes a particular phase of a request. Apache processes requests in phases - read the request, process headers, provide content, etc. For every phase, it will call handlers, provided by either the Apache core or one of its modules, such as mod_python which passes control to functions provided by the user and written in Python. A handler written in Python is not any different from a handler written in C, and follows these rules: \index{req} \indexii{request}{object} A handler function will always be passed a reference to a request object. (Throughout this manual, the request object is often referred to by the \code{req} variable.) Every handler can return: \begin{itemize} \item \constant{apache.OK}, meaning this phase of the request was handled by this handler and no errors occurred. \item \constant{apache.DECLINED}, meaning this handler has not handled this phase of the request to completion and Apache needs to look for another handler in subsequent modules. \item \constant{apache.\emph{HTTP_ERROR}}, meaning an HTTP error occurred. \var{HTTP_ERROR} can be any of the following: \begin{verbatim} HTTP_CONTINUE = 100 HTTP_SWITCHING_PROTOCOLS = 101 HTTP_PROCESSING = 102 HTTP_OK = 200 HTTP_CREATED = 201 HTTP_ACCEPTED = 202 HTTP_NON_AUTHORITATIVE = 203 HTTP_NO_CONTENT = 204 HTTP_RESET_CONTENT = 205 HTTP_PARTIAL_CONTENT = 206 HTTP_MULTI_STATUS = 207 HTTP_MULTIPLE_CHOICES = 300 HTTP_MOVED_PERMANENTLY = 301 HTTP_MOVED_TEMPORARILY = 302 HTTP_SEE_OTHER = 303 HTTP_NOT_MODIFIED = 304 HTTP_USE_PROXY = 305 HTTP_TEMPORARY_REDIRECT = 307 HTTP_BAD_REQUEST = 400 HTTP_UNAUTHORIZED = 401 HTTP_PAYMENT_REQUIRED = 402 HTTP_FORBIDDEN = 403 HTTP_NOT_FOUND = 404 HTTP_METHOD_NOT_ALLOWED = 405 HTTP_NOT_ACCEPTABLE = 406 HTTP_PROXY_AUTHENTICATION_REQUIRED= 407 HTTP_REQUEST_TIME_OUT = 408 HTTP_CONFLICT = 409 HTTP_GONE = 410 HTTP_LENGTH_REQUIRED = 411 HTTP_PRECONDITION_FAILED = 412 HTTP_REQUEST_ENTITY_TOO_LARGE = 413 HTTP_REQUEST_URI_TOO_LARGE = 414 HTTP_UNSUPPORTED_MEDIA_TYPE = 415 HTTP_RANGE_NOT_SATISFIABLE = 416 HTTP_EXPECTATION_FAILED = 417 HTTP_UNPROCESSABLE_ENTITY = 422 HTTP_LOCKED = 423 HTTP_FAILED_DEPENDENCY = 424 HTTP_INTERNAL_SERVER_ERROR = 500 HTTP_NOT_IMPLEMENTED = 501 HTTP_BAD_GATEWAY = 502 HTTP_SERVICE_UNAVAILABLE = 503 HTTP_GATEWAY_TIME_OUT = 504 HTTP_VERSION_NOT_SUPPORTED = 505 HTTP_VARIANT_ALSO_VARIES = 506 HTTP_INSUFFICIENT_STORAGE = 507 HTTP_NOT_EXTENDED = 510 \end{verbatim} \end{itemize} As an alternative to \emph{returning} an HTTP error code, handlers can signal an error by \emph{raising} the \constant{apache.SERVER_RETURN} exception, and providing an HTTP error code as the exception value, e.g. \begin{verbatim} raise apache.SERVER_RETURN, apache.HTTP_FORBIDDEN \end{verbatim} Handlers can send content to the client using the \method{req.write()} method. Client data, such as POST requests, can be read by using the \method{req.read()} function. \begin{notice} The directory of the Apache \code{Python*Handler} directive in effect is prepended to the \code{sys.path}. If the directive was specified in a server config file outside any \code{}, then the directory is unknown and not prepended. \end{notice} An example of a minimalistic handler might be: \begin{verbatim} from mod_python import apache def requesthandler(req): req.content_type = "text/plain" req.write("Hello World!") return apache.OK \end{verbatim} \section{Overview of a Filter Handler\label{pyapi-filter}} \indexii{filter}{handler} A \dfn{filter handler} is a function that can alter the input or the output of the server. There are two kinds of filters - \dfn{input} and \dfn{output} that apply to input from the client and output to the client respectively. At this time mod_python supports only request-level filters, meaning that only the body of HTTP request or response can be filtered. Apache provides support for connection-level filters, which will be supported in the future. A filter handler receives a \emph{filter} object as its argument. The request object is available as well via \code{filter.req}, but all writing and reading should be done via the filter's object read and write methods. Filters need to be closed when a read operation returns None (indicating End-Of-Stream). The return value of a filter is ignored. Filters cannot decline processing like handlers, but the same effect can be achieved by using the \method{filter.pass_on()} method. Filters must first be registered using \code{PythonInputFilter} or \code{PythonOutputFilter}, then added using the Apache \code{Add/SetInputFilter} or \code{Add/SetOutputFilter} directives. Here is an example of how to specify an output filter, it tells the server that all .py files should processed by CAPITALIZE filter: \begin{verbatim} PythonOutputFilter capitalize CAPITALIZE AddOutputFilter CAPITALIZE .py \end{verbatim} And here is what the code for the \file{capitalize.py} might look like: \begin{verbatim} from mod_python import apache def outputfilter(filter): s = filter.read() while s: filter.write(s.upper()) s = filter.read() if s is None: filter.close() \end{verbatim} When writing filters, keep in mind that a filter will be called any time anything upstream requests an IO operation, and the filter has no control over the amount of data passed through it and no notion of where in the request processing it is called. For example, within a single request, a filter may be called once or five times, and there is no way for the filter to know beforehand that the request is over and which of calls is last or first for this request, thought encounter of an EOS (None returned from a read operation) is a fairly strong indication of an end of a request. Also note that filters may end up being called recursively in subrequests. To avoid the data being altered more than once, always make sure you are not in a subrequest by examining the \code{req.main} value. For more information on filters, see \citetitle[http://httpd.apache.org/docs-2.0/developer/filters.html]{http://httpd.apache.org/docs-2.0/developer/filters.html}. \section{Overview of a Connection Handler\label{pyapi-conn}} \indexii{connection}{handler} A \dfn{connection handler} handles the connection, starting almost immediately from the point the TCP connection to the server was made. Unlike HTTP handlers, connection handlers receive a \emph{connection} object as an argument. Connection handlers can be used to implement protocols. Here is an example of a simple echo server: Apache configuration: \begin{verbatim} PythonConnectionHandler echo \end{verbatim} Contents of \filenq{echo.py} file: \begin{verbatim} from mod_python import apache def connectionhandler(conn): while 1: conn.write(conn.readline()) return apache.OK \end{verbatim} \section{\module{apache} -- Access to Apache Internals.} \declaremodule[apache]{extension}{apache} \modulesynopsis{Access to Apache Internals} \moduleauthor{Gregory Trubetskoy}{grisha@apache.org} The Python interface to Apache internals is contained in a module appropriately named \module{apache}, located inside the \module{mod_python} package. This module provides some important objects that map to Apache internal structures, as well as some useful functions, all documented below. (The request object also provides an interface to Apache internals, it is covered in its own section of this manual.) \indexii{_apache}{module} The \module{apache} module can only be imported by a script running under mod_python. This is because it depends on a built-in module \module{_apache} provided by mod_python. It is best imported like this: \begin{verbatim} from mod_python import apache \end{verbatim} \module{mod_python.apache} module defines the following functions and objects. For a more in-depth look at Apache internals, see the \citetitle[http://httpd.apache.org/dev/]{Apache Developer page} \subsection{Functions\label{pyapi-apmeth}} \begin{funcdesc}{log_error}{message\optional{, level, server}} An interface to the Apache \code{ap_log_error()} function. \var{message} is a string with the error message, \var{level} is one of the following flags constants: \begin{verbatim} APLOG_EMERG APLOG_ALERT APLOG_CRIT APLOG_ERR APLOG_WARNING APLOG_NOTICE APLOG_INFO APLOG_DEBUG APLOG_NOERRNO \end{verbatim} \var{server} is a reference to a \member{req.server} object. If \var{server} is not specified, then the error will be logged to the default error log, otherwise it will be written to the error log for the appropriate virtual server. When \var{server} is not specified, the setting of LogLevel does not apply, the LogLevel is dictated by an httpd compile-time default, usually \code{warn}. If you have a reference to a request object available, consider using \method{req.log_error} instead, it will prepend request-specific information such as the source IP of the request to the log entry. \end{funcdesc} \begin{funcdesc}{import_module}{module_name\optional{, autoreload=None, log=None, path=None}} This function can be used to import modules. \begin{notice} This function and the module importer were completely reimplemented in mod_python 3.3. If you are using an older version of mod_python do not rely on this documentation and instead refer to the documentation for the specific version you are using as the new importer does not behave exactly the same and has additional features. If you are trying to port code from an older version of mod_python to mod_python 3.3 and can't work out why the new importer is not working for you, you can enable the old module importer for specific Python interpreter instances by using: \begin{verbatim} PythonOption mod_python.legacy.importer name \end{verbatim} where 'name' is the name of the interpreter instance or '*' for it to be applied to all interpreter instances. This option should be placed at global context within the main Apache configuration files. \end{notice} When using the \code{apache.import_module()} function, the \var{module_name} should be a string containing either the module name, or a path to the actual code file for the module; where a module is a candidate for automatic module reloading, \var{autoreload} indicates whether the module should be reloaded if it has changed since the last import; when \var{log} is true, a message will be written to the logs when a module is reloaded; \var{path} can be a list specifying additional directories to be searched for modules. With the introduction of mod_python 3.3, the default arguments for the \var{autoreload} and \var{log} arguments have been changed to \code{None}, with the arguments effectively now being unnecessary except in special circumstances. When the arguments are left as the default of \code{None}, the Apache configuration in scope at the time of the call will always be consulted automatically for any settings for the \code{PythonAutoReload} and \code{PythonDebug} directives respectively. Example: \begin{verbatim} from mod_python import apache module = apache.import_module('module_name') \end{verbatim} The \code{apache.import_module()} function is not just a wrapper for the standard Python module import mechanism. The purpose of the function and the mod_python module importer in general, is to provide a means of being able to import modules based on their exact location, with modules being distinguished based on their location rather than just the name of the module. Distinguishing modules in this way, rather than by name alone, means that the same module name can be used for handlers and other code in multiple directories and they will not interfere with each other. A secondary feature of the module importer is to implement a means of having modules automatically reloaded when the corresponding code file has been changed on disk. Having modules be able to be reloaded in this way means that it is possible to change the code for a web application without having to restart the whole Apache web server. Although this was always the intent of the module importer, prior to mod_python 3.3, its effectiveness was limited. With mod_python 3.3 however, the module reloading feature is much more robust and will correctly reload parent modules even when it was only a child module what was changed. When the \code{apache.import_module()} function is called with just the name of the module, as opposed to a path to the actual code file for the module, a search has to be made for the module. The first set of directories that will be checked are those specified by the \var{path} argument if supplied. Where the function is called from another module which had previously been imported by the mod_python importer, the next directory which will be checked will be the same directory as the parent module is located. Where that same parent module contains a global data variable called \code{__mp_path__} containing a list of directories, those directories will also be searched. Finally, the mod_python module importer will search directories specified by the \code{PythonOption} called \code{mod_python.importer.path}. For example: \begin{verbatim} PythonOption mod_python.importer.path "['/some/path']" \end{verbatim} The argument to the option must be in the form of a Python list. The enclosing quotes are to ensure that Apache interprets the argument as a single value. The list must be self contained and cannot reference any prior value of the option. The list MUST NOT reference \code{sys.path} nor should any directory which also appears in \code{sys.path} be listed in the mod_python module importer search path. When searching for the module, a check is made for any code file with the name specified and having a '.py' extension. Because only modules implemented as a single file will be found, packages will not be found nor modules contained within a package. In any case where a module cannot be found, control is handed off to the standard Python module importer which will attempt to find the module or package by searching \code{sys.path}. Note that only modules found by the mod_python module importer are candidates for automatic module reloading. That is, where the mod_python module importer could not find a module and handed the search off to the standard Python module importer, those modules or packages will not be able to be reloaded. Although true Python packages are not candidates for reloading and must be located in a directory listed in \code{sys.path}, another form of packaging up modules such that they can be maintained within their own namespace is supported. When this mechanism is used, these modules will be candidates for reloading when found by the mod_python module importer. In this scheme for maintaining a pseudo package, individual modules are still placed into a directory, but the \code{__init__.py} file in the directory has no special meaning and will not be automatically imported as is the case with true Python packages. Instead, any module within the directory must always be explicitly identified when performing an import. To import a named module contained within these pseudo packages, rather than using a '.' to distinguish a sub module from the parent, a '/' is used instead. For example: \begin{verbatim} from mod_python import apache module = apache.import_module('dirname/module_name') \end{verbatim} If an \code{__init__.py} file is present and it was necessary to import it to achieve the same result as importing the root of a true Python package, then \code{__init__} can be used as the module name. For example: \begin{verbatim} from mod_python import apache module = apache.import_module('dirname/__init__') \end{verbatim} As a true Python package is not being used, if a module in the directory needs to refer to another module in the same directory, it should use just its name, it should not use any form of dotted path name via the root of the package as would be the case for true Python packages. Modules in subdirectories can be imported by using a '/' separated path where the first part of the path is the name of the subdirectory. As a new feature in mod_python 3.3, when using the standard Python 'import' statement to import a module, if the import is being done from a module which was previously imported by the mod_python module importer, it is equivalent to having called \code{apache.import_module()} directly. For example: \begin{verbatim} import name \end{verbatim} is equivalent to: \begin{verbatim} from mod_python import apache name = apache.import_module('name') \end{verbatim} It is also possible to use constructs such as: \begin{verbatim} import name as module \end{verbatim} and: \begin{verbatim} from name import value \end{verbatim} Although the 'import' statement is used, that it maps through to the \code{apache.import_module()} function ensures that parent/child relationships are maintained correctly and reloading of a parent will still work when only the child has been changed. It also ensures that one will not end up with modules which were separately imported by the mod_python module importer and the standard Python module importer. With the reimplementation of the module importer in mod_python 3.3, the \var{module_name} argument may also now be an absolute path name of an actual Python module contained in a single file. On Windows, a drive letter can be supplied if necessary. For example: \begin{verbatim} from mod_python import apache name = apache.import_module('/some/path/name.py') \end{verbatim} or: \begin{verbatim} from mod_python import apache import os here = os.path.dirname(__file__) path = os.path.join(here, 'module.py') module = apache.import_module(path) \end{verbatim} Where the file has an extension, that extension must be supplied. Although it is recommended that code files still make use of the '.py' extension, it is not actually a requirement and an alternate extension can be used. For example: \begin{verbatim} from mod_python import apache import os here = os.path.dirname(__file__) path = os.path.join(here, 'servlet.mps') servlet = apache.import_module(path) \end{verbatim} To avoid the need to use hard coded absolute path names to modules, a few shortcuts are provided. The first of these allow for the use of relative path names with respect to the directory the module performing the import is located within. For example: \begin{verbatim} from mod_python import apache parent = apache.import_module('../module.py') subdir = apache.import_module('./subdir/module.py') \end{verbatim} Forward slashes must always be used for the prefixes './' and '../', even on Windows hosts where native pathname use a backslash. This convention of using forward slashes is used as that is what Apache normalizes all paths to internally. If you are using Windows and have been using backward slashes with \code{Directory} directives etc, you are using Apache contrary to what is the accepted norm. A further shortcut allows paths to be declared relative to what is regarded as the handler root directory. The handler root directory is the directory context in which the active \code{Python*Handler} directive was specified. If the directive was specified within a \code{Location} or \code{VirtualHost} directive, or at global server scope, the handler root will be the relevant document root for the server. To express paths relative to the handler root, the '\textasciitilde/' prefix should be used. A forward slash must again always be used, even on Windows. For example: \begin{verbatim} from mod_python import apache parent = apache.import_module('~/../module.py') subdir = apache.import_module('~/subdir/module.py') \end{verbatim} In all cases where a path to the actual code file for a module is given, the \var{path} argument is redundant as there is no need to search through a list of directories to find the module. In these situations, the \var{path} is instead taken to be a list of directories to use as the initial value of the \code{__mp_path__} variable contained in the imported modules instead of an empty path. This feature can be used to attach a more restrictive search path to a set of modules rather than using the \code{PythonOption} to set a global search path. To do this, the modules should always be imported through a specific parent module. That module should then always import submodules using paths and supply \code{__mp_path__} as the \var{path} argument to subsequent calls to \code{apache.import_module()} within that module. For example: \begin{verbatim} from mod_python import apache module1 = apache.import_module('./module1.py', path=__mp_path__) module2 = apache.import_module('./module2.py', path=__mp_path__) \end{verbatim} with the module being imported as: \begin{verbatim} from mod_python import apache parent = apache.import_module('~/modules/parent.py', path=['/some/path']) \end{verbatim} The parent module may if required extend the value of \code{__mp_path__} prior to using it. Any such directories will be added to those inherited via the \var{path} argument. For example: \begin{verbatim} from mod_python import apache import os here = os.path.dirname(__file__) subdir = os.path.join(here, 'subdir') __mp_path__.append(subdir) module1 = apache.import_module('./module1.py', path=__mp_path__) module2 = apache.import_module('./module2.py', path=__mp_path__) \end{verbatim} In all cases where a search path is being specified which is specific to the mod_python module importer, whether it be specified using the \code{PythonOption} called \code{mod_python.importer.path}, using the \var{path} argument to the \code{apache.import_module()} function or in the \code{__mp_path__} attribute, the prefix '\textasciitilde/' can be used in a path and that path will be taken as being relative to handler root. For example: \begin{verbatim} PythonOption mod_python.importer.path "['~/modules']" \end{verbatim} If wishing to refer to the handler root directory itself, then '\textasciitilde' can be used and the trailing slash left off. For example: \begin{verbatim} PythonOption mod_python.importer.path "['~']" \end{verbatim} Note that with the new module importer, as directories associated with \code{Python*Handler} directives are no longer being added automatically to \code{sys.path} and they are instead used directly by the module importer only when required, some existing code which expected to be able to import modules in the handler root directory from a module in a subdirectory may no longer work. In these situations it will be necessary to set the mod_python module importer path to include '\textasciitilde' or list '\textasciitilde' in the \code{__mp_path__} attribute of the module performing the import. This trick of listing '\textasciitilde' in the module importer path will not however help in the case where Python packages were previously being placed into the handler root directory. In this case, the Python package should either be moved out of the document tree and the directory where it is located listed against the \code{PythonPath} directive, or the package converted into the pseudo packages that mod_python supports and change the module imports used to access the package. Only modules which could be imported by the mod_python module importer will be candidates for automatic reloading when changes are made to the code file on disk. Any modules or packages which were located in a directory listed in \code{sys.path} and which were imported using the standard Python module importer will not be candidates for reloading. Even where modules are candidates for module reloading, unless a true value was explicitly supplied as the \var{autoreload} option to the \code{apache.import_module()} function they will only be reloaded if the \code{PythonAutoReload} directive is \code{On}. The default value when the directive is not specified will be \code{On}, so the directive need only be used when wishing to set it to \code{Off} to disable automatic reloading, such as in a production system. Where possible, the \code{PythonAutoReload} directive should only be specified in one place and in the root context for a specific Python interpreter instance. If the \code{PythonAutoReload} directive is used in multiple places with different values, or doesn't cover all directories pertaining to a specific Python interpreter instance, then problems can result. This is because requests against some URLs may result in modules being reloaded whereas others may not, even when through each URL the same module may be imported from a common location. If absolute certainty is required that module reloading is disabled and that it isn't being enabled through some subset of URLs, the \code{PythonImport} directive should be used to import a special module whenever an Apache child process is being created. This module should include a call to the \code{apache.freeze_modules()} function. This will have the effect of permanently disabling module reloading for the complete life of that Apache child process, irrespective of what value the \code{PythonAutoReload} directive is set to. Using the new ability within mod_python 3.3 to have \code{PythonImport} call a specific function within a module after it has been imported, one could actually dispense with creating a module and instead call the function directory out of the \code{mod_python.apache} module. For example: \begin{verbatim} PythonImport mod_python.apache::freeze_modules interpreter_name \end{verbatim} Where module reloading is being undertaken, unlike the core module importer in versions of mod_python prior to 3.3, they are not reloaded on top of existing modules, but into a completely new module instance. This means that any code that previously relied on state information or data caches to be preserved across reloads will no longer work. If it is necessary to transfer such information from an old module to the new module, it is necessary to provide a hook function within modules to transfer across the data that must be preserved. The name of this hook function is \code{__mp_clone__()}. The argument given to the hook function will be an empty module into which the new module will subsequently be loaded. When called, the hook function should copy any data from the old module to the new module. In doing this, the code performing the copying should be cognizant of the fact that within a multithreaded Apache MPM that other request handlers could still be trying to access and update the data to be copied. As such, the hook function should ensure that it uses any thread locking mechanisms within the module as appropriate when copying the data. Further, it should copy the actual data locks themselves across to the new module to ensure a clean transition. Because copying integral values will result in the data then being separate, it may be necessary to always store data within a dictionary so as to provide a level of indirection which will allow the data to be usable from both module instances while they still exist. For example: \begin{verbatim} import threading, time if not globals().has_key('_lock'): # Initial import of this module. _lock = threading.Lock() _data1 = { 'value1' : 0, 'value2': 0 } _data2 = {} def __mp_clone__(module): _lock.acquire() module._lock = _lock module._data1 = _data1 module._data2 = _data2 _lock.release() \end{verbatim} Because the old module is about to be discarded, the data which is transferred should not consist of data objects which are dependent on code within the old module. Data being copied across to the new module should consist of standard Python data types, or be instances of classes contained within modules which themselves are not candidates for reloading. Otherwise, data should be migrated by transforming it into some neutral intermediate state, with the new module transforming it back when its code executes at the time of being imported. If these guidelines aren't heeded and data is dependent on code objects within the old module, it will prevent those code objects from being unloaded and if this continues across multiple reloads, then process size may increase over time due to old code objects being retained. In any case, if for some reason the hook function fails and an exception is raised then both the old and new modules will be discarded. As a last opportunity to release any resources when this occurs, an extra hook function called \code{__mp_purge__()} can be supplied. This function will be called with no arguments. \end{funcdesc} \begin{funcdesc}{allow_methods}{\optional{*args}} A convenience function to set values in \member{req.allowed}. \member{req.allowed} is a bitmask that is used to construct the \samp{Allow:} header. It should be set before returning a \code{HTTP_NOT_IMPLEMENTED} error. Arguments can be one or more of the following: \begin{verbatim} M_GET M_PUT M_POST M_DELETE M_CONNECT M_OPTIONS M_TRACE M_PATCH M_PROPFIND M_PROPPATCH M_MKCOL M_COPY M_MOVE M_LOCK M_UNLOCK M_VERSION_CONTROL M_CHECKOUT M_UNCHECKOUT M_CHECKIN M_UPDATE M_LABEL M_REPORT M_MKWORKSPACE M_MKACTIVITY M_BASELINE_CONTROL M_MERGE M_INVALID \end{verbatim} \end{funcdesc} \begin{funcdesc}{exists_config_define}{name} This function returns True if the Apache server was launched with the definition with the given \var{name}. This means that you can test whether Apache was launched with the \code{-DFOOBAR} parameter by calling \code{apache.exists_config_define('FOOBAR')}. \end{funcdesc} \begin{funcdesc}{stat}{fname, wanted} This function returns an instance of an \code{mp_finfo} object describing information related to the file with name \code{fname}. The \code{wanted} argument describes the minimum attributes which should be filled out. The resultant object can be assigned to the \code{req.finfo} attribute. \end{funcdesc} \begin{funcdesc}{register_cleanup}{callable\optional{, data}} Registers a cleanup that will be performed at child shutdown time. Equivalent to \function{server.register_cleanup()}, except that a request object is not required. \emph{Warning:} do not pass directly or indirectly a request object in the data parameter. Since the callable will be called at server shutdown time, the request object won't exist anymore and any manipulation of it in the handler will give undefined behaviour. \end{funcdesc} \begin{funcdesc}{config_tree}{} Returns the server-level configuration tree. This tree does not include directives from .htaccess files. This is a \emph{copy} of the tree, modifying it has no effect on the actual configuration. \end{funcdesc} \begin{funcdesc}{server_root}{} Returns the value of ServerRoot. \end{funcdesc} \begin{funcdesc}{make_table}{} This function is obsolete and is an alias to \class{table} (see below). \end{funcdesc} \begin{funcdesc}{mpm_query}{code} Allows querying of the MPM for various parameters such as numbers of processes and threads. The return value is one of three constants: \begin{verbatim} AP_MPMQ_NOT_SUPPORTED = 0 # This value specifies whether # an MPM is capable of # threading or forking. AP_MPMQ_STATIC = 1 # This value specifies whether # an MPM is using a static # of # threads or daemons. AP_MPMQ_DYNAMIC = 2 # This value specifies whether # an MPM is using a dynamic # of # threads or daemons. \end{verbatim} The \var{code} argument must be one of the following: \begin{verbatim} AP_MPMQ_MAX_DAEMON_USED = 1 # Max # of daemons used so far AP_MPMQ_IS_THREADED = 2 # MPM can do threading AP_MPMQ_IS_FORKED = 3 # MPM can do forking AP_MPMQ_HARD_LIMIT_DAEMONS = 4 # The compiled max # daemons AP_MPMQ_HARD_LIMIT_THREADS = 5 # The compiled max # threads AP_MPMQ_MAX_THREADS = 6 # # of threads/child by config AP_MPMQ_MIN_SPARE_DAEMONS = 7 # Min # of spare daemons AP_MPMQ_MIN_SPARE_THREADS = 8 # Min # of spare threads AP_MPMQ_MAX_SPARE_DAEMONS = 9 # Max # of spare daemons AP_MPMQ_MAX_SPARE_THREADS = 10 # Max # of spare threads AP_MPMQ_MAX_REQUESTS_DAEMON= 11 # Max # of requests per daemon AP_MPMQ_MAX_DAEMONS = 12 # Max # of daemons by config \end{verbatim} Example: \begin{verbatim} if apache.mpm_query(apache.AP_MPMQ_IS_THREADED): # do something else: # do something else \end{verbatim} \end{funcdesc} \subsection{Attributes\label{pyapi-apmem}} \begin{memberdesc}[apache]{interpreter} The name of the subinterpreter under which we're running. \emph{(Read-Only)} \end{memberdesc} \begin{memberdesc}[apache]{main_server} A \code{server} object for the main server. \emph{(Read-Only}) \end{memberdesc} \subsection{Table Object (mp_table)\obindex{table}\label{pyapi-mptable}} \index{table} \begin{classdesc}{table}{\optional{mapping-or-sequence}} Returns a new empty object of type \code{mp_table}. See Section \ref{pyapi-mptable} for description of the table object. The \var{mapping-or-sequence} will be used to provide initial values for the table. The table object is a wrapper around the Apache APR table. The table object behaves very much like a dictionary (including the Python 2.2 features such as support of the \code{in} operator, etc.), with the following differences: \begin{itemize} \item Both keys and values must be strings. \item Key lookups are case-insensitive. \item Duplicate keys are allowed (see \method{add()} below). When there is more than one value for a key, a subscript operation returns a list. \end{itemize} Much of the information that Apache uses is stored in tables. For example, \member{req.headers_in} and \member{req.headers_out}. All the tables that mod_python provides inside the request object are actual mappings to the Apache structures, so changing the Python table also changes the underlying Apache table. In addition to normal dictionary-like behavior, the table object also has the following method: \begin{methoddesc}[table]{add}{key, val} \function{add()} allows for creating duplicate keys, which is useful when multiple headers, such as \code{Set-Cookie:} are required. \end{methoddesc} \versionadded{3.0} \end{classdesc} \subsection{Request Object\index{request}\label{pyapi-mprequest}} The request object is a Python mapping to the Apache \code{request_rec} structure. When a handler is invoked, it is always passed a single argument - the request object. You can dynamically assign attributes to it as a way to communicate between handlers. \subsubsection{Request Methods\label{pyapi-mprequest-meth}} \begin{methoddesc}[request]{add_common_vars}{} Calls the Apache \cfunction{ap_add_common_vars()} function. After a call to this method, \member{req.subprocess_env} will contain a lot of CGI information. \end{methoddesc} \begin{methoddesc}[request]{add_handler}{htype, handler\optional{, dir}} Allows dynamic handler registration. \var{htype} is a string containing the name of any of the apache request (but not filter or connection) handler directives, e.g. \samp{PythonHandler}. \var{handler} is a string containing the name of the module and the handler function, or the callable object itself. Optional \var{dir} is a string containing the name of the directory to be added to the module search path when looking for the handler. If no directory is specified, then the directory to search in is inherited from the handler which is making the registration, A handler added this way only persists throughout the life of the request. It is possible to register more handlers while inside the handler of the same type. One has to be careful as to not to create an infinite loop this way. Dynamic handler registration is a useful technique that allows the code to dynamically decide what will happen next. A typical example might be a \code{PythonAuthenHandler} that will assign different \code{PythonHandlers} based on the authorization level, something like: \begin{verbatim} if manager: req.add_handler("PythonHandler", "menu::admin") else: req.add_handler("PythonHandler", "menu::basic") \end{verbatim} \begin{notice} If you pass this function an invalid handler, an exception will be generated at the time an attempt is made to find the handler. \end{notice} \end{methoddesc} \begin{methoddesc}[request]{add_input_filter}{filter_name} Adds the named filter into the input filter chain for the current request. The filter should be added before the first attempt to read any data from the request. \end{methoddesc} \begin{methoddesc}[request]{add_output_filter}{filter_name} Adds the named filter into the output filter chain for the current request. The filter should be added before the first attempt to write any data for the response. Provided that all data written is being buffered and not flushed, this could be used to add the "CONTENT_LENGTH" filter into the chain of output filters. The purpose of the "CONTENT_LENGTH" filter is to add a \code{Content-Length:} header to the response. \begin{verbatim} req.add_output_filter("CONTENT_LENGTH") req.write("content",0) \end{verbatim} \end{methoddesc} \begin{methoddesc}[request]{allow_methods}{methods\optional{, reset}} Adds methods to the \member{req.allowed_methods} list. This list will be passed in \code{Allowed:} header if \constant{HTTP_METHOD_NOT_ALLOWED} or \constant{HTTP_NOT_IMPLEMENTED} is returned to the client. Note that Apache doesn't do anything to restrict the methods, this list is only used to construct the header. The actual method-restricting logic has to be provided in the handler code. \var{methods} is a sequence of strings. If \var{reset} is 1, then the list of methods is first cleared. \end{methoddesc} \begin{methoddesc}[request]{auth_name}{} Returns AuthName setting. \end{methoddesc} \begin{methoddesc}[request]{auth_type}{} Returns AuthType setting. \end{methoddesc} \begin{methoddesc}[request]{construct_url}{uri} This function returns a fully qualified URI string from the path specified by uri, using the information stored in the request to determine the scheme, server name and port. The port number is not included in the string if it is the same as the default port 80. For example, imagine that the current request is directed to the virtual server www.modpython.org at port 80. Then supplying \samp{/index.html} will yield the string \samp{http://www.modpython.org/index.html}. \end{methoddesc} \begin{methoddesc}[request]{discard_request_body}{} Tests for and reads any message body in the request, simply discarding whatever it receives. \end{methoddesc} \begin{methoddesc}[request]{document_root}{} Returns DocumentRoot setting. \end{methoddesc} \begin{methoddesc}[request]{get_basic_auth_pw}{} Returns a string containing the password when Basic authentication is used. \end{methoddesc} \begin{methoddesc}[request]{get_config}{} Returns a reference to the table object containing the mod_python configuration in effect for this request except for \code{Python*Handler} and \code{PythonOption} (The latter can be obtained via \method{req.get_options()}. The table has directives as keys, and their values, if any, as values. \end{methoddesc} \begin{methoddesc}[request]{get_remote_host}{\optional{type, str_is_ip}} This method is used to determine remote client's DNS name or IP number. The first call to this function may entail a DNS look up, but subsequent calls will use the cached result from the first call. The optional \var{type} argument can specify the following: \begin{itemize} \item \code{apache.REMOTE_HOST} Look up the DNS name. Return None if Apache directive \code{HostNameLookups} is \code{off} or the hostname cannot be determined. \item \code{apache.REMOTE_NAME} \emph{(Default)} Return the DNS name if possible, or the IP (as a string in dotted decimal notation) otherwise. \item \code{apache.REMOTE_NOLOOKUP} Don't perform a DNS lookup, return an IP. Note: if a lookup was performed prior to this call, then the cached host name is returned. \item \code{apache.REMOTE_DOUBLE_REV} Force a double-reverse lookup. On failure, return None. \end{itemize} If \var{str_is_ip} is \code{None} or unspecified, then the return value is a string representing the DNS name or IP address. If the optional \var{str_is_ip} argument is not \code{None}, then the return value is an \code{(address, str_is_ip)} tuple, where \var{str_is_ip} is non-zero if \code{address} is an IP address string. On failure, \code{None} is returned. \end{methoddesc} \begin{methoddesc}[request]{get_options}{} Returns a reference to the table object containing the options set by the \code{PythonOption} directives. \end{methoddesc} \begin{methoddesc}[request]{internal_redirect}{new_uri} Internally redirects the request to the \var{new_uri}. \var{new_uri} must be a string. The httpd server handles internal redirection by creating a new request object and processing all request phases. Within an internal redirect, \code{req.prev} will contain a reference to a request object from which it was redirected. \end{methoddesc} \begin{methoddesc}[request]{is_https}{} Returns non-zero if the connection is using SSL/TLS. Will always return zero if the mod_ssl Apache module is not loaded. You can use this method during any request phase, unlike looking for the \code{HTTPS} variable in the \code{subprocess_env} member dictionary. This makes it possible to write an authentication or access handler that makes decisions based upon whether SSL is being used. Note that this method will not determine the quality of the encryption being used. For that you should call the \code{ssl_var_lookup} method to get one of the \code{SSL_CIPHER*} variables. \end{methoddesc} \begin{methoddesc}[request]{log_error}{message\optional{, level}} An interface to the Apache \code{ap_log_rerror} function. \var{message} is a string with the error message, \var{level} is one of the following flags constants: \begin{verbatim} APLOG_EMERG APLOG_ALERT APLOG_CRIT APLOG_ERR APLOG_WARNING APLOG_NOTICE APLOG_INFO APLOG_DEBUG APLOG_NOERRNO \end{verbatim} If you need to write to log and do not have a reference to a request object, use the \function{apache.log_error} function. \end{methoddesc} \begin{methoddesc}[request]{meets_conditions}{} Calls the Apache \cfunction{ap_meets_conditions()} function which returns a status code. If \var{status} is \constant{apache.OK}, generate the content of the response normally. If not, simply return \var{status}. Note that \var{mtime} (and possibly the ETag header) should be set as appropriate prior to calling this function. The same goes for \member{req.status} if the status differs from \constant{apache.OK}. Example: \begin{verbatim} ... r.headers_out['ETag'] = '"1130794f-3774-4584-a4ea-0ab19e684268"' r.headers_out['Expires'] = 'Mon, 18 Apr 2005 17:30:00 GMT' r.update_mtime(1000000000) r.set_last_modified() status = r.meets_conditions() if status != apache.OK: return status ... do expensive generation of the response content ... \end{verbatim} \end{methoddesc} \begin{methoddesc}[request]{requires}{} Returns a tuple of strings of arguments to \code{require} directive. For example, with the following apache configuration: \begin{verbatim} AuthType Basic require user joe require valid-user \end{verbatim} \method{requires()} would return \code{('user joe', 'valid-user')}. \end{methoddesc} \begin{methoddesc}[request]{read}{\optional{len}} Reads at most \var{len} bytes directly from the client, returning a string with the data read. If the \var{len} argument is negative or omitted, reads all data given by the client. This function is affected by the \code{Timeout} Apache configuration directive. The read will be aborted and an \exception{IOError} raised if the \code{Timeout} is reached while reading client data. This function relies on the client providing the \code{Content-length} header. Absence of the \code{Content-length} header will be treated as if \code{Content-length: 0} was supplied. Incorrect \code{Content-length} may cause the function to try to read more data than available, which will make the function block until a \code{Timeout} is reached. \end{methoddesc} \begin{methoddesc}[request]{readline}{\optional{len}} Like \function{read()} but reads until end of line. \begin{notice} In accordance with the HTTP specification, most clients will be terminating lines with \samp{\e r\e n} rather than simply \samp{\e n}. \end{notice} \end{methoddesc} \begin{methoddesc}[request]{readlines}{\optional{sizehint}} Reads all lines using \method{readline} and returns a list of the lines read. If the optional \var{sizehint} parameter is given in, the method will read at least \var{sizehint} bytes of data, up to the completion of the line in which the \var{sizehint} bytes limit is reached. \end{methoddesc} \begin{methoddesc}[request]{register_cleanup}{callable\optional{, data}} Registers a cleanup. Argument \var{callable} can be any callable object, the optional argument \var{data} can be any object (default is \code{None}). At the very end of the request, just before the actual request record is destroyed by Apache, \var{callable} will be called with one argument, \var{data}. It is OK to pass the request object as data, but keep in mind that when the cleanup is executed, the request processing is already complete, so doing things like writing to the client is completely pointless. If errors are encountered during cleanup processing, they should be in error log, but otherwise will not affect request processing in any way, which makes cleanup bugs sometimes hard to spot. If the server is shut down before the cleanup had a chance to run, it's possible that it will not be executed. \end{methoddesc} \begin{methoddesc}[request]{register_input_filter}{filter_name, filter\optional{, dir}} Allows dynamic registration of mod_python input filters. \var{filter_name} is a string which would then subsequently be used to identify the filter. \var{filter} is a string containing the name of the module and the filter function or the callable object itself. Optional \var{dir} is a string containing the name of the directory to be added to the module search when looking for the module. The registration of the filter this way only persists for the life of the request. To actually add the filter into the chain of input filters for the current request \code{req.add_input_filter()} would be used. \end{methoddesc} \begin{methoddesc}[request]{register_output_filter}{filter_name, filter\optional{, dir}} Allows dynamic registration of mod_python output filters. \var{filter_name} is a string which would then subsequently be used to identify the filter. \var{filter} is a string containing the name of the module and the filter function or the callable object itself. Optional \var{dir} is a string containing the name of the directory to be added to the module search path when looking for the handler. The registration of the filter this way only persists for the life of the request. To actually add the filter into the chain of output filters for the current request \code{req.add_output_filter()} would be used. \end{methoddesc} \begin{methoddesc}[request]{sendfile}{path\optional{, offset, len}} Sends \var{len} bytes of file \var{path} directly to the client, starting at offset \var{offset} using the server's internal API. \var{offset} defaults to 0, and \var{len} defaults to -1 (send the entire file). Returns the number of bytes sent, or raises an IOError exception on failure. This function provides the most efficient way to send a file to the client. \end{methoddesc} \begin{methoddesc}[request]{set_etag}{} Sets the outgoing \samp{ETag} header. \end{methoddesc} \begin{methoddesc}[request]{set_last_modified}{} Sets the outgoing \samp{Last-Modified} header based on value of \code{mtime} attribute. \end{methoddesc} \begin{methoddesc}[request]{ssl_var_lookup}{var_name} Looks up the value of the named SSL variable. This method queries the mod_ssl Apache module directly, and may therefore be used in early request phases (unlike using the \code{subprocess_env} member. If the mod_ssl Apache module is not loaded or the variable is not found then \code{None} is returned. If you just want to know if a SSL or TLS connection is being used, you may consider calling the \code{is_https} method instead. It is unfortunately not possible to get a list of all available variables with the current mod_ssl implementation, so you must know the name of the variable you want. Some of the potentially useful ssl variables are listed below. For a complete list of variables and a description of their values see the mod_ssl documentation. \begin{verbatim} SSL_CIPHER SSL_CLIENT_CERT SSL_CLIENT_VERIFY SSL_PROTOCOL SSL_SESSION_ID \end{verbatim} \begin{notice} Not all SSL variables are defined or have useful values in every request phase. Also use caution when relying on these values for security purposes, as SSL or TLS protocol parameters can often be renegotiated at any time during a request. \end{notice} \end{methoddesc} \begin{methoddesc}[request]{update_mtime}{dependency_mtime} If \var{dependency_mtime} is later than the value in the \code{mtime} attribute, sets the attribute to the new value. \end{methoddesc} \begin{methoddesc}[request]{write}{string\optional{, flush=1}} Writes \var{string} directly to the client, then flushes the buffer, unless flush is 0. \end{methoddesc} \begin{methoddesc}[request]{flush}{} Flushes the output buffer. \end{methoddesc} \begin{methoddesc}[request]{set_content_length}{len} Sets the value of \member{req.clength} and the \samp{Content-Length} header to len. Note that after the headers have been sent out (which happens just before the first byte of the body is written, i.e. first call to \member{req.write()}), calling the method is meaningless. \end{methoddesc} \subsubsection{Request Members\label{pyapi-mprequest-mem}} \begin{memberdesc}[request]{connection} A \code{connection} object associated with this request. See Connection Object below for details. \emph{(Read-Only)} \end{memberdesc} \begin{memberdesc}[request]{server} A server object associate with this request. See Server Object below for details. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{next} If this is an internal redirect, the request object we redirect to. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{prev} If this is an internal redirect, the request object we redirect from. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{main} If this is a sub-request, pointer to the main request. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{the_request} String containing the first line of the request. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{assbackwards} Indicates an HTTP/0.9 ``simple'' request. This means that the response will contain no headers, only the body. Although this exists for backwards compatibility with obsolescent browsers, some people have figred out that setting assbackwards to 1 can be a useful technique when including part of the response from an internal redirect to avoid headers being sent. \end{memberdesc} \begin{memberdesc}[request]{proxyreq} A proxy request: one of \constant{apache.PROXYREQ_*} values. \end{memberdesc} \begin{memberdesc}[request]{header_only} A boolean value indicating HEAD request, as opposed to GET. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{protocol} Protocol, as given by the client, or \samp{HTTP/0.9}. Same as CGI \envvar{SERVER_PROTOCOL}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{proto_num} Integer. Number version of protocol; 1.1 = 1001 \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{hostname} String. Host, as set by full URI or Host: header. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{request_time} A long integer. When request started. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{status_line} Status line. E.g. \samp{200 OK}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{status} Status. One of \constant{apache.HTTP_*} values. \end{memberdesc} \begin{memberdesc}[request]{method} A string containing the method - 'GET', 'HEAD', 'POST', etc. Same as CGI \envvar{REQUEST_METHOD}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{method_number} Integer containing the method number. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{allowed} Integer. A bitvector of the allowed methods. Used to construct the Allowed: header when responding with \constant{HTTP_METHOD_NOT_ALLOWED} or \constant{HTTP_NOT_IMPLEMENTED}. This field is for Apache's internal use, to set the Allowed: methods use \method{req.allow_methods()} method, described in section \ref{pyapi-mprequest-meth}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{allowed_xmethods} Tuple. Allowed extension methods. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{allowed_methods} Tuple. List of allowed methods. Used in relation with \constant{METHOD_NOT_ALLOWED}. This member can be modified via \method{req.allow_methods()} described in section \ref{pyapi-mprequest-meth}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{sent_bodyct} Integer. Byte count in stream is for body. (?) \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{bytes_sent} Long integer. Number of bytes sent. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{mtime} Long integer. Time the resource was last modified. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{chunked} Boolean value indicating when sending chunked transfer-coding. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{range} String. The \code{Range:} header. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{clength} Long integer. The ``real'' content length. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{remaining} Long integer. Bytes left to read. (Only makes sense inside a read operation.) \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{read_length} Long integer. Number of bytes read. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{read_body} Integer. How the request body should be read. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{read_chunked} Boolean. Read chunked transfer coding. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{expecting_100} Boolean. Is client waiting for a 100 (\constant{HTTP_CONTINUE}) response. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{headers_in} A table object containing headers sent by the client. \end{memberdesc} \begin{memberdesc}[request]{headers_out} A \code{table} object representing the headers to be sent to the client. \end{memberdesc} \begin{memberdesc}[request]{err_headers_out} These headers get send with the error response, instead of headers_out. \end{memberdesc} \begin{memberdesc}[request]{subprocess_env} A \code{table} object containing environment information typically usable for CGI. You may have to call \member{req.add_common_vars()} first to fill in the information you need. \end{memberdesc} \begin{memberdesc}[request]{notes} A \code{table} object that could be used to store miscellaneous general purpose info that lives for as long as the request lives. If you need to pass data between handlers, it's better to simply add members to the request object than to use \member{notes}. \end{memberdesc} \begin{memberdesc}[request]{phase} The phase currently being being processed, e.g. \samp{PythonHandler}. \emph{(Read-Only)} \end{memberdesc} \begin{memberdesc}[request]{interpreter} The name of the subinterpreter under which we're running. \emph{(Read-Only)} \end{memberdesc} \begin{memberdesc}[request]{content_type} String. The content type. Mod_python maintains an internal flag (\member{req._content_type_set}) to keep track of whether \member{content_type} was set manually from within Python. The publisher handler uses this flag in the following way: when \member{content_type} isn't explicitly set, it attempts to guess the content type by examining the first few bytes of the output. \end{memberdesc} \begin{memberdesc}[request]{content_languages} Tuple. List of strings representing the content languages. \end{memberdesc} \begin{memberdesc}[request]{handler} The symbolic name of the content handler (as in module, not mod_python handler) that will service the request during the response phase. When the SetHandler/AddHandler directives are used to trigger mod_python, this will be set to \samp{mod_python} by mod_mime. A mod_python handler executing prior to the response phase may also set this to \samp{mod_python} along with calling \samp{req.add_handler()} to register a mod_python handler for the response phase. \begin{verbatim} def typehandler(req): if os.path.splitext(req.filename)[1] == ".py": req.handler = "mod_python" req.add_handler("PythonHandler", "mod_python.publisher") return apache.OK return apache.DECLINED \end{verbatim} \end{memberdesc} \begin{memberdesc}[request]{content_encoding} String. Content encoding. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{vlist_validator} Integer. Variant list validator (if negotiated). \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{user} If an authentication check is made, this will hold the user name. Same as CGI \envvar{REMOTE_USER}. \begin{notice} \method{req.get_basic_auth_pw()} must be called prior to using this value. \end{notice} \end{memberdesc} \begin{memberdesc}[request]{ap_auth_type} Authentication type. Same as CGI \envvar{AUTH_TYPE}. \end{memberdesc} \begin{memberdesc}[request]{no_cache} Boolean. This response cannot be cached. \end{memberdesc} \begin{memberdesc}[request]{no_local_copy} Boolean. No local copy exists. \end{memberdesc} \begin{memberdesc}[request]{unparsed_uri} The URI without any parsing performed. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{uri} The path portion of the URI. \end{memberdesc} \begin{memberdesc}[request]{filename} String. File name being requested. \end{memberdesc} \begin{memberdesc}[request]{canonical_filename} String. The true filename (\member{req.filename} is canonicalized if they don't match). \end{memberdesc} \begin{memberdesc}[request]{path_info} String. What follows after the file name, but is before query args, if anything. Same as CGI \envvar{PATH_INFO}. \end{memberdesc} \begin{memberdesc}[request]{args} String. Same as CGI \envvar{QUERY_ARGS}. \end{memberdesc} \begin{memberdesc}[request]{finfo} A file information object with type \code{mp_finfo}, analogous to the result of the POSIX stat function, describing the file pointed to by the URI. The object provides the attributes \code{fname}, \code{filetype}, \code{valid}, \code{protection}, \code{user}, \code{group}, \code{size}, \code{inode}, \code{device}, \code{nlink}, \code{atime}, \code{mtime}, \code{ctime} and \code{name}. The attribute may be assigned to using the result of \code{apache.stat()}. For example: \begin{verbatim} if req.finfo.filetype == apache.APR_DIR: req.filename = posixpath.join(req.filename, 'index.html') req.finfo = apache.stat(req.filename, apache.APR_FINFO_MIN) \end{verbatim} For backward compatability, the object can also be accessed as if it were a tuple. The \code{apache} module defines a set of \constant{FINFO_*} constants that should be used to access elements of this tuple. \begin{verbatim} user = req.finfo[apache.FINFO_USER] \end{verbatim} \end{memberdesc} \begin{memberdesc}[request]{parsed_uri} Tuple. The URI broken down into pieces. \code{(scheme, hostinfo, user, password, hostname, port, path, query, fragment)}. The \code{apache} module defines a set of \constant{URI_*} constants that should be used to access elements of this tuple. Example: \begin{verbatim} fname = req.parsed_uri[apache.URI_PATH] \end{verbatim} \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[request]{used_path_info} Flag to accept or reject path_info on current request. \end{memberdesc} \begin{memberdesc}[request]{eos_sent} Boolean. EOS bucket sent. \emph{(Read-Only}) \end{memberdesc} \subsection{Connection Object (mp_conn)\obindex{connection}\label{pyapi-mpconn}} The connection object is a Python mapping to the Apache conn_rec structure. \subsubsection{Connection Methods\label{pyapi-mpconn-meth}} \begin{methoddesc}[connection]{log_error}{message\optional{, level}} An interface to the Apache \code{ap_log_cerror} function. \var{message} is a string with the error message, \var{level} is one of the following flags constants: \begin{verbatim} APLOG_EMERG APLOG_ALERT APLOG_CRIT APLOG_ERR APLOG_WARNING APLOG_NOTICE APLOG_INFO APLOG_DEBUG APLOG_NOERRNO \end{verbatim} If you need to write to log and do not have a reference to a connection or request object, use the \function{apache.log_error} function. \end{methoddesc} \begin{methoddesc}[connection]{read}{\optional{length}} Reads at most \var{length} bytes from the client. The read blocks indefinitely until there is at least one byte to read. If length is -1, keep reading until the socket is closed from the other end (This is known as \code{EXHAUSTIVE} mode in the http server code). This method should only be used inside \emph{Connection Handlers}. \begin{notice} The behaviour of this method has changed since version 3.0.3. In 3.0.3 and prior, this method would block until \var{length} bytes was read. \end{notice} \end{methoddesc} \begin{methoddesc}[connection]{readline}{\optional{length}} Reads a line from the connection or up to \var{length} bytes. This method should only be used inside \emph{Connection Handlers}. \end{methoddesc} \begin{methoddesc}[connection]{write}{string} Writes \var{string} to the client. This method should only be used inside \emph{Connection Handlers}. \end{methoddesc} \subsubsection{Connection Members\label{pyapi-mpconn-mem}} \begin{memberdesc}[connection]{base_server} A \code{server} object for the physical vhost that this connection came in through. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{local_addr} The (address, port) tuple for the server. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{remote_addr} The (address, port) tuple for the client. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{remote_ip} String with the IP of the client. Same as CGI \envvar{REMOTE_ADDR}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{remote_host} String. The DNS name of the remote client. None if DNS has not been checked, \code{""} (empty string) if no name found. Same as CGI \envvar{REMOTE_HOST}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{remote_logname} Remote name if using RFC1413 (ident). Same as CGI \envvar{REMOTE_IDENT}. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{aborted} Boolean. True is the connection is aborted. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{keepalive} Integer. 1 means the connection will be kept for the next request, 0 means ``undecided'', -1 means ``fatal error''. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{double_reverse} Integer. 1 means double reverse DNS lookup has been performed, 0 means not yet, -1 means yes and it failed. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{keepalives} The number of times this connection has been used. (?) \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{local_ip} String with the IP of the server. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{local_host} DNS name of the server. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{id} Long. A unique connection id. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[connection]{notes} A \code{table} object containing miscellaneous general purpose info that lives for as long as the connection lives. \end{memberdesc} \subsection{Filter Object (mp_filter)\obindex{filter}\label{pyapi-mpfilt}} A filter object is passed to mod_python input and output filters. It is used to obtain filter information, as well as get and pass information to adjacent filters in the filter stack. \subsubsection{Filter Methods\label{pyapi-mpfilt-meth}} \begin{methoddesc}[filter]{pass_on}{} Passes all data through the filter without any processing. \end{methoddesc} \begin{methoddesc}[filter]{read}{\optional{length}} Reads at most \var{len} bytes from the next filter, returning a string with the data read or None if End Of Stream (EOS) has been reached. A filter \emph{must} be closed once the EOS has been encountered. If the \var{len} argument is negative or omitted, reads all data currently available. \end{methoddesc} \begin{methoddesc}[filter]{readline}{\optional{length}} Reads a line from the next filter or up to \var{length} bytes. \end{methoddesc} \begin{methoddesc}[filter]{write}{string} Writes \var{string} to the next filter. \end{methoddesc} \begin{methoddesc}[filter]{flush}{} Flushes the output by sending a FLUSH bucket. \end{methoddesc} \begin{methoddesc}[filter]{close}{} Closes the filter and sends an EOS bucket. Any further IO operations on this filter will throw an exception. \end{methoddesc} \begin{methoddesc}[filter]{disable}{} Tells mod_python to ignore the provided handler and just pass the data on. Used internally by mod_python to print traceback from exceptions encountered in filter handlers to avoid an infinite loop. \end{methoddesc} \subsubsection{Filter Members\label{pyapi-mpfilt-mem}} \begin{memberdesc}[filter]{closed} A boolean value indicating whether a filter is closed. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[filter]{name} String. The name under which this filter is registered. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[filter]{req} A reference to the request object. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[filter]{is_input} Boolean. True if this is an input filter. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[filter]{handler} String. The name of the Python handler for this filter as specified in the configuration. \emph{(Read-Only}) \end{memberdesc} \subsection{Server Object (mp_server)\obindex{server}\label{pyapi-mpserver}} The request object is a Python mapping to the Apache \code{request_rec} structure. The server structure describes the server (possibly virtual server) serving the request. \subsubsection{Server Methods\label{pyapi-mpsrv-meth}} \begin{methoddesc}[server]{get_config}{} Similar to \code{req.get_config()}, but returns a table object holding only the mod_python configuration defined at global scope within the Apache configuration. That is, outside of the context of any VirtualHost, Location, Directory or Files directives. \end{methoddesc} \begin{methoddesc}[server]{get_options}{} Similar to \code{req.get_options()}, but returns a table object holding only the mod_python options defined at global scope within the Apache configuration. That is, outside of the context of any VirtualHost, Location, Directory or Files directives. \end{methoddesc} \begin{methoddesc}[server]{log_error}{message\optional{, level}} An interface to the Apache \code{ap_log_error} function. \var{message} is a string with the error message, \var{level} is one of the following flags constants: \begin{verbatim} APLOG_EMERG APLOG_ALERT APLOG_CRIT APLOG_ERR APLOG_WARNING APLOG_NOTICE APLOG_INFO APLOG_DEBUG APLOG_NOERRNO \end{verbatim} If you need to write to log and do not have a reference to a server or request object, use the \function{apache.log_error} function. \end{methoddesc} \begin{methoddesc}[server]{register_cleanup}{request, callable\optional{, data}} Registers a cleanup. Very similar to \function{req.register_cleanup()}, except this cleanup will be executed at child termination time. This function requires the request object be supplied to infer the interpreter name. If you don't have any request object at hand, then you must use the \function{apache.register_cleanup} variant. \emph{Warning:} do not pass directly or indirectly a request object in the data parameter. Since the callable will be called at server shutdown time, the request object won't exist anymore and any manipulation of it in the callable will give undefined behaviour. \end{methoddesc} \subsubsection{Server Members\label{pyapi-mpsrv-mem}} \begin{memberdesc}[server]{defn_name} String. The name of the configuration file where the server definition was found. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{defn_line_number} Integer. Line number in the config file where the server definition is found. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{server_admin} Value of the \code{ServerAdmin} directive. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{server_hostname} Value of the \code{ServerName} directive. Same as CGI \envvar{SERVER_NAME}.\emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{names} Tuple. List of normal server names specified in the \code{ServerAlias} directive. This list does not include wildcarded names, which are listed separately in \code{wild_names}. \emph{(Read-Only)} \end{memberdesc} \begin{memberdesc}[server]{wild_names} Tuple. List of wildcarded server names specified in the \code{ServerAlias} directive. \emph{(Read-Only)} \end{memberdesc} \begin{memberdesc}[server]{port} Integer. TCP/IP port number. Same as CGI \envvar{SERVER_PORT}. \emph{This member appears to be 0 on Apache 2.0, look at req.connection.local_addr instead} \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{error_fname} The name of the error log file for this server, if any. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{loglevel} Integer. Logging level. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{is_virtual} Boolean. True if this is a virtual server. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{timeout} Integer. Value of the \code{Timeout} directive. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{keep_alive_timeout} Integer. Keepalive timeout. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{keep_alive_max} Maximum number of requests per keepalive. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{keep_alive} Use persistent connections? \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{path} String. Path for \code{ServerPath} \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{pathlen} Integer. Path length. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{limit_req_line} Integer. Limit on size of the HTTP request line. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{limit_req_fieldsize} Integer. Limit on size of any request header field. \emph{(Read-Only}) \end{memberdesc} \begin{memberdesc}[server]{limit_req_fields} Integer. Limit on number of request header fields. \emph{(Read-Only}) \end{memberdesc} \section{\module{util} -- Miscellaneous Utilities\label{pyapi-util}} \declaremodule[util]{extension}{util} \modulesynopsis{Miscellaneous Utilities} \moduleauthor{Gregory Trubetskoy}{grisha@apache.org} The \module{util} module provides a number of utilities handy to a web application developer similar to those in the standard library \module{cgi} module. The implementations in the \module{util} module are much more efficient because they call directly into Apache API's as opposed to using CGI which relies on the environment to pass information. The recommended way of using this module is: \begin{verbatim} from mod_python import util \end{verbatim} \begin{seealso} \seetitle[http://CGI-Spec.Golux.Com/] {Common Gateway Interface RFC Project Page} {for detailed information on the CGI specification} \end{seealso} \subsection{FieldStorage class\label{pyapi-util-fstor}} Access to form data is provided via the \class{FieldStorage} class. This class is similar to the standard library module \module{cgi} \class{FieldStorage}. \begin{classdesc}{FieldStorage}{req\optional{, keep_blank_values, strict_parsing, file_callback, field_callback}} This class provides uniform access to HTML form data submitted by the client. \var{req} is an instance of the mod_python request object. The optional argument \var{keep_blank_values} is a flag indicating whether blank values in URL encoded form data should be treated as blank strings. The default is false, which means that blank values are ignored as if they were not included. The optional argument \var{strict_parsing} is not yet implemented. The optional argument \var{file_callback} allows the application to override both file creation/deletion semantics and location. See \ref{pyapi-util-fstor-examples} ``FieldStorage Examples'' for additional information. \emph{New in version 3.2} The optional argument \var{field_callback} allows the application to override both the creation/deletion semantics and behaviour. \emph{New in version 3.2} During initialization, \class{FieldStorage} class reads all of the data provided by the client. Since all data provided by the client is consumed at this point, there should be no more than one \class{FieldStorage} class instantiated per single request, nor should you make any attempts to read client data before or after instantiating a \class{FieldStorage}. A suggested strategy for dealing with this is that any handler should first check for the existance of a \code{form} attribute within the request object. If this exists, it should be taken to be an existing instance of the \class{FieldStorage} class and that should be used. If the attribute does not exist and needs to be created, it should be cached as the \code{form} attribute of the request object so later handler code can use it. When the \class{FieldStorage} class instance is created, the data read from the client is then parsed into separate fields and packaged in \class{Field} objects, one per field. For HTML form inputs of type \code{file}, a temporary file is created that can later be accessed via the \member{file} attribute of a \class{Field} object. The \class{FieldStorage} class has a mapping object interface, i.e. it can be treated like a dictionary in most instances, but is not strictly compatible as is it missing some methods provided by dictionaries and some methods don't behave entirely like their counterparts, especially when there is more than one value associated with a form field. When used as a mapping, the keys are form input names, and the returned dictionary value can be: \begin{itemize} \item An instance of \class{StringField}, containing the form input value. This is only when there is a single value corresponding to the input name. \class{StringField} is a subclass of \class{str} which provides the additional \member{value} attribute for compatibility with standard library \module{cgi} module. \item An instance of a \class{Field} class, if the input is a file upload. \item A list of \class{StringField} and/or \class{Field} objects. This is when multiple values exist, such as for a \code{