Commit 0d189dca authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki Committed by Arnaud Fontaine

WIP: remove ZServer dependency.

parent 6b712031
......@@ -106,14 +106,12 @@ instancehome = getConfiguration().instancehome
if instancehome is not None:
log_directory = os.path.join(instancehome, 'log')
if os.path.isdir(log_directory):
from Signals import Signals
from ZConfig.components.logger.loghandler import FileHandler
log_file_handler = FileHandler(os.path.join(log_directory, 'CMFActivity.log'))
# Default zope log format string borrowed from
# ZConfig/components/logger/factory.xml, but without the extra "------"
# line separating entries.
log_file_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s", "%Y-%m-%dT%H:%M:%S"))
Signals.registerZopeSignals([log_file_handler])
activity_logger.addHandler(log_file_handler)
activity_logger.propagate = 0
......
......@@ -114,7 +114,3 @@ def match(self, request):
return 1
else:
return 0
if six.PY2:
from ZServer.HTTPServer import zhttp_handler
zhttp_handler.match = match
......@@ -61,9 +61,6 @@ from Products.ERP5Type.patches import PersistentMapping
from Products.ERP5Type.patches import DateTimePatch
from Products.ERP5Type.patches import PythonScript
from Products.ERP5Type.patches import MailHost
if six.PY2:
# No more ZServer
from Products.ERP5Type.patches import http_server
from Products.ERP5Type.patches import memcache_client
from Products.ERP5Type.patches import StateChangeInfoPatch
from Products.ERP5Type.patches import transforms
......@@ -94,9 +91,6 @@ from Products.ERP5Type.patches import OFSFile
from Products.ERP5Type.patches import ZSQLMethod
from Products.ERP5Type.patches import MimetypesRegistry
from Products.ERP5Type.patches import users
if six.PY2:
# No ZServer
from Products.ERP5Type.patches import Publish
from Products.ERP5Type.patches import WSGITask
if six.PY2:
# XXX-zope4py3: urllib2 removed (see future/backports/urllib/request.py)
......
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
from Products.ERP5Type.Timeout import getPublisherDeadlineValue
try:
from ZServer.ZPublisher import Publish
from ZServer.ZPublisher.Publish import (
# Produced using:
# dis.dis(
# compile(open(<this_file>, 'r').read(), 'foo', 'exec').co_consts[
# <index of publish code object in co_consts>
# ]
# )
# and checking all uniques LOAD_GLOBAL names, excluding builtins and
# getPublisherDeadlineValue, and including publish parameter default
# values.
ISkinnable,
IBrowserPage,
recordMetaData,
pubevents,
Redirect,
Retry,
call_object,
dont_publish_class,
endInteraction,
get_module_info,
mapply,
missing_name,
newInteraction,
notify,
publish,
setDefaultSkin,
sys,
urlparse,
noSecurityManager,
)
def publish(request, module_name, after_list, debug=0,
# Optimize:
call_object=call_object,
missing_name=missing_name,
dont_publish_class=dont_publish_class,
mapply=mapply,
):
(bobo_before, bobo_after, object, realm, debug_mode, err_hook,
validated_hook, transactions_manager)= get_module_info(module_name)
parents=None
response=None
try:
with getPublisherDeadlineValue(request):
notify(pubevents.PubStart(request))
# TODO pass request here once BaseRequest implements IParticipation
newInteraction()
request.processInputs()
request_get = request.get
response = request.response
# First check for "cancel" redirect:
if request_get('SUBMIT', '').strip().lower() == 'cancel':
cancel = request_get('CANCEL_ACTION', '')
if cancel:
# Relative URLs aren't part of the spec, but are accepted by
# some browsers.
for part, base in zip(urlparse(cancel)[:3],
urlparse(request['BASE1'])[:3]):
if not part:
continue
if not part.startswith(base):
cancel = ''
break
if cancel:
raise Redirect(cancel)
after_list[0] = bobo_after
if debug_mode:
response.debug_mode = debug_mode
if realm and not request.get('REMOTE_USER', None):
response.realm = realm
noSecurityManager()
if bobo_before is not None:
bobo_before()
# Get the path list.
# According to RFC1738 a trailing space in the path is valid.
path = request_get('PATH_INFO')
request['PARENTS'] = parents = [object]
if transactions_manager:
transactions_manager.begin()
object = request.traverse(path, validated_hook=validated_hook)
if IBrowserPage.providedBy(object):
request.postProcessInputs()
notify(pubevents.PubAfterTraversal(request))
if transactions_manager:
recordMetaData(object, request)
result = mapply(object, request.args, request,
call_object, 1,
missing_name,
dont_publish_class,
request, bind=1)
if result is not response:
response.setBody(result)
notify(pubevents.PubBeforeCommit(request))
if transactions_manager:
transactions_manager.commit()
notify(pubevents.PubSuccess(request))
endInteraction()
return response
except:
# save in order to give 'PubFailure' the original exception info
exc_info = sys.exc_info()
# DM: provide nicer error message for FTP
sm = None
if response is not None:
sm = getattr(response, "setMessage", None)
if sm is not None:
from asyncore import compact_traceback
cl, val = sys.exc_info()[:2]
sm('%s: %s %s' % (
getattr(cl, '__name__', cl), val,
debug_mode and compact_traceback()[-1] or ''))
# debug is just used by tests (has nothing to do with debug_mode!)
if not debug and err_hook is not None:
retry = False
if parents:
parents = parents[0]
try:
try:
with getPublisherDeadlineValue(request):
return err_hook(parents, request,
sys.exc_info()[0],
sys.exc_info()[1],
sys.exc_info()[2],
)
except Retry:
if not request.supports_retry():
with getPublisherDeadlineValue(request):
return err_hook(parents, request,
sys.exc_info()[0],
sys.exc_info()[1],
sys.exc_info()[2],
)
retry = True
finally:
# Note: 'abort's can fail.
# Nevertheless, we want end request handling.
try:
try:
notify(pubevents.PubBeforeAbort(
request, exc_info, retry))
finally:
if transactions_manager:
transactions_manager.abort()
finally:
endInteraction()
notify(pubevents.PubFailure(request, exc_info, retry))
# Only reachable if Retry is raised and request supports retry.
newrequest = request.retry()
request.close() # Free resources held by the request.
# Set the default layer/skin on the newly generated request
if ISkinnable.providedBy(newrequest):
setDefaultSkin(newrequest)
try:
return publish(newrequest, module_name, after_list, debug)
finally:
newrequest.close()
else:
# Note: 'abort's can fail.
# Nevertheless, we want end request handling.
try:
try:
notify(pubevents.PubBeforeAbort(request, exc_info, False))
finally:
if transactions_manager:
transactions_manager.abort()
finally:
endInteraction()
notify(pubevents.PubFailure(request, exc_info, False))
raise
Publish.publish = publish
except ImportError: # BBB Zope2
from ZPublisher import Publish, pubevents
from ZPublisher.Publish import (
# Produced using:
# dis.dis(
# compile(open(<this_file>, 'r').read(), 'foo', 'exec').co_consts[
# <index of publish code object in co_consts>
# ]
# )
# and checking all uniques LOAD_GLOBAL names, excluding builtins and
# getPublisherDeadlineValue, and including publish parameter default
# values.
ISkinnable,
PubAfterTraversal,
PubBeforeAbort,
PubBeforeCommit,
PubFailure,
PubStart,
PubSuccess,
Redirect,
Retry,
call_object,
dont_publish_class,
endInteraction,
get_module_info,
mapply,
missing_name,
newInteraction,
notify,
publish,
setDefaultSkin,
sys,
urlparse,
)
def publish(request, module_name, after_list, debug=0,
# Optimize:
call_object=call_object,
missing_name=missing_name,
dont_publish_class=dont_publish_class,
mapply=mapply,
):
(bobo_before, bobo_after, object, realm, debug_mode, err_hook,
validated_hook, transactions_manager)= get_module_info(module_name)
parents=None
response=None
try:
with getPublisherDeadlineValue(request):
notify(PubStart(request))
# TODO pass request here once BaseRequest implements IParticipation
newInteraction()
request.processInputs()
request_get=request.get
response=request.response
# First check for "cancel" redirect:
if request_get('SUBMIT', '').strip().lower() == 'cancel':
cancel = request_get('CANCEL_ACTION', '')
if cancel:
# Relative URLs aren't part of the spec, but are accepted by
# some browsers.
for part, base in zip(urlparse(cancel)[:3],
urlparse(request['BASE1'])[:3]):
if not part:
continue
if not part.startswith(base):
cancel = ''
break
if cancel:
raise Redirect(cancel)
after_list[0]=bobo_after
if debug_mode:
response.debug_mode=debug_mode
if realm and not request.get('REMOTE_USER',None):
response.realm=realm
if bobo_before is not None:
bobo_before()
# Get the path list.
# According to RFC1738 a trailing space in the path is valid.
path=request_get('PATH_INFO')
request['PARENTS']=parents=[object]
if transactions_manager:
transactions_manager.begin()
object=request.traverse(path, validated_hook=validated_hook)
notify(PubAfterTraversal(request))
if transactions_manager:
transactions_manager.recordMetaData(object, request)
result=mapply(object, request.args, request,
call_object,1,
missing_name,
dont_publish_class,
request, bind=1)
if result is not response:
response.setBody(result)
notify(PubBeforeCommit(request))
if transactions_manager:
transactions_manager.commit()
endInteraction()
notify(PubSuccess(request))
return response
except:
# save in order to give 'PubFailure' the original exception info
exc_info = sys.exc_info()
# DM: provide nicer error message for FTP
sm = None
if response is not None:
sm = getattr(response, "setMessage", None)
if sm is not None:
from asyncore import compact_traceback
cl,val= sys.exc_info()[:2]
sm('%s: %s %s' % (
getattr(cl,'__name__',cl), val,
debug_mode and compact_traceback()[-1] or ''))
# debug is just used by tests (has nothing to do with debug_mode!)
if not debug and err_hook is not None:
retry = False
if parents:
parents=parents[0]
try:
try:
with getPublisherDeadlineValue(request):
return err_hook(parents, request,
sys.exc_info()[0],
sys.exc_info()[1],
sys.exc_info()[2],
)
except Retry:
if not request.supports_retry():
with getPublisherDeadlineValue(request):
return err_hook(parents, request,
sys.exc_info()[0],
sys.exc_info()[1],
sys.exc_info()[2],
)
retry = True
finally:
# Note: 'abort's can fail. Nevertheless, we want end request handling
try:
try:
notify(PubBeforeAbort(request, exc_info, retry))
finally:
if transactions_manager:
transactions_manager.abort()
finally:
endInteraction()
notify(PubFailure(request, exc_info, retry))
# Only reachable if Retry is raised and request supports retry.
newrequest=request.retry()
request.close() # Free resources held by the request.
# Set the default layer/skin on the newly generated request
if ISkinnable.providedBy(newrequest):
setDefaultSkin(newrequest)
try:
return publish(newrequest, module_name, after_list, debug)
finally:
newrequest.close()
else:
# Note: 'abort's can fail. Nevertheless, we want end request handling
try:
try:
notify(PubBeforeAbort(request, exc_info, False))
finally:
if transactions_manager:
transactions_manager.abort()
finally:
endInteraction()
notify(PubFailure(request, exc_info, False))
raise
Publish.publish = publish
# This code is taken from the medusa in zope 2.8.
#
# The license term should be this one:
#
# Medusa is Copyright 1996-2000, Sam Rushing &lt;rushing@nightmare.com&gt;
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of Sam
# Rushing not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
# Author: Sam Rushing <rushing@nightmare.com>
# Copyright 1996-2000 by Sam Rushing
# All Rights Reserved.
from ZServer.medusa.http_server import http_request
import ZPublisher.HTTPRequest
import string
import base64
import time
from six.moves.urllib.parse import quote
def log (self, bytes):
addr = self.channel.addr[0]
# Frontend-facing proxy is responsible for sanitising
# HTTP_X_FORWARDED_FOR, and only trusted accesses should bypass
# that proxy. So trust first entry.
#
# <patch>
if ZPublisher.HTTPRequest.trusted_proxies == ('0.0.0.0',): # Magic value to enable this functionality
forwarded_for = (self.get_header('x-forwarded-for') or '').split(',', 1)[0].strip()
if forwarded_for:
addr = forwarded_for
# </patch>
user_agent=self.get_header('user-agent')
if not user_agent: user_agent=''
referer=self.get_header('referer')
if not referer: referer=''
auth=self.get_header('Authorization')
name='Anonymous'
if auth is not None:
if string.lower(auth[:6]) == 'basic ':
try: decoded=base64.decodestring(auth[6:])
except base64.binascii.Error: decoded=''
t = string.split(decoded, ':', 1)
if len(t) < 2:
name = 'Unknown (bad auth string)'
else:
name = t[0]
# Originally, an unquoted request string was logged, but
# it only confuses log analysis programs! Note that Apache
# HTTP Server never unquote URIs in the access log.
t = self.request.split(' ')
quoted_request = '%s %s %s' % (t[0], quote(' '.join(t[1:-1])), t[-1])
self.channel.server.logger.log (
# <patch>
addr,
# </patch>
'- %s [%s] "%s" %d %d "%s" "%s"\n' % (
name,
self.log_date_string (time.time()),
# <patch>
quoted_request,
# </patch>
self.reply_code,
bytes,
referer,
user_agent
)
)
http_request.log = log
......@@ -3,7 +3,6 @@ import errno, logging, os, socket, time
import itertools
from threading import Thread
from UserDict import IterableUserDict
import Lifetime
import transaction
from Testing import ZopeTestCase
from ZODB.POSException import ConflictError
......@@ -140,21 +139,13 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
"""
_server_address = None # (host, port) of the http server if it was started, None otherwise
@staticmethod
def asyncore_loop():
try:
Lifetime.lifetime_loop()
except KeyboardInterrupt:
pass
Lifetime.graceful_shutdown_loop()
def startZServer(self, verbose=False):
"""Start HTTP ZServer in background"""
if self._server_address is None:
from Products.ERP5Type.tests.runUnitTest import log_directory
log = os.path.join(log_directory, "Z2.log")
message = "Running %s server at %s:%s\n"
if int(os.environ.get('erp5_wsgi', 0)):
if True:
from Products.ERP5.bin.zopewsgi import app_wrapper, createServer
sockets = []
server_type = 'HTTP'
......@@ -196,23 +187,6 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
t = Thread(target=hs.run)
t.setDaemon(1)
t.start()
else:
_print = lambda hs: verbose and ZopeTestCase._print(
message % (hs.server_protocol, hs.server_name, hs.server_port))
try:
hs = createZServer(log)
except RuntimeError as e:
ZopeTestCase._print(str(e))
else:
ProcessingNodeTestCase._server_address = hs.server_name, hs.server_port
_print(hs)
try:
_print(createZServer(log, zserver_type='webdav'))
except RuntimeError as e:
ZopeTestCase._print('Could not start webdav zserver: %s\n' % e)
t = Thread(target=Lifetime.loop)
t.setDaemon(1)
t.start()
from Products.CMFActivity import ActivityTool
# Reset, in case that getServerAddress was already called,
# in which case, the value was ('', '')
......@@ -305,9 +279,6 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
ZopeTestCase._print(' %i' % message_count)
old_message_count = message_count
portal_activities.process_timer(None, None)
if Lifetime._shutdown_phase:
# XXX CMFActivity contains bare excepts
raise KeyboardInterrupt
message_list = getMessageList()
message_count = len(message_list)
if time.time() >= deadline or message_count and any(x.processing_node == -2
......@@ -375,7 +346,7 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
def processing_node(self):
"""Main loop for nodes that process activities"""
try:
while not Lifetime._shutdown_phase:
while True:
time.sleep(.3)
transaction.begin()
try:
......@@ -398,7 +369,7 @@ class ProcessingNodeTestCase(ZopeTestCase.TestCase):
timerserver_thread = None
try:
while not Lifetime._shutdown_phase:
while True:
time.sleep(.3)
transaction.begin()
try:
......
......@@ -463,9 +463,6 @@ class DebugTestResult:
self.result = result
def _start_debugger(self, tb):
import Lifetime
if Lifetime._shutdown_phase:
return
try:
# try ipython if available
import IPython
......@@ -624,11 +621,9 @@ def runUnitTestList(test_list, verbosity=1, debug=0, run_only=None):
TestRunner = unittest.TextTestRunner
import Lifetime
from Zope2.custom_zodb import Storage, save_mysql, \
node_pid_list, neo_cluster, zeo_server_pid, wcfs_server
def shutdown(signum, frame, signum_set=set()):
Lifetime.shutdown(0)
signum_set.add(signum)
if node_pid_list is None and len(signum_set) > 1:
# in case of ^C, a child should also receive a SIGHUP from the parent,
......
......@@ -69,13 +69,6 @@ def get_new_publish(zope_publish):
if patch is False:
patch = True
if six.PY2: # ZServer-specific patch
# Apply the patch TODO: zope4py2 is this really needed ?
from ZPublisher import Publish
Publish.publish = get_new_publish(Publish.publish)
# PATCH 2: Accept
#
# Adds the variable AcceptLanguage to the REQUEST. It provides a higher
......
import six
if six.PY2:
from ZServer.datatypes import ServerFactory
class TimerServerFactory(ServerFactory):
def __init__(self, section):
ServerFactory.__init__(self)
self.interval = section.interval
def create(self):
from .TimerServer import TimerServer
return TimerServer(self.module, self.interval)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment