[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 ===