[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server - FixedStreamReceiver.py:1.1.2.1 IDispatcher.py:1.1.2.1 IDispatcherEventHandler.py:1.1.2.1 IDispatcherLogging.py:1.1.2.1 IServer.py:1.1.2.1 IServerChannel.py:1.1.2.1 ISocket.py:1.1.2.1 ServerChannelBase.py:1.1.2.1 Adjustments.py:1.1.2.4.2.1 Buffers.py:1.1.2.3.2.1 DualModeChannel.py:1.1.2.4.2.1 IHeaderOutput.py:1.1.2.3.2.1 IRequestFactory.py:1.1.4.2.2.1 IStreamConsumer.py:1.1.2.3.2.1 ITask.py:1.1.2.3.2.1 ITaskDispatcher.py:1.1.2.2.2.1 ServerBase.py:1.1.2.4.2.1 TaskThreads.py:1.1.2.8.2.1 Utilities.py:1.1.2.3.2.1 ZLogIntegration.py:1.1.2.3.2.1 __init__.py:1.1.2.5.2.1 Chunking.py:NONE HTTPServer.py:NONE PublisherServers.py:NONE
Stephan Richter
srichter@cbu.edu
Tue, 2 Apr 2002 00:08:37 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Server
In directory cvs.zope.org:/tmp/cvs-serv6290/lib/python/Zope/Server
Modified Files:
Tag: Zope3-Server-Branch
Adjustments.py Buffers.py DualModeChannel.py IHeaderOutput.py
IRequestFactory.py IStreamConsumer.py ITask.py
ITaskDispatcher.py ServerBase.py TaskThreads.py Utilities.py
ZLogIntegration.py __init__.py
Added Files:
Tag: Zope3-Server-Branch
FixedStreamReceiver.py IDispatcher.py
IDispatcherEventHandler.py IDispatcherLogging.py IServer.py
IServerChannel.py ISocket.py ServerChannelBase.py
Removed Files:
Tag: Zope3-Server-Branch
Chunking.py HTTPServer.py PublisherServers.py
Log Message:
Issue 53: Comment
- Created a bunch of interfaces that let us know what is going on.
- Split, updated and zopefied the Logger code.
- Reorganized dir structure in Zope.Server
- HTTP component split up in files (HTTP server works)
- Inserted Shane's skeleton FTP code (since I like his better than mine)
- Took a first cut at the Virtual File System (VFS) by copying and updating
medusa'a old filesys.py code.
=== Added File Zope3/lib/python/Zope/Server/FixedStreamReceiver.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: FixedStreamReceiver.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
from IStreamConsumer import IStreamConsumer
class FixedStreamReceiver:
__implements__ = IStreamConsumer
# See Zope.Server.IStreamConsumer.IStreamConsumer
completed = 0
def __init__(self, cl, buf):
self.remain = cl
self.buf = buf
############################################################
# Implementation methods for interface
# Zope.Server.IStreamConsumer
def received(self, data):
'See Zope.Server.IStreamConsumer.IStreamConsumer'
rm = self.remain
if rm < 1:
self.completed = 1 # Avoid any chance of spinning
return 0
datalen = len(data)
if rm <= datalen:
self.buf.append(data[:rm])
self.remain = 0
self.completed = 1
return rm
else:
self.buf.append(data)
self.remain -= datalen
return datalen
#
############################################################
def getfile(self):
return self.buf.getfile()
=== Added File Zope3/lib/python/Zope/Server/IDispatcher.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: IDispatcher.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
from ISocket import ISocket
from IDispatcherEventHandler import IDispatcherEventHandler
from IDispatcherLogging import IDispatcherLogging
class IDispatcher(ISocket, IDispatcherEventHandler, IDispatcherLogging):
"""The dispatcher is the most low-level component of a server.
1. It manages the socket connections and distributes the
request to the appropriate channel.
2. It handles the events passed to it, such as reading input,
writing output and handling errors. More about this
functionality can be found in IDispatcherEventHandler.
3. It handles logging of the requests passed to the server as
well as other informational messages and erros. Please see
IDispatcherLogging for more details.
Note: Most of this documentation is taken from the Python
Library Reference.
"""
def add_channel(map=None):
"""After the low-level socket connection negotiation is
completed, a channel is created that handles all requests
and responses until the end of the connection.
"""
def del_channel(map=None):
"""Delete a channel. This should include also closing the
socket to the client.
"""
def create_socket(family, type):
"""This is identical to the creation of a normal socket, and
will use the same options for creation. Refer to the socket
documentation for information on creating sockets.
"""
def readable():
"""Each time through the select() loop, the set of sockets is
scanned, and this method is called to see if there is any
interest in reading. The default method simply returns 1,
indicating that by default, all channels will be
interested.
"""
def writable():
"""Each time through the select() loop, the set of sockets is
scanned, and this method is called to see if there is any
interest in writing. The default method simply returns 1,
indicating that by default, all channels will be
interested.
"""
=== Added File Zope3/lib/python/Zope/Server/IDispatcherEventHandler.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: IDispatcherEventHandler.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
from Interface import Interface
class IDispatcherEventHandler(Interface):
"""The Dispatcher can receive several different types of events. This
interface describes the necessary methods that handle these common
event types.
"""
def handle_read_event():
"""Given a read event, a server has to handle the event and
read the input from the client.
"""
def handle_write_event():
"""Given a write event, a server has to handle the event and
write the output to the client.
"""
def handle_expt_event():
"""An exception event was handed to the server.
"""
def handle_error():
"""An error occured, but we are still trying to fix it.
"""
def handle_expt():
"""Handle unhandled exceptions. This is usually a time to log.
"""
def handle_read():
"""Read output from client.
"""
def handle_write():
"""Write output via the socket to the client.
"""
def handle_connect():
"""A client requests a connection, now we need to do soemthing.
"""
def handle_accept():
"""A connection is accepted.
"""
def handle_close():
"""A connection is being closed.
"""
=== Added File Zope3/lib/python/Zope/Server/IDispatcherLogging.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: IDispatcherLogging.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
from Interface import Interface
class IDispatcherLogging(Interface):
"""This interface provides methods through which the Dispatcher will
write its logs. A distinction is made between hit and message logging,
since they often go to different output types and can have very
different structure.
"""
def log (message):
"""Logs general requests made to the server.
"""
def log_info(message, type='info'):
"""Logs informational messages, warnings and errors.
"""
=== Added File Zope3/lib/python/Zope/Server/IServer.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: IServer.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
from Interface import Interface
from Interface.Attribute import Attribute
class IServer(Interface):
"""This interface describes the basic base server.
The most unusual part about the Zope servers (since they all
implement this interface or inherit its base class) is that it
uses a mix of asynchronous and thread-based mechanism to
serve. While the low-level socket listener uses async, the
actual request is executed in a thread. This has the huge
advantage that if a request takes really long to process, the
server does not hang at that point to wait for the request to
finish.
"""
channel_class = Attribute("""
The channel class defines the type of channel
to be used by the server. See IServerChannel
for more information.
""")
SERVER_IDENT = Attribute("""
This string identifies the server. By default
this is 'Zope.Server.' and should be
overridden.
""")
=== Added File Zope3/lib/python/Zope/Server/IServerChannel.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: IServerChannel.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
from Interface import Interface
from Interface.Attribute import Attribute
class IServerChannel(Interface):
"""
"""
parser_class = Attribute("Subclasses must provide a parser class")
task_class = Attribute("Subclasses must provide a task class.")
active_channels = Attribute("Class-specific channel tracker")
next_channel_cleanup = Attribute("Class-specific cleanup time")
proto_request = Attribute("A request parser instance")
ready_requests = Attribute("A list of requests to be processed.")
last_activity = Attribute("Time of last activity")
running_tasks = Attribute("boolean")
def queue_request(self, req):
"""Queues a request to be processed in sequence by a task.
"""
def end_task(self, close):
"""Called at the end of a task, may launch another task.
"""
def create_task(self, req):
"""Creates a new task and queues it for execution.
The task may get executed in another thread.
"""
=== Added File Zope3/lib/python/Zope/Server/ISocket.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: ISocket.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
from Interface import Interface
class ISocket(Interface):
"""Represents a socket.
Note: Most of this documentation is taken from the Python Library
Reference.
"""
def listen(num):
"""Listen for connections made to the socket. The backlog argument
specifies the maximum number of queued connections and should
be at least 1; the maximum value is system-dependent (usually
5).
"""
def bind(addr):
"""Bind the socket to address. The socket must not already be bound.
"""
def connect(address):
"""Connect to a remote socket at address.
"""
def accept():
"""Accept a connection. The socket must be bound to an address and
listening for connections. The return value is a pair (conn,
address) where conn is a new socket object usable to send and
receive data on the connection, and address is the address
bound to the socket on the other end of the connection.
"""
def recv(buffer_size):
"""Receive data from the socket. The return value is a string
representing the data received. The maximum amount of data
to be received at once is specified by bufsize. See the
Unix manual page recv(2) for the meaning of the optional
argument flags; it defaults to zero.
"""
def send(data):
"""Send data to the socket. The socket must be connected to a
remote socket. The optional flags argument has the same
meaning as for recv() above. Returns the number of bytes
sent. Applications are responsible for checking that all
data has been sent; if only some of the data was
transmitted, the application needs to attempt delivery of
the remaining data.
"""
def close():
"""Close the socket. All future operations on the socket
object will fail. The remote end will receive no more data
(after queued data is flushed). Sockets are automatically
closed when they are garbage-collected.
"""
=== Added File Zope3/lib/python/Zope/Server/ServerChannelBase.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: ServerChannelBase.py,v 1.1.2.1 2002/04/02 05:08:05 srichter Exp $
"""
import os
import time
import sys
import asyncore
from thread import allocate_lock
# Enable ZOPE_SERVER_SIMULT_MODE to enable experimental
# simultaneous channel mode, which may improve or degrade
# throughput depending on load characteristics.
if os.environ.get('ZOPE_SERVER_SIMULT_MODE'):
from DualModeChannel import SimultaneousModeChannel as \
ChannelBaseClass
else:
from DualModeChannel import DualModeChannel as ChannelBaseClass
from IServerChannel import IServerChannel
# Synchronize access to the "running_tasks" attributes.
running_lock = allocate_lock()
class ServerChannelBase(ChannelBaseClass):
"""Base class for a high-performance, mixed-mode server-side channel.
"""
__implements__ = ChannelBaseClass.__implements__, IServerChannel
parser_class = None # Subclasses must provide a parser class
task_class = None # ... and a task class.
active_channels = {} # Class-specific channel tracker
next_channel_cleanup = [0] # Class-specific cleanup time
proto_request = None # A request parser instance
ready_requests = None # A list
last_activity = 0 # Time of last activity
running_tasks = 0 # boolean: true when any task is being executed
#
# ASYNCHRONOUS METHODS (incl. __init__)
#
def __init__(self, server, conn, addr, adj=None, socket_map=None):
ChannelBaseClass.__init__(self, server, conn, addr, adj, socket_map)
self.last_activity = t = self.creation_time
self.check_maintenance(t)
def add_channel(self, map=None):
"""This hook keeps track of opened HTTP channels.
"""
ChannelBaseClass.add_channel(self, map)
self.active_channels[self._fileno] = self
def del_channel(self, map=None):
"""This hook keeps track of closed HTTP channels.
"""
ChannelBaseClass.del_channel(self, map)
ac = self.active_channels
fd = self._fileno
if ac.has_key(fd):
del ac[fd]
def check_maintenance(self, now):
"""Performs maintenance if necessary.
"""
if now < self.next_channel_cleanup[0]:
return
self.next_channel_cleanup[0] = now + self.adj.cleanup_interval
self.maintenance()
def maintenance(self):
"""Kills off dead connections.
"""
self.kill_zombies()
def kill_zombies(self):
"""Closes connections that have not had any activity in a while.
The timeout is configured through adj.channel_timeout (seconds).
"""
now = time.time()
cutoff = now - self.adj.channel_timeout
for channel in self.active_channels.values():
if (channel is not self and not channel.running_tasks and
channel.last_activity < cutoff):
channel.close()
def received(self, data):
"""Receives input asynchronously and launches or queues requests.
"""
preq = self.proto_request
while data:
if preq is None:
preq = self.parser_class(self.adj)
n = preq.received(data)
if preq.completed:
# The request is ready to use.
if not preq.empty:
self.queue_request(preq)
preq = None
self.proto_request = None
else:
self.proto_request = preq
if n >= len(data):
break
data = data[n:]
def queue_request(self, req):
"""Queues a request to be processed in sequence.
"""
do_now = 0
running_lock.acquire()
try:
if self.running_tasks:
# Wait for the current tasks to finish.
rr = self.ready_requests
if rr is None:
rr = []
self.ready_requests = rr
rr.append(req)
else:
# Do it now.
self.running_tasks = 1
do_now = 1
finally:
running_lock.release()
if do_now:
self.process_request(req)
def handle_error(self):
"""Handles program errors (not communication errors)
"""
t, v = sys.exc_info()[:2]
if t is SystemExit or t is KeyboardInterrupt:
raise t, v
asyncore.dispatcher.handle_error(self)
def handle_comm_error(self):
"""Handles communication errors (not program errors)
"""
if self.adj.log_socket_errors:
self.handle_error()
else:
# Ignore socket errors.
self.close()
#
# SYNCHRONOUS METHODS
#
def end_task(self, close):
"""Called at the end of a task and may launch another task.
"""
if close:
self.close_when_done()
return
new_req = None
running_lock.acquire()
try:
rr = self.ready_requests
if rr:
new_req = rr.pop(0)
else:
# No requests to service.
self.running_tasks = 0
finally:
running_lock.release()
if new_req:
# Respond to the next request.
self.process_request(new_req)
else:
# Wait for another request on this connection.
self.set_async()
#
# BOTH MODES
#
def process_request(self, req):
"""Creates a new task and queues it for execution.
The task may get executed in another thread.
"""
self.set_sync()
task = self.task_class(self, req)
self.server.addTask(task)
=== Zope3/lib/python/Zope/Server/Adjustments.py 1.1.2.4 => 1.1.2.4.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
@@ -9,8 +6,7 @@
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
from medusa.test import max_sockets
=== Zope3/lib/python/Zope/Server/Buffers.py 1.1.2.3 => 1.1.2.3.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
+
try:
from cStringIO import StringIO
except ImportError:
=== Zope3/lib/python/Zope/Server/DualModeChannel.py 1.1.2.4 => 1.1.2.4.2.1 ===
#
##############################################################################
+"""
+
+$Id$
+"""
+
import asyncore
import socket
from time import time
@@ -51,7 +56,7 @@
select_trigger.the_trigger.pull_trigger()
-class ASMTrigger (AlternateSocketMapMixin, select_trigger.trigger):
+class ASMTrigger(AlternateSocketMapMixin, select_trigger.trigger):
"""Trigger for an alternate socket map"""
def __init__(self, socket_map):
@@ -61,17 +66,19 @@
pull_trigger = select_trigger.trigger.pull_trigger
-class SocketMapWithTrigger (UserDict):
+class SocketMapWithTrigger(UserDict):
def __init__(self):
UserDict.__init__(self)
self.pull_trigger = ASMTrigger(self).pull_trigger
-class DualModeChannel (AlternateSocketMapMixin, asyncore.dispatcher):
+class DualModeChannel(AlternateSocketMapMixin, asyncore.dispatcher):
"""Channel that switches between asynchronous and synchronous mode.
"""
+ __implements__ = asyncore.dispatcher.__implements__
+
# will_close is set to 1 to close the socket.
will_close = 0
@@ -236,6 +243,9 @@
helper. The asynchronous callbacks empty the output buffer
and fill the input buffer.
"""
+
+ __implements__ = asyncore.dispatcher.__implements__
+
def __init__(self, server, conn, addr, adj=None, socket_map=None):
global allocate_lock
=== Zope3/lib/python/Zope/Server/IHeaderOutput.py 1.1.2.3 => 1.1.2.3.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
@@ -9,8 +6,8 @@
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
+
from Interface import Interface
=== Zope3/lib/python/Zope/Server/IRequestFactory.py 1.1.4.2 => 1.1.4.2.2.1 ===
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
+# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""
=== Zope3/lib/python/Zope/Server/IStreamConsumer.py 1.1.2.3 => 1.1.2.3.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
+
from Interface import Interface
from Interface.Attribute import Attribute
=== Zope3/lib/python/Zope/Server/ITask.py 1.1.2.3 => 1.1.2.3.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
@@ -9,8 +6,8 @@
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
+
from Interface import Interface
=== Zope3/lib/python/Zope/Server/ITaskDispatcher.py 1.1.2.2 => 1.1.2.2.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
+
from Interface import Interface
class ITaskDispatcher (Interface):
=== Zope3/lib/python/Zope/Server/ServerBase.py 1.1.2.4 => 1.1.2.4.2.1 ===
#
##############################################################################
-import os
+"""
+
+$Id$
+"""
+
import asyncore
import socket
-import time
-import sys
-from thread import allocate_lock
from DualModeChannel import AlternateSocketMapMixin
-from IStreamConsumer import IStreamConsumer
from Adjustments import default_adj
+from IServer import IServer
-# Enable ZOPE_SERVER_SIMULT_MODE to enable experimental
-# simultaneous channel mode, which may improve or degrade
-# throughput depending on load characteristics.
-if os.environ.get('ZOPE_SERVER_SIMULT_MODE'):
- from DualModeChannel import SimultaneousModeChannel as \
- channel_base_class
-else:
- from DualModeChannel import DualModeChannel as channel_base_class
-
-
-
-class FixedStreamReceiver:
-
- __implements__ = IStreamConsumer
-
- completed = 0
-
- def __init__(self, cl, buf):
- self.remain = cl
- self.buf = buf
-
- def received(self, data):
- rm = self.remain
- if rm < 1:
- self.completed = 1 # Avoid any chance of spinning
- return 0
- datalen = len(data)
- if rm <= datalen:
- self.buf.append(data[:rm])
- self.remain = 0
- self.completed = 1
- return rm
- else:
- self.buf.append(data)
- self.remain -= datalen
- return datalen
-
- def getfile(self):
- return self.buf.getfile()
-
-
-
-# Synchronize access to the "running_tasks" attributes.
-running_lock = allocate_lock()
-
-
-
-class ServerChannelBase (channel_base_class):
- """Base class for a high-performance, mixed-mode server-side channel.
- """
-
- parser_class = None # Subclasses must provide a parser class
- task_class = None # ... and a task class.
-
- active_channels = {} # Class-specific channel tracker
- next_channel_cleanup = [0] # Class-specific cleanup time
- proto_request = None # A request parser instance
- ready_requests = None # A list
- last_activity = 0 # Time of last activity
- running_tasks = 0 # boolean: true when any task is being executed
-
- #
- # ASYNCHRONOUS METHODS (incl. __init__)
- #
-
- def __init__(self, server, conn, addr, adj=None, socket_map=None):
- channel_base_class.__init__(self, server, conn, addr, adj, socket_map)
- self.last_activity = t = self.creation_time
- self.check_maintenance(t)
-
- def add_channel(self, map=None):
- """This hook keeps track of opened HTTP channels.
- """
- channel_base_class.add_channel(self, map)
- self.active_channels[self._fileno] = self
-
- def del_channel(self, map=None):
- """This hook keeps track of closed HTTP channels.
- """
- channel_base_class.del_channel(self, map)
- ac = self.active_channels
- fd = self._fileno
- if ac.has_key(fd):
- del ac[fd]
-
- def check_maintenance(self, now):
- """Performs maintenance if necessary.
- """
- if now < self.next_channel_cleanup[0]:
- return
- self.next_channel_cleanup[0] = now + self.adj.cleanup_interval
- self.maintenance()
-
- def maintenance(self):
- """Kills off dead connections.
- """
- self.kill_zombies()
-
- def kill_zombies(self):
- """Closes connections that have not had any activity in a while.
-
- The timeout is configured through adj.channel_timeout (seconds).
- """
- now = time.time()
- cutoff = now - self.adj.channel_timeout
- for channel in self.active_channels.values():
- if (channel is not self and not channel.running_tasks and
- channel.last_activity < cutoff):
- channel.close()
-
- def received(self, data):
- """Receives input asynchronously and launches or queues requests.
- """
- preq = self.proto_request
- while data:
- if preq is None:
- preq = self.parser_class(self.adj)
- n = preq.received(data)
- if preq.completed:
- # The request is ready to use.
- if not preq.empty:
- self.queue_request(preq)
- preq = None
- self.proto_request = None
- else:
- self.proto_request = preq
- if n >= len(data):
- break
- data = data[n:]
-
- def queue_request(self, req):
- """Queues a request to be processed in sequence.
- """
- do_now = 0
- running_lock.acquire()
- try:
- if self.running_tasks:
- # Wait for the current tasks to finish.
- rr = self.ready_requests
- if rr is None:
- rr = []
- self.ready_requests = rr
- rr.append(req)
- else:
- # Do it now.
- self.running_tasks = 1
- do_now = 1
- finally:
- running_lock.release()
- if do_now:
- self.process_request(req)
-
- def handle_error(self):
- """Handles program errors (not communication errors)
- """
- t, v = sys.exc_info()[:2]
- if t is SystemExit or t is KeyboardInterrupt:
- raise t, v
- asyncore.dispatcher.handle_error(self)
-
- def handle_comm_error(self):
- """Handles communication errors (not program errors)
- """
- if self.adj.log_socket_errors:
- self.handle_error()
- else:
- # Ignore socket errors.
- self.close()
-
- #
- # SYNCHRONOUS METHODS
- #
-
- def end_task(self, close):
- """Called at the end of a task and may launch another task.
- """
- if close:
- self.close_when_done()
- return
- new_req = None
- running_lock.acquire()
- try:
- rr = self.ready_requests
- if rr:
- new_req = rr.pop(0)
- else:
- # No requests to service.
- self.running_tasks = 0
- finally:
- running_lock.release()
- if new_req:
- # Respond to the next request.
- self.process_request(new_req)
- else:
- # Wait for another request on this connection.
- self.set_async()
-
- #
- # BOTH MODES
- #
-
- def process_request(self, req):
- """Creates a new task and queues it for execution.
-
- The task may get executed in another thread.
- """
- self.set_sync()
- task = self.task_class(self, req)
- self.server.addTask(task)
-
-
-
-
-
-class ServerBase (AlternateSocketMapMixin, asyncore.dispatcher):
+class ServerBase(AlternateSocketMapMixin, asyncore.dispatcher):
"""Async. server base for launching derivatives of ServerChannelBase.
"""
+ __implements__ = asyncore.dispatcher.__implements__, IServer
+
channel_class = None # Override with a channel class.
SERVER_IDENT = 'Zope.Server.ServerBase' # Override.
@@ -296,23 +85,40 @@
self.port
))
+
+ def addTask(self, task):
+ td = self.task_dispatcher
+ if td is not None:
+ td.addTask(task)
+ else:
+ task.service()
+
+ ############################################################
+ # Implementation methods for interface
+ # Zope.Server.IDispatcher.IDispatcher
+
def readable(self):
+ 'See Zope.Server.IDispatcher.IDispatcher'
return (self.accepting and
len(asyncore.socket_map) < self.adj.connection_limit)
- def writable (self):
+ def writable(self):
+ 'See Zope.Server.IDispatcher.IDispatcher'
return 0
-
- def handle_read (self):
+
+ ######################################
+ # from: Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler
+
+ def handle_read(self):
+ 'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler'
pass
-
- def readable (self):
- return self.accepting
-
- def handle_connect (self):
+
+ def handle_connect(self):
+ 'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler'
pass
- def handle_accept (self):
+ def handle_accept(self):
+ 'See Zope.Server.IDispatcherEventHandler.IDispatcherEventHandler'
try:
v = self.accept()
if v is None:
@@ -329,10 +135,6 @@
return
self.channel_class(self, conn, addr, self.adj, self.socket_map)
- def addTask(self, task):
- td = self.task_dispatcher
- if td is not None:
- td.addTask(task)
- else:
- task.service()
+ #
+ ############################################################
=== Zope3/lib/python/Zope/Server/TaskThreads.py 1.1.2.8 => 1.1.2.8.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
@@ -9,8 +6,8 @@
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
+
import sys
from Queue import Queue, Empty
from thread import allocate_lock, start_new_thread
=== Zope3/lib/python/Zope/Server/Utilities.py 1.1.2.3 => 1.1.2.3.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+
+
def find_double_newline(s):
"""Returns the position just after a double newline in the given string."""
pos1 = s.find('\n\r\n') # One kind of double newline
=== Zope3/lib/python/Zope/Server/ZLogIntegration.py 1.1.2.3 => 1.1.2.3.2.1 ===
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
+# Copyright 2001-2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
@@ -9,8 +6,6 @@
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
"""Makes asyncore log to zLOG.
"""
=== Zope3/lib/python/Zope/Server/__init__.py 1.1.2.5 => 1.1.2.5.2.1 ===
"""
Zope.Server package.
-"""
-
-
-
+$Id$
+"""
-### A routine to try to arrange for request sockets to be closed
-### on exec. This makes it easier for folks who spawn long running
-### processes from Zope code. Thanks to Dieter Maurer for this.
-##try:
-## import fcntl, FCNTL
-## FCNTL.F_SETFD; FCNTL.FD_CLOEXEC
-## def requestCloseOnExec(sock):
-## try: fcntl.fcntl(sock.fileno(), FCNTL.F_SETFD, FCNTL.FD_CLOEXEC)
-## except: pass
-
-##except (ImportError, AttributeError):
-
-## def requestCloseOnExec(sock):
-## pass
+from IDispatcher import IDispatcher
+from Interface.Implements import implements
-##import asyncore
-##from medusa import resolver, logger
-##from HTTPServer import zhttp_server, zhttp_handler
-##from PubCore import setNumberOfThreads
-##from medusa.monitor import secure_monitor_server
+import asyncore
-### override the service name in logger.syslog_logger
-##logger.syslog_logger.svc_name='ZServer'
+implements(asyncore.dispatcher, IDispatcher, 0)
=== Removed File Zope3/lib/python/Zope/Server/Chunking.py ===
=== Removed File Zope3/lib/python/Zope/Server/HTTPServer.py ===
=== Removed File Zope3/lib/python/Zope/Server/PublisherServers.py ===