This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
expression/src/core/main.py

797 lines
35 KiB
Python

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Expression
# By: Frederic Peters <fpeters@entrouvert.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
#
# Copyright (C) 2004 Entr'ouvert, Frederic Peters & Emmanuel Raviart
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""HTTP Server"""
import __builtin__
import base64
import Cookie
import errno
import gettext
import grp
import locale
import logging
from optparse import OptionParser
import os
import pwd
import re
import sys
import urllib
import libxml2
import expression
import configurations
import dataholders
import elements
import environs
import faults
import filesystems
import html
import http
import httpstatuses
import logs
import locations
import metadatas
import modules
import namespaces
import sessions
import stations
import strings
import stylesheets
import submissions
import things
import webdav
import xmlschemas
import xpaths
import xslt
def goDaemon(nochdir = 0, noclose = 0, user = None, group = None):
"""Run server as INIT daemon
See also http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
for another code to create a daemon.
"""
if user:
if user.isdigit():
user = int(user)
else:
try:
user = pwd.getpwnam(user)[2]
except KeyError:
user = None
if group:
if group.isdigit():
group = int(group)
else:
try:
group = grp.getgrnam(group)[2]
except KeyError:
group = None
if user and user != os.getuid():
try:
os.setuid(user)
except OSError:
logs.warning("Failed to setuid() to %s" % user)
if group and group != os.getgid():
try:
os.setgid(group)
except OSError:
logs.warning("Failed to setgid() to %s" % group)
if os.fork():
os._exit(0)
os.setsid()
if nochdir == 0:
os.chdir('/')
if noclose == 0:
fp = open('/dev/null', 'rw')
sys.stdin = sys.__stdin__ = fp
sys.stdout = sys.__stdout__ = fp
sys.stderr = sys.__stderr__ = fp
del fp
if os.fork():
os._exit(0)
class Application(object):
xpathContext = None
def handleHttpCommand(self, httpRequestHandler):
virtualHosts = environs.getVar("virtualHosts")
try:
requestedHostName = httpRequestHandler.headers["Host"].split(":")[0]
except KeyError:
requestedHostName = ''
for virtualHost in virtualHosts:
if virtualHost.getServerName() == requestedHostName:
break
else:
# handle serverAlias
for virtualHost in virtualHosts:
if requestedHostName in virtualHost.getServerAliases():
if not virtualHost.getPort() in (80, 443):
break # we only redirect on standard ports
httpRequestHandler.send_response(301, "Moved Permanently")
httpRequestHandler.send_header("Location",
environs.getVar("httpServer").uriScheme + '://' + \
virtualHost.getServerName() + httpRequestHandler.path)
httpRequestHandler.end_headers()
httpRequestHandler.wfile.write("Moved")
return
# nothing else, take the first one
virtualHost = virtualHosts[0]
hostName = virtualHost.getServerName() or httpRequestHandler.headers["Host"]
# Needed by talkback.
environs.setVar("virtualHost", virtualHost)
environs.push(
_level = "handleHttpCommand",
canUseCookie = False,
cookie = None,
currentStation = None,
currentDirectoryPath = None,
httpAuthenticationLogoutTrick = False,
httpQuery = None,
httpRequestHandler = httpRequestHandler,
httpScriptDirectoryPath = None,
languageSetInUrl = False,
readLanguages = None,
rootStation = None,
session = None,
submission = None,
testCookieSupport = False,
uriAuthority = hostName,
uriScheme = environs.getVar("httpServer").uriScheme,
user = None,
)
try:
splitedPath = httpRequestHandler.path.split("?")
httpPath = splitedPath[0]
while len(httpPath) > 1 and httpPath[-1] == "/":
httpPath = httpPath[:-1]
if not httpPath:
httpPath = "/"
if len(splitedPath) >= 2:
httpQuery = splitedPath[1]
if not httpQuery:
httpQuery = ""
else:
httpQuery = ""
environs.setVar("httpQuery", httpQuery)
httpScriptDirectoryPath = "/"
if httpScriptDirectoryPath == "/":
httpInternPath = httpPath
else:
httpInternPath = httpPath[len(httpScriptDirectoryPath):]
uriPathFragments = [urllib.unquote(name) for name in httpInternPath.split("/") if name]
inRawMode = False
if uriPathFragments and uriPathFragments[0] == "raw":
inRawMode = uriPathFragments[0]
uriPathFragments = uriPathFragments[1:]
if httpScriptDirectoryPath[-1] == "/":
httpScriptDirectoryPath = "%s%s" % (httpScriptDirectoryPath, inRawMode)
else:
httpScriptDirectoryPath = "%s/%s" % (httpScriptDirectoryPath, inRawMode)
environs.setVar("httpScriptDirectoryPath", httpScriptDirectoryPath)
# Setup root data holder.
documentRootAbsolutePath = virtualHost.getConfigAbsolutePath("yep:documentRoot")
fileSystem = filesystems.PartialFileSystem(documentRootAbsolutePath)
uriPathFragment = environs.getVar("httpScriptDirectoryPath")[1:]
rootDataHolder = dataholders.DataHolder(
pathFragment = documentRootAbsolutePath,
uriPathFragment = uriPathFragment,
uriScheme = environs.getVar("uriScheme"),
uriAuthority = environs.getVar("uriAuthority"),
isRootElder = True,
containedFileSystem = fileSystem)
environs.setVar("rootStation", rootDataHolder)
environs.setVar("currentStation", rootDataHolder)
# Throw away bad referers
bad_referrers = rootDataHolder.getConfigList("yep:badReferrers/yep:host", default = [])
referer = httpRequestHandler.headers.get("Referer", "")
if referer:
for bad in bad_referrers:
if bad == referer or re.findall(bad, referer):
httpRequestHandler.headers["Referer"] = "BAD"
return httpRequestHandler.outputErrorAccessForbidden("")
# Get query, headers and form variables in a submission object.
submission = submissions.readSubmission(httpRequestHandler)
environs.setVar("submission", submission)
session = None
sessionToken = None
user = None
# Handle X509 certificate authentication.
if environs.getVar("peerCertificate", default = None):
cert = environs.getVar("peerCertificate")
serial = "%x" % int(cert.get_serial_number())
from expression.modules.x509accounts import X509Account
try:
accountHolder = rootDataHolder.walkToLocation("/accounts/x509/%s" % serial)
except faults.PathNotFound:
logs.info("Wrong serial number = %s" % serial)
accountHolder = None
if accountHolder:
account = accountHolder.getRootElement()
if not isinstance(account, X509Account):
logs.info("Bad X509 account file (%r)" % account)
return httpRequestHandler.outputErrorUnauthorized(httpPath)
user = account.getUser()
if user:
sessionToken = user.getSessionToken()
else:
logs.warning('Account "%s" without user.' % account)
return httpRequestHandler.outputErrorUnauthorized(httpPath)
if sessionToken:
session = sessions.retrieveSession(sessionToken)
if session is None:
sessionToken = None
user.deleteSessionToken()
# Don't call user.getDocument().save() now, because the session
# will be retrieved (from cookie or sessionToken submission field)
# or created. So user/@sessionToken will be updated.
else:
session.setPublishToken("true")
# Handle HTTP authentication.
authorization = httpRequestHandler.headers.get("authorization")
if submission.getField("_action") == "login" and not authorization \
and rootDataHolder.getConfigBoolean("yep:useHttpAuthentication",
default = False):
# Ask for HTTP authentication.
return httpRequestHandler.outputErrorUnauthorized(httpPath)
if submission.getField("_action") == "logout" and authorization:
# Since HTTP authentication provides no way to logout, we send a status
# Unauthorized to force the user to press the cancel button. But instead of
# sending an error page immediately, we send the real page, so the user will see
# the page instead of an error message.
authorization = None
environs.setVar("httpAuthenticationLogoutTrick", True)
if authorization:
try:
authenticationScheme, credentials = authorization.split(None, 1)
except ValueError:
return httpRequestHandler.outputErrorUnauthorized(httpPath)
authenticationScheme = authenticationScheme.lower()
if authenticationScheme == "basic":
loginAndPassword = base64.decodestring(credentials)
try:
login, password = loginAndPassword.split(":", 1)
except:
login = loginAndPassword
password = ""
logs.debug('Basic authentication: login = "%s" / password = "%s"' % (
login, password))
if password:
import expression.modules.passwordaccounts as passwordaccounts
try:
accountHolder = rootDataHolder.walkToLocation(
"/accounts/passwords/%s" % strings.simplify(login))
except faults.PathNotFound:
logs.info("Wrong login = %s" % login)
return httpRequestHandler.outputErrorUnauthorized(httpPath)
account = accountHolder.getRootElement()
if not isinstance(account, passwordaccounts.PasswordAccount):
logs.info("Bad password account file (%r)" % account)
return httpRequestHandler.outputErrorUnauthorized(httpPath)
if password != account.password:
logs.debug("Wrong password = %s (instead of %s)" % (
password, account.password))
return httpRequestHandler.outputErrorUnauthorized(httpPath)
user = account.getUser()
if user:
sessionToken = user.getSessionToken()
else:
logs.warning('Account "%s" without user.' % account)
return httpRequestHandler.outputErrorUnauthorized(httpPath)
if sessionToken:
session = sessions.retrieveSession(sessionToken)
if session is None:
sessionToken = None
user.deleteSessionToken()
# Don't call user.getDocument().save() now, because the session
# will be retrieved (from cookie or sessionToken submission field)
# or created. So user/@sessionToken will be updated.
else:
# For security reasons, we want to minimize the publication of
# session token (it is better not to store it in a cookie or in
# URLs).
if session.publishToken:
del session.publishToken
elif login:
# No password was given. Assume login contains a session token.
# TODO: sanity chek on login
session = sessions.retrieveSession(login)
if session is not None:
account = session.getAccount()
if account is not None:
user = account.getUser()
if user is not None \
and user.getSessionToken() != session.getToken():
# Sanity check.
user.setSessionToken(session.getToken())
user.getDocument().save()
else:
logs.info("Unknown authentication scheme = %s" % authenticationScheme)
return httpRequestHandler.outputErrorUnauthorized(httpPath)
# Handle use of cookies, session and user.
cookie = None
cookieContent = {}
if httpRequestHandler.headers.has_key("Cookie"):
logs.debug("Cookie received:")
cookie = Cookie.SimpleCookie(
httpRequestHandler.headers["Cookie"])
for k, v in cookie.items():
cookieContent[k] = v.value
logs.debug(" %s = %s" % (k, cookieContent[k]))
environs.setVar("cookie", cookie)
sessionToken = None
sessionTokenInCookie = False
if submission.hasField("sessionToken"):
sessionToken = submission.getField("sessionToken")
if not sessionToken:
sessionToken = None
if session is not None and sessionToken != session.token:
sessionToken = None
if cookieContent.has_key("sessionToken"):
cookieSessionToken = cookieContent["sessionToken"]
if cookieSessionToken:
if session is None or cookieSessionToken == session.token:
if sessionToken is None:
sessionToken = cookieSessionToken
if cookieSessionToken == sessionToken:
sessionTokenInCookie = True
canUseCookie = True
if session is None and sessionToken is not None:
session = sessions.retrieveSession(sessionToken)
if session is None:
sessionToken = None
sessionTokenInCookie = False
else:
if user is None:
# import expression.modules.passwordaccounts as passwordaccounts
account = session.getAccount(acceptOnlyAccount = False)
if account is not None:
user = account.getUser()
if user is not None and user.getSessionToken() != sessionToken:
# Sanity check.
user.setSessionToken(session.getToken())
user.getDocument().save()
else:
# The user has been authenticated (using HTTP authentication), but the
# associated session didn't exist (or was too old, or...). So, update
# its sessionToken.
user.setSessionToken(session.getToken())
user.getDocument().save()
# For security reasons, we want to minimize the publication of session
# token (it is better not to store it in a cookie or in URLs).
if session.publishToken:
del session.publishToken
if session is None and user is not None:
# The user has been authenticated (using HTTP authentication), but the session
# doesn't exist yet (or was too old, or...). Create a new session.
session = sessions.getOrCreateSession()
# For security reasons, we want to minimize the publication of session
# token (it is better not to store it in a cookie or in URLs).
# session.publishToken = False # False is the default value.
session.setAccountAbsolutePath(account.getAbsolutePath())
user.setSessionToken(session.getToken())
user.getDocument().save()
if user is not None:
environs.setVar("user", user)
logs.debug("User: %s" % user.simpleLabel)
if session is not None:
if not sessionTokenInCookie:
# The sessionToken is valid but is not stored in the cookie. So, don't try to
# use cookie.
canUseCookie = False
environs.setVar("session", session)
logs.debug("Session: %s" % session.token)
if canUseCookie:
environs.setVar("canUseCookie", canUseCookie)
# Look for the right languages to use for HTTP answer.
languages = []
if user is not None:
userLanguage = user.getLanguage()
if userLanguage is not None:
languages = [userLanguage]
if not languages \
and httpRequestHandler.headers.has_key("Accept-Language"):
languages = [
language.strip()[:2]
for language in httpRequestHandler.headers[
"Accept-Language"].split(",")
if language.strip()]
virtualHostLanguage = virtualHost.getConfigString("yep:language", default = "en")
if virtualHostLanguage not in languages:
languages.append(virtualHostLanguage)
environs.setVar("readLanguages", languages)
self.setGettextLanguage()
try:
try:
if not rootDataHolder.checkAccess(
uriPathFragments, httpRequestHandler.command):
raise faults.PathNotFound("/".join(uriPathFragments))
if inRawMode:
if not rootDataHolder.isContentAccessAuthorized(inRawMode, None):
raise faults.PathUnauthorized("/".join([inRawMode] + uriPathFragments))
rootDataHolder._inRawMode = True
rootDataHolder.walk(uriPathFragments, httpRequestHandler.command)
except faults.BadRequest, fault:
if environs.getVar("debug"):
logs.exception(str(fault))
httpRequestHandler.outputErrorBadRequest(fault.reason, station = fault.station)
except faults.PathForbidden, fault:
if environs.getVar("debug"):
logs.exception(str(fault))
httpRequestHandler.outputErrorAccessForbidden(
fault.path, station = fault.station)
except faults.PathNotFound, fault:
if environs.getVar("debug"):
logs.exception(str(fault))
httpRequestHandler.outputErrorNotFound(fault.path, station = fault.station)
except faults.PathUnauthorized, fault:
if environs.getVar("debug"):
logs.exception(str(fault))
# Output an Unauthorized status only when the user is not yet logged in,
# because we assume each user has only one account.
if environs.getVar("user") is None:
httpRequestHandler.outputErrorUnauthorized(
fault.path, station = fault.station)
else:
httpRequestHandler.outputErrorAccessForbidden(
fault.path, station = fault.station)
except:
httpRequestHandler.outputUnknownException()
finally:
session = environs.getVar("session")
if session is not None:
sessionDocument = session.getDocument()
if sessionDocument.isDirty:
sessionDocument.save()
finally:
environs.pull(_level = "handleHttpCommand")
def launch(self):
# We need to use only one libxml2.xpathContext, because the libxml2
# Python binding limits the number of registered XPath functions to
# 10, even if they are registered in different contexts.
#
# Other problem: A segmentation fault occurs when setContextDoc is
# called and the previous context doc was None. So we can't do:
# self.xpathContext = libxml2.xpathContext()
dummyDoc = libxml2.newDoc("1.0")
dummyDoc.newTextChild(None, "dummy", None)
self.xpathContext = dummyDoc.xpathNewContext()
for ns in namespaces.nsList:
self.xpathContext.xpathRegisterNs(ns.name, ns.uri)
xpaths.registerFunctions(self.xpathContext)
xslt.registerFunctions()
def setGettextLanguage(self):
virtualHost = environs.getVar("virtualHost")
configuration = environs.getVar("configuration")
readLanguages = environs.getVar("readLanguages")
domains = virtualHost.getDomains() + [expression.applicationName]
locales = configuration.getLocales()
localesPath = configuration.getLocalesPath() or "/usr/share/locale"
language = readLanguages[0]
for l in readLanguages:
if l in locales:
language = l
break
try:
locale.setlocale(locale.LC_COLLATE, (language, None))
except locale.Error:
locale.setlocale(locale.LC_COLLATE, "C")
translation = gettext.NullTranslations()
for domain in domains:
try:
domainTranslation = gettext.translation(
domain, localesPath, [language])
logs.debug("using translations in language %s for domain %s" % (language, domain))
except IOError:
continue
if not hasattr(domainTranslation, "_catalog"):
continue
if translation.__class__.__name__ == "NullTranslations":
translation = domainTranslation
continue
translation._catalog.update(domainTranslation._catalog)
__builtin__.__dict__["_"] = translation.gettext
def stop(self):
xslt.unregisterFunctions()
xpaths.unregisterFunctions(self.xpathContext)
self.xpathContext.xpathFreeContext()
del self.xpathContext
# Main.
def main():
parser = OptionParser(version = "%prog 0.1")
parser.add_option("-f",
dest = "configurationFilePath",
help = "specify an alternate configuration file",
metavar = "FILE",
default = "/etc/expression/config.xml")
parser.add_option("-l",
dest = "logLevel",
help = "specify log level (debug, info, warning, error, critical)",
metavar = "LEVEL",
default = "error")
parser.add_option("--debug",
dest = "debugMode",
action = "store_true",
default = False,
help = "set debug mode")
parser.add_option("-F",
dest = "daemonMode",
action = "store_false",
default = True,
help = "run main process in foreground, for process supervisors")
parser.add_option("--no-email",
dest = "sendEmails",
action = "store_false",
default = True,
help = "don't send emails (they are logged instead)")
(options, args) = parser.parse_args()
if options.logLevel.upper() not in logging._levelNames.keys():
raise Exception("Unknown log level (%s)" % options.logLevel)
# Configure libxml2 to be thread safe.
libxml2.initParser()
# One more libxml2 idiosyncrasy: After having RTFM for function xmlKeepBlanksDefault, it
# seems that it is better to never call it, because, calling it causes XMLSec1 and/or Lasso to
# fail when checking signatures. And we haven't found a clean way for Lasso to save and restore
# the following variables when dumping XML.
# By default:
# xmlKeepBlanksDefaultValue = 1
# xmlIndentTreeOutput = 1
# After calling libxml2.keepBlanksDefault(0):
# xmlKeepBlanksDefaultValue = 0
# xmlIndentTreeOutput = 1
# After calling libxml2.keepBlanksDefault(1):
# xmlKeepBlanksDefaultValue = 1
# xmlIndentTreeOutput = 0
#
# libxml2.keepBlanksDefault(0)
environs.push(
_level = "__main__",
application = None,
configuration = None,
debug = options.debugMode,
httpPort = None,
httpServer = None,
httpsPort = None,
logger = None,
sendEmails = options.sendEmails,
virtualHosts = None,
)
try:
application = Application()
application.launch()
environs.setVar("application", application)
# Build configuration from configuration file.
configurationAbsolutePath = os.path.abspath(options.configurationFilePath)
fileSystem = filesystems.PartialFileSystem(configurationAbsolutePath)
try:
configurationHolder = dataholders.DataHolder(
pathFragment = configurationAbsolutePath, mimeType = "text/xml",
isRootElder = True, containedFileSystem = fileSystem)
except IOError, error:
if error.errno == errno.ENOENT:
print >> sys.stderr, "No such configuration file:", options.configurationFilePath
sys.exit(1)
raise
configuration = configurationHolder.getRootElement()
if not isinstance(configuration, configurations.Configuration):
print >> sys.stderr, "Bad configuration file %s; aborting" % configuration
sys.exit(1)
environs.setVar("configuration", configuration)
# Configure root logger.
logger = logging.getLogger()
if options.debugMode and not options.daemonMode:
handler = logging.StreamHandler(sys.stdout)
else:
handler = logging.FileHandler(configuration.getConfigAbsolutePath(
"yep:logFilePath", default = "/dev/null"))
formatter = logging.Formatter('%(asctime)s %(levelname)-9s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging._levelNames[options.logLevel.upper()])
environs.setVar("logger", logger)
sys.path.extend(configuration.getPythonAbsolutePaths())
sys.path.extend(
['/usr/local/lib/expression/modules',
'/usr/lib/expression/modules'])
for moduleName in configuration.getPythonModuleNames():
try:
module = __import__(moduleName)
except ImportError:
logs.error("Failed to load module %s; skipping" % moduleName)
raise
for namespace in configuration.evaluateXpath("yep:namespace"):
name, uri = namespace.prop("name"), namespace.prop("uri")
if not namespaces.getUri(name):
ns = namespaces.Namespace(name, uri)
application.xpathContext.xpathRegisterNs(name, uri)
allVirtualHosts = [
virtualHost for virtualHost in configuration.getVirtualHosts()]
# Needed because virtualHosts is not a list
# TODO but it should be made Iterable
if not allVirtualHosts:
logs.critical("No virtual host defined; aborting")
sys.exit(1)
virtualHostsByIpAddressAndPortCouple = {}
accessLogFiles = {}
for virtualHost in allVirtualHosts:
if not virtualHost.getPort():
logs.warning("Virtual host without port; skipping")
continue
if not virtualHost.getConfigBaseRelativePath("yep:documentRoot", default = None):
logs.warning("Virtual host without document root; skipping.")
continue
ipAddressAndPort = (virtualHost.getIpAddress(), virtualHost.getPort())
if not virtualHostsByIpAddressAndPortCouple.has_key(ipAddressAndPort):
virtualHostsByIpAddressAndPortCouple[ipAddressAndPort] = []
virtualHostsByIpAddressAndPortCouple[ipAddressAndPort].append(virtualHost)
accessLogFilePath = virtualHost.getConfigAbsolutePath("yep:accessLogFilePath",
default = None)
if not accessLogFilePath:
accessLogFilePath = configuration.getConfigAbsolutePath("yep:accessLogFilePath",
default = None)
if accessLogFilePath:
if not accessLogFiles.has_key(accessLogFilePath):
fd = open(accessLogFilePath, "a", 1)
accessLogFiles[accessLogFilePath] = fd
virtualHost.accessLogFile = accessLogFiles[accessLogFilePath]
if virtualHost.isSsl:
assert virtualHost.brotherVirtualHost is None
for nonSslVirtualHost in allVirtualHosts:
if nonSslVirtualHost == virtualHost:
continue
if nonSslVirtualHost.isSsl:
continue
if nonSslVirtualHost.getIpAddress() == virtualHost.getIpAddress() \
and nonSslVirtualHost.getServerName() == virtualHost.getServerName():
assert nonSslVirtualHost.brotherVirtualHost is None
nonSslVirtualHost.brotherVirtualHost = virtualHost
virtualHost.brotherVirtualHost = nonSslVirtualHost
break
if not virtualHostsByIpAddressAndPortCouple:
logs.critical("No correct virtual host defined; aborting")
sys.exit(1)
if options.daemonMode:
goDaemon(
nochdir = 1, user = configuration.getConfigString("yep:user", default = None),
group = configuration.getConfigString("yep:group", default = None))
httpPort = None
httpsPort = None
for serverIpAddressAndPortCouple, virtualHosts \
in virtualHostsByIpAddressAndPortCouple.items():
if os.fork():
continue
httpServerIpAddressAndPortCouple = serverIpAddressAndPortCouple
virtualHost = virtualHosts[0]
if virtualHost.isSsl:
HttpRequestHandler = http.HttpsRequestHandler
httpServer = http.HttpsServer(
httpServerIpAddressAndPortCouple, HttpRequestHandler,
virtualHost.getConfigAbsolutePath("yep:sslCertificateKeyFile"),
# Server private key
virtualHost.getConfigAbsolutePath("yep:sslCertificateFile"),
# Server certificate
virtualHost.getConfigAbsolutePath("yep:sslCACertificateFile", None),
# Clients certification authority certificate
virtualHost.getConfigAbsolutePath("yep:sslCertificateChainFile", None),
# see mod_ssl, ssl_engine_init.c, line 852
virtualHost.getConfigString("yep:sslVerifyClient", None),
# http://www.modssl.org/docs/2.1/ssl_reference.html#ToC13
)
httpsPort = httpServerIpAddressAndPortCouple[1]
else:
HttpRequestHandler = http.HttpRequestHandler
httpServer = http.HttpServer(
httpServerIpAddressAndPortCouple, HttpRequestHandler)
httpPort = httpServerIpAddressAndPortCouple[1],
break
else:
pidFileAbsolutePath = configuration.getConfigAbsolutePath(
"yep:pidFilePath", default = None)
if pidFileAbsolutePath is None:
logs.info("No PID file specified; PID is %s" % os.getpid())
else:
pidFile = file(pidFileAbsolutePath, "w")
pidFile.write(str(os.getpid()))
pidFile.close()
while 1:
try:
os.wait()
except KeyboardInterrupt:
logger.info("Exiting on KeyboardInterrupt")
break
os._exit(0)
environs.setVar("httpServer", httpServer)
environs.setVar("httpPort", httpPort)
environs.setVar("httpsPort", httpsPort)
environs.setVar("virtualHosts", virtualHosts)
HttpRequestHandler.application = application
HttpRequestHandler.baseEnviron = environs.get()
httpServer.application = application
if isinstance(httpServer, http.HttpsServer):
logger.info("Serving HTTPS on %s port %s..." % httpServer.socket.getsockname())
else:
logger.info("Serving HTTP on %s port %s..." % httpServer.socket.getsockname())
try:
httpServer.serve_forever()
except KeyboardInterrupt:
pass
application.stop()
del HttpRequestHandler.baseEnviron
finally:
environs.pull(_level = "__main__")