[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/LineReceiver - LineCommandParser.py:1.2 LineServerChannel.py:1.2 LineTask.py:1.2 __init__.py:1.2

Jim Fulton jim@zope.com
Mon, 10 Jun 2002 19:30:07 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Server/LineReceiver
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/Server/LineReceiver

Added Files:
	LineCommandParser.py LineServerChannel.py LineTask.py 
	__init__.py 
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.

=== Zope3/lib/python/Zope/Server/LineReceiver/LineCommandParser.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+from Zope.Server.IStreamConsumer import IStreamConsumer
+
+
+class LineCommandParser:
+    """Line Command parser. Arguments are left alone for now."""
+
+    __implements__ = IStreamConsumer
+
+    # See Zope.Server.IStreamConsumer.IStreamConsumer
+    completed = 0
+    inbuf = ''
+    cmd = ''
+    args = ''
+    empty = 0
+
+    max_line_length = 1024  # Not a hard limit
+
+
+    def __init__(self, adj):
+        """
+        adj is an Adjustments object.
+        """
+        self.adj = adj
+
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Server.IStreamConsumer
+
+    def received(self, data):
+        'See Zope.Server.IStreamConsumer.IStreamConsumer'
+        if self.completed:
+            return 0  # Can't consume any more.
+        pos = data.find('\n')
+        datalen = len(data)
+        if pos < 0:
+            self.inbuf = self.inbuf + data
+            if len(self.inbuf) > self.max_line_length:
+                # Don't accept any more.
+                self.completed = 1
+            return datalen
+        else:
+            # Line finished.
+            s = data[:pos + 1]
+            self.inbuf = self.inbuf + s
+            self.completed = 1
+            line = self.inbuf.strip()
+            self.parseLine(line)
+            return len(s)
+
+    #
+    ############################################################
+
+
+    def parseLine(self, line):
+        parts = line.split(' ', 1)
+        if len(parts) == 2:
+            self.cmd, self.args = parts
+        else:
+            self.cmd = parts[0]


=== Zope3/lib/python/Zope/Server/LineReceiver/LineServerChannel.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+import os
+import stat
+import socket
+import sys
+import time
+
+from Zope.Server.ServerChannelBase import ServerChannelBase
+from LineCommandParser import LineCommandParser
+from LineTask import LineTask
+
+
+DEBUG = os.environ.get('ZOPE_SERVER_DEBUG')
+
+
+class LineServerChannel(ServerChannelBase):
+    """The Line Server Channel represents a connection to a particular
+       client. We can therefore store information here."""
+
+    __implements__ = ServerChannelBase.__implements__
+
+    # Wrapper class that is used to execute a command in a different thread
+    task_class = LineTask
+
+    # Class that is being initialized to parse the input
+    parser_class = LineCommandParser
+
+    # List of commands that are always available
+    special_commands = ('cmd_quit')
+
+    # Commands that are run in a separate thread
+    thread_commands = ()
+
+    # Define the authentication status of the channel. Note that only the
+    # "special commands" can be executed without having authenticated.
+    authenticated = 0
+
+    # Define the reply code for non-authenticated responses
+    not_auth_reply = 'LOGIN_REQUIRED'
+
+    # Define the reply code for an unrecognized command
+    unknown_reply = 'CMD_UNKNOWN'
+
+    # Define the error message that occurs, when the reply code was not found.
+    reply_error = '500 Unknown Reply Code: %s.'
+
+    # Define the status messages
+    status_messages = {
+        'CMD_UNKNOWN'      : "500 '%s': command not understood.",
+        'INTERNAL_ERROR'   : "500 Internal error: %s",
+        'LOGIN_REQUIRED'   : '530 Please log in with USER and PASS',
+        }
+
+
+    def process_request(self, command):
+        """Processes a command.
+
+        Some commands use an alternate thread.
+        """
+        assert isinstance(command, LineCommandParser)
+        cmd = command.cmd
+        method = 'cmd_' + cmd.lower()
+        if ( not self.authenticated and method not in self.special_commands):
+            # The user is not logged in, therefore don't allow anything
+            self.reply(self.not_auth_reply)
+
+        elif method in self.thread_commands:
+            # Process in another thread.
+            return self.task_class(self, command, method)
+
+        elif hasattr(self, method):
+            try:
+                getattr(self, method)(command.args)
+            except:
+                self.exception()
+        else:
+            self.reply(self.unknown_reply, cmd.upper())
+        return None
+
+
+    def reply(self, code, args=(), flush=1):
+        """ """
+        try:
+            msg = self.status_messages[code] %args
+        except:
+            msg = self.reply_error %code
+
+        self.write('%s\r\n' %msg)
+
+        if flush:
+            self.flush(0)
+
+        # XXX: Some logging should go on here.
+
+
+    def exception(self):
+        if DEBUG:
+            import traceback
+            traceback.print_exc()
+        t, v = sys.exc_info()[:2]
+        try:
+            info = '%s: %s' % (getattr(t, '__name__', t), v)
+        except:
+            info = str(t)
+        self.reply('INTERNAL_ERROR', info)
+        self.handle_error()


=== Zope3/lib/python/Zope/Server/LineReceiver/LineTask.py 1.1 => 1.2 ===
+#
+# 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$
+"""
+
+import socket
+import time
+from Zope.Server.ITask import ITask
+
+
+class LineTask:
+    """This is a generic task that can be used with command line
+       protocols to handle commands in a separate thread.
+    """
+
+    __implements__ = ITask
+
+
+    def __init__(self, channel, command, m_name):
+        self.channel = channel
+        self.m_name = m_name
+        self.args = command.args
+
+        self.close_on_finish = 0
+
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Server.ITask
+
+    def service(self):
+        """Called to execute the task.
+        """
+        try:
+            try:
+                self.start()
+                getattr(self.channel, self.m_name)(self.args)
+                self.finish()
+            except socket.error:
+                self.close_on_finish = 1
+                if self.channel.adj.log_socket_errors:
+                    raise
+            except:
+                self.channel.exception()
+        finally:
+            self.channel.end_task(self.close_on_finish)
+
+
+    def cancel(self):
+        'See Zope.Server.ITask.ITask'
+        self.channel.close_when_done()
+
+
+    def defer(self):
+        'See Zope.Server.ITask.ITask'
+        pass
+
+    #
+    ############################################################
+
+    def start(self):
+        now = time.time()
+        self.start_time = now
+
+
+    def finish(self):
+        hit_log = self.channel.server.hit_log
+        if hit_log is not None:
+            hit_log.log(self)


=== Zope3/lib/python/Zope/Server/LineReceiver/__init__.py 1.1 => 1.2 ===
+#
+# 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$
+"""