You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mod_ftp-commits@incubator.apache.org by ji...@apache.org on 2005/10/06 13:17:04 UTC

svn commit: r306631 [7/8] - in /incubator/mod_ftp/trunk: ./ conf/ docs/ include/ modules/ patches/ src/ tests/ tests/conf/ tests/logs/ tests/tests/ utils/ utils/ftp_proxy/ utils/static_build/ utils/stresstest/

Added: incubator/mod_ftp/trunk/src/mod_ftp.dsp
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/src/mod_ftp.dsp?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/src/mod_ftp.dsp (added)
+++ incubator/mod_ftp/trunk/src/mod_ftp.dsp Thu Oct  6 06:16:28 2005
@@ -0,0 +1,188 @@
+# Microsoft Developer Studio Project File - Name="mod_ftp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_ftp - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_ftp.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_ftp.mak" CFG="mod_ftp - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_ftp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_ftp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_ftp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "SRC_EXPORTS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../include" /I "$(APACHE_TMPINSTALL_WINNT)/include" /D "FTP_NO_GLOB" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "FTP_DECLARE_EXPORT" /Fd"Release/mod_ftp" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /dll /machine:I386
+# ADD LINK32 libapr.lib libhttpd.lib libaprutil.lib wsock32.lib /nologo /dll /debug /machine:I386 /out:"Release/mod_ftp.so" /libpath:"$(APACHE_TMPINSTALL_WINNT)\lib" /base:@"$(SRCROOT)/dev-bin/cov_dll.ref",ftp_module
+
+!ELSEIF  "$(CFG)" == "mod_ftp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SRC_EXPORTS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../include" /I "$(APACHE_TMPINSTALL_WINNT)/include" /D "FTP_NO_GLOB" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "FTP_DECLARE_EXPORT" /Fd"Debug\mod_ftp" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 libapr.lib libhttpd.lib libaprutil.lib wsock32.lib /nologo /dll /debug /machine:I386 /out:"Debug/mod_ftp.so" /libpath:"$(APACHE_TMPINSTALL_WINNT)\lib" /base:@"$(SRCROOT)/dev-bin/cov_dll.ref",ftp_module
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_ftp - Win32 Release"
+# Name "mod_ftp - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\ftp_commands.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_connection.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_data_connection.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_data_filters.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_filters.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_inet_pton.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_limitlogin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_log.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_message.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_protocol.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_request.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftp_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_ftp.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\include\ftp_config.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\mod_ftp.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE="..\config-win32.awk"
+
+!IF  "$(CFG)" == "mod_ftp - Win32 Release"
+
+USERDEP__CONFI="..\configure.in"	
+# Begin Custom Build - Generating ftp_config.h
+InputPath="..\config-win32.awk"
+
+"..\include\ftp_config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f $(InputPath) < ..\configure.in > ..\include\ftp_config.h
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "mod_ftp - Win32 Debug"
+
+USERDEP__CONFI="..\configure.in"	
+# Begin Custom Build - Generating ftp_config.h
+InputPath="..\config-win32.awk"
+
+"..\include\ftp_config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f $(InputPath) < ..\configure.in > ..\include\ftp_config.h
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Target
+# End Project

Propchange: incubator/mod_ftp/trunk/src/mod_ftp.dsp
------------------------------------------------------------------------------
    svn:eol-style = CRLF

Added: incubator/mod_ftp/trunk/src/remake_ftp_protocol
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/src/remake_ftp_protocol?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/src/remake_ftp_protocol (added)
+++ incubator/mod_ftp/trunk/src/remake_ftp_protocol Thu Oct  6 06:16:28 2005
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+# $Date: 2002/01/02 19:14:54 $ $Id: remake_ftp_protocol,v 1.6 2002/01/02 19:14:54 rmorgan Exp $
+#
+$SRCDIR="\.\.";
+
+open FHREPLY,"$SRCDIR/include/mod_ftp.h"
+	or die "Cannot open FTP its mod_ftp.h: $!";
+open FHCOMMAND,"$SRCDIR/src/ftp_commands.c"
+	or die "Cannot open FTP its ftp_commands.c: $!";
+
+$t=scalar(gmtime(time));
+$nr_of_resp = 0;
+$nr_of_req = 0;
+
+print qq|/* ftp_protocol.h
+ *
+ * Dynamicaly generated FTP request types and response types.
+ *
+ * Do not edit manually; but delete the file and do
+ * another gmake (or a make ftp_protocol.h)
+ *
+ * Generated from $SRCDIR on 
+ * $t
+ */
+|;
+
+while(<FHREPLY>) {
+	next unless m/^\#define/;
+	if (m/^\#define\s+FTP_REPLY_(\w+)\s*(\d+)/) {
+		$p{ $2 } = $1;
+		$nr_of_resp++;
+	};
+};
+
+@resp = ();
+
+while(<FHCOMMAND>) {
+	next unless m/\s*ftp_hook_cmd\(\"/;
+	if (m/\s*ftp_hook_cmd\(\"/) {
+		$nr_of_req++;
+		s/\s*ftp_hook_cmd\(\"//g;
+		s/\"(.+)//g;
+		chop;
+		push (@resp, $_);
+	};
+};
+
+
+
+print qq|
+
+#define WWW_MIB_TOTAL_FTP_RESPONSES $nr_of_resp
+
+const int ftp_response_types[] = {
+    |;
+
+map {
+	print "$_, ";
+	} sort { $a <=> $b } keys %p;
+
+print qq|0 }; 
+
+#define WWW_MIB_TOTAL_FTP_REQUESTS $nr_of_req
+
+const char *ftp_request_types[] ={
+    |;
+map {
+	print "\"$_\", ";
+	} sort { 
+		$x = length($a) <=> length($b);
+		return $x ? $x : (uc $a cmp uc $b);
+		} @resp;
+print "NULL };
+
+";

Propchange: incubator/mod_ftp/trunk/src/remake_ftp_protocol
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/stamp-h.in
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/stamp-h.in?rev=306631&view=auto
==============================================================================
    (empty)

Added: incubator/mod_ftp/trunk/tests/.cvsignore
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/.cvsignore?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/.cvsignore (added)
+++ incubator/mod_ftp/trunk/tests/.cvsignore Thu Oct  6 06:16:28 2005
@@ -0,0 +1,10 @@
+Makefile
+Makefile.in
+apachetest.py
+pytest.py
+pytest.pyc
+server_config.py
+server_config.pyc
+test.out
+test.err
+htdocs

Propchange: incubator/mod_ftp/trunk/tests/.cvsignore
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/Makefile.in
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/Makefile.in?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/Makefile.in (added)
+++ incubator/mod_ftp/trunk/tests/Makefile.in Thu Oct  6 06:16:28 2005
@@ -0,0 +1,12 @@
+check:
+	@-mkdir -p logs htdocs > /dev/null 2>&1
+	@python apachetest.py @TESTBIN@ @PYTESTDIR@/conf/httpd.conf
+
+clean:
+	true
+
+install:
+	true
+
+all:
+	true

Propchange: incubator/mod_ftp/trunk/tests/Makefile.in
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/apachetest.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/apachetest.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/apachetest.py (added)
+++ incubator/mod_ftp/trunk/tests/apachetest.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,191 @@
+#
+# WARNING: This file lives in handy/pytest and is copied over during the
+# configuration process.  Changes to the file after it has been copied
+# will be lost!
+#
+
+import signal, os, re, time, sys, StringIO, popen2
+from pytest import Tester
+from string import *
+
+class ApacheTester(Tester):
+    def __init__(self, log_file, apachebin, apacheconf, errfile='test.err'):
+        self.apachebin  = apachebin
+        self.apacheconf = apacheconf
+        self.serverroot = self.find_serverroot()
+        self.pidfile    = self.find_pidfile()
+        self.maxline    = 50
+        self.ntests     = 0
+        self.nsuccess   = 0
+        self.log_buf    = StringIO.StringIO()
+        self.log_real   = log_file
+        self.apacheinfo = ''
+        self.teststart  = None
+        self.testend    = None
+        self.errfile    = errfile
+        
+        Tester.__init__(self, self.log_buf)
+
+    def snag_take1(self, directive):
+        my_re = re.compile('%s[ \t](("[^"]*")|([^ \t\r\n]*))' % directive,
+                           re.IGNORECASE)
+        for line in open(self.apacheconf, 'r').readlines():
+            m = my_re.match(line)
+            if m:
+                res = m.groups(2)[0]
+                if res[:1] == '"':
+                    return res[1:-1]
+                else:
+                    return res
+        return None
+        
+    def find_serverroot(self):
+        return self.snag_take1('serverroot')
+    
+    def find_pidfile(self):
+        return self.snag_take1('serverroot') + '/' + self.snag_take1('pidfile')
+    
+    def end_testsuite(self):
+        self.testend = time.time()
+        self.stop_server()
+        self.log_buf.seek(0)
+        self.log_real.write(self.generate_summary())
+        self.log_real.write(self.log_buf.read())
+        
+    def begin_testsuite(self):
+        self.teststart = time.time()
+        self.apacheinfo = os.popen('%s -v' % self.apachebin, 'r').read() + '\n'
+        print self.apacheinfo
+        
+        self.start_server()
+
+    def start_server(self):
+        pidfile = self.pidfile
+        try:    os.unlink(pidfile)
+        except: pass
+
+        cmdline = "%s -f %s 2>>%s" % (self.apachebin, self.apacheconf,
+                                      self.errfile)
+        #print cmdline
+        if os.system(cmdline):
+            raise 'Error starting server'
+
+        for i in range(100):
+            try:
+                x = open(pidfile, 'r')
+            except:
+                x = None
+                time.sleep(1)
+            if not x:  continue
+            else:      break
+
+        if not x:
+            raise 'Error starting server'
+
+    def stop_server(self):
+        try:
+            pid = int(open(self.pidfile, 'r').read())
+        except:
+            return
+        
+        while 1:  # KILL IT TILL ITS DEAD!
+            try:
+                os.kill(pid, signal.SIGTERM)
+            except:
+                break
+
+    def create_nicedoc(self, docstr):
+        res = []
+        words = split(docstr)
+        linelen = 0
+        for word in words:
+            if not linelen:
+                linelen = linelen + 1
+
+            res.append(word + ' ')
+            linelen = linelen + 1 + len(word)
+            if linelen > self.maxline:
+                linelen = 0
+                res.append('\n')
+
+        return split(join(res, ''), '\n')
+        
+    def generate_test_header(self, testname, success, nicedoc=None):
+        if success:
+            sucstring = 'Success'
+        else:
+            sucstring = 'FAILURE'
+            
+        header = [ 'Test:   ' + testname,
+                   'Time:   ' + time.ctime(time.time()),
+                   'Result: ' + sucstring ]
+
+        if nicedoc:
+            header.append('Info:   ' + nicedoc[0])
+            nicedoc = map(lambda x: '%-8s%s' % (' ', x), nicedoc)
+            header.extend(nicedoc[1:])
+                          
+        return self.boxulate(header) + '\n'
+        
+    def run_test(self, testname, fn):
+        self.ntests = self.ntests + 1
+        test_buf = StringIO.StringIO()
+        
+        sys.stdout.write('%-30s: ' % testname)
+        sys.stdout.flush()
+        nicedoc = None
+        if fn.__doc__:
+            nicedoc = self.create_nicedoc(fn.__doc__)
+            
+        if Tester.run_test(self, testname, fn, self, test_buf):
+            print 'Failure'
+            success = 0
+        else:
+            print 'Success'
+            self.nsuccess = self.nsuccess + 1
+            success = 1
+
+        test_buf.seek(0)
+        self.write_log(self.generate_test_header(testname, success, nicedoc))
+        self.write_log(test_buf.read())
+
+
+    def generate_summary(self):
+        if not self.ntests:
+            percsucc = 'Unknown'
+        else:
+            percsucc = '%.2f' % (self.nsuccess * 100 / self.ntests,)
+            
+        docinfo = ['Testsuite Summary','',
+                   'Start Time: ' + time.ctime(self.teststart),
+                   'End Time:   ' + time.ctime(self.testend),
+                   '# Tests:    ' + `self.ntests`,
+                   '# Success:  ' + `self.nsuccess`,
+                   '% Success:  ' + percsucc]
+
+        return self.boxulate(docinfo)
+
+        
+if __name__ == '__main__':
+    import sys, os
+
+    sys.path.append('tests')
+    for i in ('test.out', 'test.err'):
+        try:
+            os.unlink(i)
+        except:
+            pass
+
+    x = ApacheTester(open('test.out', 'w'), sys.argv[1], sys.argv[2],
+                     'test.err')
+    tests = os.listdir('tests')
+    tests.sort()
+    for fname in tests:
+        if fname[-3:] != '.py': continue
+        mod = __import__(fname[:-3], {}, {}, [])
+        x.run_test(fname[:-3], mod.test)
+
+    x.end_testsuite()
+    
+    path = os.getcwd()
+    print '\nSee results in ' + os.path.join(path, 'test.out') + '\n'

Propchange: incubator/mod_ftp/trunk/tests/apachetest.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/conf/.cvsignore
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/conf/.cvsignore?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/conf/.cvsignore (added)
+++ incubator/mod_ftp/trunk/tests/conf/.cvsignore Thu Oct  6 06:16:28 2005
@@ -0,0 +1,4 @@
+httpd.conf
+httpd.conf.in
+loadmodules.conf
+mime.types

Propchange: incubator/mod_ftp/trunk/tests/conf/.cvsignore
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/conf/httpd.conf.in
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/conf/httpd.conf.in?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/conf/httpd.conf.in (added)
+++ incubator/mod_ftp/trunk/tests/conf/httpd.conf.in Thu Oct  6 06:16:28 2005
@@ -0,0 +1,83 @@
+ServerRoot "@PYTESTDIR@"
+PidFile logs/httpd.pid
+
+<IfModule !dexter.c>
+ScoreBoardFile logs/apache_scoreboard
+</IfModule>
+
+Timeout 300
+KeepAlive On
+MaxKeepAliveRequests 100
+KeepAliveTimeout 15
+
+<IfModule prefork.c>
+StartServers         5
+MinSpareServers      5
+MaxSpareServers     10
+MaxClients          20
+MaxRequestsPerChild  0
+</IfModule>
+
+<IfModule mpmt_pthread.c>
+StartServers         5
+MaxClients           8
+MinSpareThreads      5
+MaxSpareThreads     10
+ThreadsPerChild     20
+MaxRequestsPerChild  0
+</IfModule>
+
+<IfModule dexter.c>
+NumServers           5
+StartThreads         5
+MinSpareThreads      5
+MaxSpareThreads     10
+MaxThreadsPerChild  20
+MaxRequestsPerChild  0
+</IfModule>
+
+Include "@PYTESTDIR@/conf/loadmodules.conf"
+
+Listen 12345 
+Listen 12346
+ServerAdmin you@your.address
+DocumentRoot "@PYTESTDIR@/htdocs"
+
+<Directory />
+    Options FollowSymLinks
+    AllowOverride None
+</Directory>
+
+<Directory "@PYTESTDIR@/htdocs">
+    Options Indexes FollowSymLinks
+    AllowOverride AuthConfig
+    Order allow,deny
+    Allow from all
+</Directory>
+
+DirectoryIndex index.html
+AccessFileName .htaccess
+<Files ~ "^\.ht">
+    Order allow,deny
+    Deny from all
+</Files>
+
+UseCanonicalName On
+TypesConfig conf/mime.types
+DefaultType text/plain
+
+<IfModule mod_mime_magic.c>
+    MIMEMagicFile conf/magic
+</IfModule>
+
+HostnameLookups Off
+ErrorLog logs/error_log
+LogLevel warn
+LogFormat "%h %l %u %t \"%r\" %>s %b" common
+CustomLog logs/access_log common
+ServerSignature On
+
+BrowserMatch "Mozilla/2" nokeepalive
+BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
+
+Include "@PYTESTDIR@/conf/mod_specs.conf"

Propchange: incubator/mod_ftp/trunk/tests/conf/httpd.conf.in
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/conf/loadmodules.conf.in
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/conf/loadmodules.conf.in?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/conf/loadmodules.conf.in (added)
+++ incubator/mod_ftp/trunk/tests/conf/loadmodules.conf.in Thu Oct  6 06:16:28 2005
@@ -0,0 +1 @@
+LoadModule ftp_module    @FTPDIR@/src/.libs/libmod_ftp.so

Propchange: incubator/mod_ftp/trunk/tests/conf/loadmodules.conf.in
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/conf/mime.types
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/conf/mime.types?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/conf/mime.types (added)
+++ incubator/mod_ftp/trunk/tests/conf/mime.types Thu Oct  6 06:16:28 2005
@@ -0,0 +1,428 @@
+# This is a comment. I love comments.
+
+# This file controls what Internet media types are sent to the client for
+# given file extension(s).  Sending the correct media type to the client
+# is important so they know how to handle the content of the file.
+# Extra types can either be added here or by using an AddType directive
+# in your config files. For more information about Internet media types,
+# please read RFC 2045, 2046, 2047, 2048, and 2077.  The Internet media type
+# registry is at <ftp://ftp.iana.org/in-notes/iana/assignments/media-types/>.
+
+# MIME type			Extension
+application/EDI-Consent
+application/EDI-X12
+application/EDIFACT
+application/activemessage
+application/andrew-inset	ez
+application/applefile
+application/atomicmail
+application/batch-SMTP
+application/cals-1840
+application/commonground
+application/cybercash
+application/dca-rft
+application/dec-dx
+application/eshop
+application/http
+application/hyperstudio
+application/iges
+application/index
+application/index.cmd
+application/index.obj
+application/index.response
+application/index.vnd
+application/iotp
+application/ipp
+application/mac-binhex40	hqx
+application/mac-compactpro	cpt
+application/macwriteii
+application/marc
+application/mathematica
+application/mathematica-old
+application/msword		doc
+application/news-message-id
+application/news-transmission
+application/ocsp-request
+application/ocsp-response
+application/octet-stream	bin dms lha lzh exe class so dll
+application/oda			oda
+application/pdf			pdf
+application/pgp-encrypted
+application/pgp-keys
+application/pgp-signature
+application/pkcs10
+application/pkcs7-mime
+application/pkcs7-signature
+application/pkix-cert
+application/pkix-crl
+application/pkixcmp
+application/postscript		ai eps ps
+application/prs.alvestrand.titrax-sheet
+application/prs.cww
+application/prs.nprend
+application/remote-printing
+application/riscos
+application/sdp
+application/set-payment
+application/set-payment-initiation
+application/set-registration
+application/set-registration-initiation
+application/sgml
+application/sgml-open-catalog
+application/slate
+application/smil		smi smil
+application/vemmi
+application/vnd.3M.Post-it-Notes
+application/vnd.FloGraphIt
+application/vnd.accpac.simply.aso
+application/vnd.accpac.simply.imp
+application/vnd.acucobol
+application/vnd.anser-web-certificate-issue-initiation
+application/vnd.anser-web-funds-transfer-initiation
+application/vnd.audiograph
+application/vnd.businessobjects
+application/vnd.bmi
+application/vnd.canon-cpdl
+application/vnd.canon-lips
+application/vnd.claymore
+application/vnd.commerce-battelle
+application/vnd.commonspace
+application/vnd.comsocaller
+application/vnd.contact.cmsg
+application/vnd.cosmocaller
+application/vnd.cups-postscript
+application/vnd.cups-raster
+application/vnd.cups-raw
+application/vnd.ctc-posml
+application/vnd.cybank
+application/vnd.dna
+application/vnd.dpgraph
+application/vnd.dxr
+application/vnd.ecdis-update
+application/vnd.ecowin.chart
+application/vnd.ecowin.filerequest
+application/vnd.ecowin.fileupdate
+application/vnd.ecowin.series
+application/vnd.ecowin.seriesrequest
+application/vnd.ecowin.seriesupdate
+application/vnd.enliven
+application/vnd.epson.esf
+application/vnd.epson.msf
+application/vnd.epson.quickanime
+application/vnd.epson.salt
+application/vnd.epson.ssf
+application/vnd.ericsson.quickcall
+application/vnd.eudora.data
+application/vnd.fdf
+application/vnd.ffsns
+application/vnd.framemaker
+application/vnd.fujitsu.oasys
+application/vnd.fujitsu.oasys2
+application/vnd.fujitsu.oasys3
+application/vnd.fujitsu.oasysgp
+application/vnd.fujitsu.oasysprs
+application/vnd.fujixerox.ddd
+application/vnd.fujixerox.docuworks
+application/vnd.fujixerox.docuworks.binder
+application/vnd.fut-misnet
+application/vnd.grafeq
+application/vnd.groove-account
+application/vnd.groove-identity-message
+application/vnd.groove-injector
+application/vnd.groove-tool-message
+application/vnd.groove-tool-template
+application/vnd.groove-vcard
+application/vnd.hp-HPGL
+application/vnd.hp-PCL
+application/vnd.hp-PCLXL
+application/vnd.hp-hpid
+application/vnd.hp-hps
+application/vnd.httphone
+application/vnd.hzn-3d-crossword
+application/vnd.ibm.MiniPay
+application/vnd.ibm.modcap
+application/vnd.informix-visionary
+application/vnd.intercon.formnet
+application/vnd.intertrust.digibox
+application/vnd.intertrust.nncp
+application/vnd.intu.qbo
+application/vnd.intu.qfx
+application/vnd.is-xpr
+application/vnd.japannet-directory-service
+application/vnd.japannet-jpnstore-wakeup
+application/vnd.japannet-payment-wakeup
+application/vnd.japannet-registration
+application/vnd.japannet-registration-wakeup
+application/vnd.japannet-setstore-wakeup
+application/vnd.japannet-verification
+application/vnd.japannet-verification-wakeup
+application/vnd.koan
+application/vnd.lotus-1-2-3
+application/vnd.lotus-approach
+application/vnd.lotus-freelance
+application/vnd.lotus-notes
+application/vnd.lotus-organizer
+application/vnd.lotus-screencam
+application/vnd.lotus-wordpro
+application/vnd.mcd
+application/vnd.mediastation.cdkey
+application/vnd.meridian-slingshot
+application/vnd.mif		mif
+application/vnd.minisoft-hp3000-save
+application/vnd.mitsubishi.misty-guard.trustweb
+application/vnd.mobius.daf
+application/vnd.mobius.dis
+application/vnd.mobius.msl
+application/vnd.mobius.plc
+application/vnd.mobius.txf
+application/vnd.motorola.flexsuite
+application/vnd.motorola.flexsuite.adsi
+application/vnd.motorola.flexsuite.fis
+application/vnd.motorola.flexsuite.gotap
+application/vnd.motorola.flexsuite.kmr
+application/vnd.motorola.flexsuite.ttc
+application/vnd.motorola.flexsuite.wem
+application/vnd.mozilla.xul+xml
+application/vnd.ms-artgalry
+application/vnd.ms-asf
+application/vnd.ms-excel	xls
+application/vnd.ms-lrm
+application/vnd.ms-powerpoint	ppt
+application/vnd.ms-project
+application/vnd.ms-tnef
+application/vnd.ms-works
+application/vnd.msign
+application/vnd.music-niff
+application/vnd.musician
+application/vnd.netfpx
+application/vnd.noblenet-directory
+application/vnd.noblenet-sealer
+application/vnd.noblenet-web
+application/vnd.novadigm.EDM
+application/vnd.novadigm.EDX
+application/vnd.novadigm.EXT
+application/vnd.osa.netdeploy
+application/vnd.pg.format
+application/vnd.pg.osasli
+application/vnd.powerbuilder6
+application/vnd.powerbuilder6-s
+application/vnd.powerbuilder7
+application/vnd.powerbuilder7-s
+application/vnd.powerbuilder75
+application/vnd.powerbuilder75-s
+application/vnd.previewsystems.box
+application/vnd.publishare-delta-tree
+application/vnd.rapid
+application/vnd.s3sms
+application/vnd.seemail
+application/vnd.shana.informed.formdata
+application/vnd.shana.informed.formtemplate
+application/vnd.shana.informed.interchange
+application/vnd.shana.informed.package
+application/vnd.street-stream
+application/vnd.svd
+application/vnd.swiftview-ics
+application/vnd.triscape.mxs
+application/vnd.trueapp
+application/vnd.truedoc
+application/vnd.ufdl
+application/vnd.uplanet.alert
+application/vnd.uplanet.alert-wbxml
+application/vnd.uplanet.bearer-choi-wbxml
+application/vnd.uplanet.bearer-choice
+application/vnd.uplanet.cacheop
+application/vnd.uplanet.cacheop-wbxml
+application/vnd.uplanet.channel
+application/vnd.uplanet.channel-wbxml
+application/vnd.uplanet.list
+application/vnd.uplanet.list-wbxml
+application/vnd.uplanet.listcmd
+application/vnd.uplanet.listcmd-wbxml
+application/vnd.uplanet.signal
+application/vnd.vcx
+application/vnd.vectorworks
+application/vnd.visio
+application/vnd.wap.sic
+application/vnd.wap.slc
+application/vnd.wap.wbxml	wbxml
+application/vnd.wap.wmlc	wmlc
+application/vnd.wap.wmlscriptc	wmlsc
+application/vnd.webturbo
+application/vnd.wrq-hp3000-labelled
+application/vnd.wt.stf
+application/vnd.xara
+application/vnd.xfdl
+application/vnd.yellowriver-custom-menu
+application/whoispp-query
+application/whoispp-response
+application/wita
+application/wordperfect5.1
+application/x-bcpio		bcpio
+application/x-cdlink		vcd
+application/x-chess-pgn		pgn
+application/x-compress
+application/x-cpio		cpio
+application/x-csh		csh
+application/x-director		dcr dir dxr
+application/x-dvi		dvi
+application/x-futuresplash	spl
+application/x-gtar		gtar
+application/x-gzip
+application/x-hdf		hdf
+application/x-javascript	js
+application/x-koan		skp skd skt skm
+application/x-latex		latex
+application/x-netcdf		nc cdf
+application/x-sh		sh
+application/x-shar		shar
+application/x-shockwave-flash	swf
+application/x-stuffit		sit
+application/x-sv4cpio		sv4cpio
+application/x-sv4crc		sv4crc
+application/x-tar		tar
+application/x-tcl		tcl
+application/x-tex		tex
+application/x-texinfo		texinfo texi
+application/x-troff		t tr roff
+application/x-troff-man		man
+application/x-troff-me		me
+application/x-troff-ms		ms
+application/x-ustar		ustar
+application/x-wais-source	src
+application/x400-bp
+application/xml
+application/zip			zip
+audio/32kadpcm
+audio/basic			au snd
+audio/l16
+audio/midi			mid midi kar
+audio/mpeg			mpga mp2 mp3
+audio/prs.sid
+audio/telephone-event
+audio/tone
+audio/vnd.cns.anp1
+audio/vnd.cns.inf1
+audio/vnd.digital-winds
+audio/vnd.everad.plj
+audio/vnd.lucent.voice
+audio/vnd.nortel.vbk
+audio/vnd.nuera.ecelp4800
+audio/vnd.nuera.ecelp7470
+audio/vnd.octel.sbc
+audio/vnd.qcelp
+audio/vnd.rhetorex.32kadpcm
+audio/vnd.vmx.cvsd
+audio/x-aiff			aif aiff aifc
+audio/x-pn-realaudio		ram rm
+audio/x-pn-realaudio-plugin	rpm
+audio/x-realaudio		ra
+audio/x-wav			wav
+chemical/x-pdb			pdb
+chemical/x-xyz			xyz
+image/bmp			bmp
+image/cgm
+image/g3fax
+image/gif			gif
+image/ief			ief
+image/jpeg			jpeg jpg jpe
+image/naplps
+image/png			png
+image/prs.btif
+image/prs.pti
+image/tiff			tiff tif
+image/vnd.cns.inf2
+image/vnd.dwg
+image/vnd.dxf
+image/vnd.fastbidsheet
+image/vnd.fpx
+image/vnd.fst
+image/vnd.fujixerox.edmics-mmr
+image/vnd.fujixerox.edmics-rlc
+image/vnd.mix
+image/vnd.net-fpx
+image/vnd.svf
+image/vnd.wap.wbmp		wbmp
+image/vnd.xiff
+image/x-cmu-raster		ras
+image/x-portable-anymap		pnm
+image/x-portable-bitmap		pbm
+image/x-portable-graymap	pgm
+image/x-portable-pixmap		ppm
+image/x-rgb			rgb
+image/x-xbitmap			xbm
+image/x-xpixmap			xpm
+image/x-xwindowdump		xwd
+message/delivery-status
+message/disposition-notification
+message/external-body
+message/http
+message/news
+message/partial
+message/rfc822
+message/s-http
+model/iges			igs iges
+model/mesh			msh mesh silo
+model/vnd.dwf
+model/vnd.flatland.3dml
+model/vnd.gdl
+model/vnd.gs-gdl
+model/vnd.gtw
+model/vnd.mts
+model/vnd.vtu
+model/vrml			wrl vrml
+multipart/alternative
+multipart/appledouble
+multipart/byteranges
+multipart/digest
+multipart/encrypted
+multipart/form-data
+multipart/header-set
+multipart/mixed
+multipart/parallel
+multipart/related
+multipart/report
+multipart/signed
+multipart/voice-message
+text/calendar
+text/css			css
+text/directory
+text/enriched
+text/html			html htm
+text/plain			asc txt
+text/prs.lines.tag
+text/rfc822-headers
+text/richtext			rtx
+text/rtf			rtf
+text/sgml			sgml sgm
+text/tab-separated-values	tsv
+text/t140
+text/uri-list
+text/vnd.DMClientScript
+text/vnd.IPTC.NITF
+text/vnd.IPTC.NewsML
+text/vnd.abc
+text/vnd.curl
+text/vnd.flatland.3dml
+text/vnd.fly
+text/vnd.fmi.flexstor
+text/vnd.in3d.3dml
+text/vnd.in3d.spot
+text/vnd.latex-z
+text/vnd.motorola.reflex
+text/vnd.ms-mediapackage
+text/vnd.wap.si
+text/vnd.wap.sl
+text/vnd.wap.wml		wml
+text/vnd.wap.wmlscript		wmls
+text/x-setext			etx
+text/xml			xml
+video/mpeg			mpeg mpg mpe
+video/pointer
+video/quicktime			qt mov
+video/vnd.fvt
+video/vnd.motorola.video
+video/vnd.motorola.videop
+video/vnd.vivo
+video/x-msvideo			avi
+video/x-sgi-movie		movie
+x-conference/x-cooltalk		ice

Propchange: incubator/mod_ftp/trunk/tests/conf/mime.types
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/conf/mod_specs.conf
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/conf/mod_specs.conf?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/conf/mod_specs.conf (added)
+++ incubator/mod_ftp/trunk/tests/conf/mod_specs.conf Thu Oct  6 06:16:28 2005
@@ -0,0 +1,12 @@
+<VirtualHost _default_:12346>
+
+FTP on
+
+FTPMaxLoginAttempts 3
+FTPTimeoutLogin     120
+FTPTimeoutIdle      600
+FTPTimeoutData      300
+
+LogLevel debug
+
+</VirtualHost>

Propchange: incubator/mod_ftp/trunk/tests/conf/mod_specs.conf
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/logs/.cvsignore
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/logs/.cvsignore?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/logs/.cvsignore (added)
+++ incubator/mod_ftp/trunk/tests/logs/.cvsignore Thu Oct  6 06:16:28 2005
@@ -0,0 +1,3 @@
+access_log
+error_log
+apache_scoreboard

Propchange: incubator/mod_ftp/trunk/tests/logs/.cvsignore
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/pytest.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/pytest.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/pytest.py (added)
+++ incubator/mod_ftp/trunk/tests/pytest.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,53 @@
+import traceback, time, string
+
+class Tester:
+    def __init__(self, log_file):
+        self._log_file = log_file
+        self.begin_testsuite()
+
+    def write_log(self, data):
+        self._log_file.write(data)
+
+    def end_testsuite(self):
+        self._log_file.write('\nTest suite ended at: %s\n' %
+                             (time.ctime(time.time())))
+
+    def begin_testsuite(self):
+        self._log_file.write('Test suite begun at: %s\n' %
+                             (time.ctime(time.time())))
+
+    def boxulate(self, s):
+        pad     = 3
+        mstrlen = 0
+        if type(s) == type(''):
+            s = [s]
+
+        mstrlen = max(map(lambda x: len(x), s))
+
+        # Fudge a few characters on each side
+        boxwidth = mstrlen + pad + pad
+        
+        res = ['+' + '-' * boxwidth + '+']
+        for sub in s:
+            res.append('|' + ' ' *pad + string.ljust(sub, mstrlen + pad) + '|')
+
+        res.append('+' + '-' * boxwidth + '+')
+        return string.join(res, '\n') + '\n'
+
+    def generate_test_header(self, testname):
+        header = [ 'Test: ' + testname, 'Time: ' + time.ctime(time.time()) ]
+        return self.boxulate(header) + '\n'
+
+    def run_test(self, testname, fn, arg, logfile=None):
+        real_log = logfile or self._log_file
+        try:
+            data = fn(arg)
+            if data:
+                real_log.write(data)
+            real_log.write('Test completed successfully\n\n')
+            return 0
+        except:
+            traceback.print_exc(file=real_log)
+            real_log.write('Test failed\n\n')
+            return -1
+

Propchange: incubator/mod_ftp/trunk/tests/pytest.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/.cvsignore
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/.cvsignore?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/.cvsignore (added)
+++ incubator/mod_ftp/trunk/tests/tests/.cvsignore Thu Oct  6 06:16:28 2005
@@ -0,0 +1,2 @@
+*.pyc
+

Propchange: incubator/mod_ftp/trunk/tests/tests/.cvsignore
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/aasetup.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/aasetup.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/aasetup.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/aasetup.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,92 @@
+#
+# Setup the FTP test environment.  This script must be run first.
+#
+# Naming conventions:
+# Directories are single letters, files are a number that corresponds to the
+# size of the file.
+#
+import string
+import basic
+import os
+import tempfile
+import random
+import time
+from stat import *
+
+# Max size at 20k for now.
+MAX_FILE_SIZE = 1024 * 20
+SETUP_COMPLETE = ".ftp_setup_complete"
+
+# Routine for directory creation
+def make_dirs(root):
+    dirs = string.letters
+    for i in range(26):
+        dir = os.path.join(root, dirs[i])
+        if not os.path.exists(dir):
+            os.mkdir(dir)
+
+# Routine for random file creation
+def make_files(root, num):
+    randfile = open("/dev/urandom")
+    for i in range(num):
+        size = random.random() * MAX_FILE_SIZE
+        buf = randfile.read(size)
+        filename = '%s/%s' %(root, int(size))
+        file = open(filename, 'w+')
+        file.write(buf)
+        file.close()
+
+# Create a named file
+def make_file(root, name):
+    randfile = open("/dev/urandom")
+    size = random.random() * MAX_FILE_SIZE
+    buf = randfile.read(size)
+    filename = '%s/%s' %(root, name)
+    file = open(filename, 'w+')
+    file.write(buf)
+    file.close()
+
+def file_remove(arg, top, names):
+    """Called from os.path.walk.  Deletes all files in the directory"""
+    for file in names:
+        abspath = os.path.join(top, file)
+        if not os.path.isdir(abspath):
+            os.remove(abspath)
+
+def dir_remove(arg, top, names):
+    """Called from os.path.walk.  Delete all directories in the directory"""
+    for dir in names:
+        abspath = os.path.join(top, dir)
+        os.rmdir(abspath)
+
+def test(arg):
+    """This is the setup script for all the FTP tests.  This script creates
+    a file system layout that other scripts will depend on.  Because of this
+    it is not recommended that you change the files or directories that are
+    created here without first looking at the other tests."""
+    x = arg.find_serverroot()
+    serverroot = x + '/htdocs'
+
+    if os.path.exists(serverroot):
+        os.path.walk(serverroot, file_remove, '')
+        os.path.walk(serverroot, dir_remove, '')
+        if not os.path.exists(serverroot):
+            os.mkdir(serverroot)
+    
+    # Make the top level directories
+    make_dirs(serverroot)
+
+    # Create 40 files in the top level directory
+    make_files(serverroot, 40)
+
+    # Create a file we know the name of for ABOR test
+    make_file(serverroot, 'aborfile')
+
+    # Create 10 files in each of the toplevel directories
+    dirs = string.letters
+    for i in range(26):
+        dir = os.path.join(serverroot, dirs[i])
+        if os.path.exists(dir):
+            make_files(dir, 10)
+    
+    return "FTP test environment created\n\n"

Propchange: incubator/mod_ftp/trunk/tests/tests/aasetup.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/abor.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/abor.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/abor.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/abor.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,38 @@
+import basic, string
+
+def send_abor(conn):
+    conn.send_command('ABOR')
+
+def send_retr(conn, file):
+    conn.send_command('RETR', file)
+
+def send_pasv(conn):
+    conn.send_command('PASV')
+
+def dotest():
+    x = basic.FTPControl()
+    x.login()
+
+    # Request a passive connection
+    send_pasv(x)
+
+    # Request a file we know exists
+    send_retr(x, 'aborfile')
+  
+    # Immediately send an ABOR
+    send_abor(x)
+
+def test(arg):
+    """This is the test for the ABOR command.  This test will
+    initiate a RETR, but then ABOR before opening a data
+    connection.  This test is to demonstrate the errors seen
+    at Cisco"""
+
+    x = basic.FTPControl()
+    x.login()
+
+    for i in range(25):
+        dotest()
+        
+    res = 'command: ABOR \nreturned: OK\n\n'
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/abor.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/basic.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/basic.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/basic.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/basic.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,190 @@
+#
+# Login test -- Checks basic login functionality, and is used by all
+#               the other testing modules to test login functionality.
+
+import string
+from socket import *
+
+CRLF = '\r\n'
+CR = '\r'
+LF = '\n'
+
+RFCvals = { "Connect" : ( {(120,) : (220,) }, 220, 421 ),
+            "USER"    : (230,530,500,501,421,331,332),
+            "PASS"    : (230,202,530,500,501,503,421,332),
+            "ACCT"    : (230,202,540,500,501,503,421),
+            "CWD"     : (250,500,501,502,421,530,550),
+            "CDUP"    : (200,500,501,502,421,530,550),
+            "SMNT"    : (202,250,500,501,502,421,530,550),
+            "REIN"    : ( {(120,) : (220,) }, 220, 421, 500, 502),
+            "QUIT"    : (221, 500),
+            "PORT"    : (200, 500, 501, 421, 530),
+            "PASV"    : (227, 500, 501, 502, 421, 530),
+            "MODE"    : (200, 500, 501, 504, 421, 530),
+            "TYPE"    : (200, 500, 501, 504, 421, 530),
+            "STRU"    : (200, 500, 501, 504, 421, 530),
+            "ALLO"    : (200, 202, 500, 501, 504, 421, 530),
+            "REST"    : (500, 501, 502, 421, 530, 350),
+            "STOR"    : ({(125, 150):(110, 226, 250, 425, 426, 451, 551,552)},
+                         532, 450, 452, 553, 500, 501, 421, 530),
+            "STOU"    : ({(125, 150):(110, 226, 250, 425, 426, 451, 551,552)},
+                         532, 450, 452, 553, 500, 501, 421, 530),
+            "RETR"    : ({(125, 150):(110, 226, 250, 425, 426, 451)},
+                         450, 550, 500, 501, 421, 530),
+            "LIST"    : ({(125, 150):(226,250,425,426,451)},
+                         450, 500, 501, 502, 421, 530),
+            "NLST"    : ({(125, 150):(226,250,425,426,451)},
+                         425, 450, 500, 501, 502, 421, 530),
+            "APPE"    : ({(125, 150):(110,226,250,425,426,451,551,552)},
+                         450, 500, 501, 502, 421, 530),
+            "RNFR"    : (450,550,500,501,502,421,530,350),
+            "RNTO"    : (250,532,553,500,501,502,503,421,530),
+            "DELE"    : (250,450,550,500,501,502,421,530),
+            "RMD"     : (250,500,501,502,421,530,550),
+            "MKD"     : (257,500,501,502,421,530,550),
+            "PWD"     : (257,500,501,502,421,530,550),
+            "ABOR"    : (225,226,426,500,501,502,421),
+            "SYST"    : (215,500,501,502,421),
+            "STAT"    : (211,212,213,450,500,501,502,421,530),
+            "HELP"    : (211,214,500,501,502,421),
+            "SITE"    : (200,202,500,501,530),
+            "NOOP"    : (200,500,421),
+            }
+
+class FTPControl:
+    """FTPControl:  Base class for dealing with the FTP control connection"""
+    def __init__(self, host='localhost', port=12346):
+        self.sock = socket(AF_INET, SOCK_STREAM)
+        self.sock.connect((host, port))
+        self.sockf = self.sock.makefile('wb+')
+        self.passive = 0
+        self.port = 0
+        self.host = ''
+
+        rescode, msg = self.get_result()
+        if not self.response_is_valid("Connect", (rescode,)):
+            raise 'Invalid response to connection'
+        
+    def send_command(self, *args):
+        cmd = args[0]
+        if len(args) > 1:
+            argstr = ' ' + string.join(args[1:], ' ')
+        else:
+            argstr = ''
+
+        self.sockf.write('%s%s%s' % (cmd, argstr, CRLF))
+
+        
+    def response_is_valid(self, cmd, rescodes):
+        """response_is_valid(cmd,rescodes):  Return 1 if the response codes
+        are valid for a given command, 0 if not"""
+
+        if len(rescodes) == 1:
+            return rescodes[0] in RFCvals[cmd]
+
+        for val in filter(lambda x:type(x)==type({}), RFCvals[cmd]):
+            for key in val.keys():
+                if rescodes[0] in key:
+                    return rescodes[1] in val[key]
+        return 0
+
+    def error_perm(self, code):
+        """error_perm(code): Check if a permanent error has occured"""
+        if (code >= 500 and code < 600):
+            return 1
+        else:
+            return 0
+
+    def error_temp(self, code):
+        """error_temp(code): Check if a temporary error has occured"""
+        if (code >= 400 and code < 500):
+            return 1
+        else:
+            return 0
+    
+    def get_result(self):
+        """get_result():  Get the result from the previous sent
+        FTP command.  See rfc959, section 4.2"""
+        line = self.sockf.readline()
+        if line[-2:] != CRLF:
+            raise 'No CRLF at the end of a response'
+        if len(line) < 4:
+            raise 'Malformed result'
+
+        resmsg = [line,]
+        rescode = line[:3]
+        if line[3] == '-':
+            while 1:
+                line = self.sockf.readline()
+                if line[-2:] != CRLF:
+                    raise 'No CRLF at the end of a response line'
+                resmsg.append(line)
+                if line[:4] == rescode + ' ':
+                    break
+        
+        return int(rescode), resmsg
+    
+    def login(self, user='anonymous', password='BLAH'):
+        self.send_command('USER', user)
+        code, msg = self.get_result()
+        if not self.response_is_valid("USER", (code,)):
+            raise "Invalid response from USER", code
+
+        self.send_command('PASS', password)
+        code, msg = self.get_result()
+        if not self.response_is_valid("PASS", (code,)):
+            raise "Invalid response from PASS", code
+
+    def logout(self):
+        self.send_command('QUIT')
+        code, msg = self.get_result()
+        if not self.response_is_valid("QUIT", (code,)):
+            raise 'Invalid response from QUIT'
+
+    def create_portstring(self, host, port):
+        res   = string.replace(host, '.', ',')
+        low8  = port & 0x00ff
+        high8 = (port & 0xff00) >> 8
+        return '%s,%d,%d' % (res, high8, low8)
+
+    def parse_portstring(self, msg):
+        """Return an ip address and port based on a PASV response"""
+        if msg[:3] <> '227':
+            raise 'Invalid string passed to parse_portstring', msg
+        left = string.find(msg, '(')
+        right = string.find(msg, ')', left + 1)
+        numbers = string.split(msg[left+1:right], ',')
+        host = string.join(numbers[:4], '.')
+        port = (string.atoi(numbers[4]) << 8) + string.atoi(numbers[5])
+        return host, port
+    
+    def setup_dataconn(self, passive=0):
+        x = socket(AF_INET, SOCK_STREAM)
+        if not passive:
+            x.bind(('', 0))
+            x.listen(10)
+            z, port = x.getsockname()
+            host, z = self.sock.getsockname()
+            portstr = self.create_portstring(host, port)
+            self.send_command('PORT', portstr)
+            code, msg = self.get_result()
+            if not self.response_is_valid('PORT', (code,)):
+                raise 'Invalid response from PORT'
+        else:
+            self.send_command('PASV')
+            code, msg = self.get_result()
+            if not self.response_is_valid('PASV', (code,)):
+                raise 'Invalid response from PASV'
+            self.host, self.port = self.parse_portstring(msg[0])
+
+        return x
+
+def test(arg):
+    """This is the base class for most of the FTP operations.  The basic
+    class is used for setting up the control connection and logging in.
+    This class is also used for sending commands, reading responses and
+    setting up sockets."""
+    x = FTPControl()
+    x.login()
+    x.logout()
+    return None

Propchange: incubator/mod_ftp/trunk/tests/tests/basic.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/cd.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/cd.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/cd.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/cd.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,77 @@
+import basic, string, os
+
+# Note: CWD's outside of the document root will succeed as '/'.
+tests = ['../../../../../', 'a/../a/../', 'a/../b/../c/../d/..',
+         'a/././././', 'a/./../b/.' '/../../../', 'abcd', '.']
+
+def send_pwd(conn, dir):
+    conn.send_command('PWD')
+    code, msg = conn.get_result()
+    if not conn.response_is_valid("PWD", (code,)):
+        raise 'Invalid response from PWD', code
+    
+    newdir = string.split(msg[0], '"')
+    if newdir[1] != os.path.join('/', dir):
+        raise 'Incorrect response from PWD: ', newdir[1]
+    return code, msg
+
+def send_cdup(conn):
+    conn.send_command('CDUP')
+    code, msg = conn.get_result()
+    if not conn.response_is_valid("CDUP", (code,)):
+        #
+        # Many servers (e.g. wu-ftp) return 250 on a CDUP command.
+        # According to RFC959, this is not valid, but we let it
+        # slip by.
+        if code != 250:
+            raise 'Invalid response from CDUP', code
+    return code, msg
+
+def send_cwd(conn, dir):
+    conn.send_command('CWD', dir)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid("CWD", (code,)):
+        raise 'Invalid response from CWD', code
+    return code, msg
+
+def test(arg):
+    """This is the change directory test.  This tests change working
+    directory (CWD), change directory up (CDUP) and print working
+    directory (PWD).  These tests are performed on a known file system
+    layout, so sucess or failure is easy to detect.  If a failure is
+    found, an exception is raised, and the test will fail.  Otherwise
+    all commands and responses are printed to the log file."""
+    x = basic.FTPControl()
+    x.login()
+
+    # Buffer to hold our results
+    buf = ''
+
+    # First test known directories
+    dirs = string.letters
+    for i in range(26):
+
+        code, msg = send_cwd(x, dirs[i])
+        buf = '%scommand: %s%s \nreturned: \n%s\n\n' %(buf, 'CWD ', dirs[i],
+                                                       string.join(msg))
+        code, msg = send_pwd(x, dirs[i])
+        buf = '%scommand: %s \nreturned: \n%s\n\n' %(buf, 'PWD',
+                                                     string.join(msg))
+        code, msg = send_cdup(x)
+        buf = '%scommand: %s \nreturned: \n%s\n\n' %(buf, 'CDUP',
+                                                     string.join(msg))
+        code, msg = send_pwd(x, '')
+        buf = '%scommand: %s \nreturned: \n%s\n\n' %(buf, 'PWD',
+                                                     string.join(msg))
+    
+    # Other random tests
+    for test in tests:
+        code, msg = send_cwd(x, test)
+        buf = '%scommand: %s \nreturned: \n%s\n\n' %(buf, 'CWD',
+                                                     string.join(msg))
+        code ,msg = send_cwd(x, '/')
+        buf = '%scommand: %s \nreturned: \n%s\n\n' %(buf, 'PWD',
+                                                     string.join(msg))
+ 
+    x.logout()
+    return string.replace(buf, '\r\n', '\n') 

Propchange: incubator/mod_ftp/trunk/tests/tests/cd.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/dele.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/dele.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/dele.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/dele.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,62 @@
+import basic, string
+
+def send_cwd(conn, dir):
+    conn.send_command('CWD', dir)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('CWD', (code,)):
+        raise 'Invalid response from CWD', code
+
+def send_nlst(conn, dataconn, args):
+    """Sends an NLST command with the given pattern.  Returns a list
+    of files that were found."""
+
+    conn.send_command('NLST', args)
+    code1, msg = conn.get_result()
+    if conn.error_perm(code1):
+        return
+    code2, msg = conn.get_result()
+    if not conn.response_is_valid("NLST", (code1, code2)):
+        raise 'Invalid response from NLST'
+    if conn.error_perm(code2):
+        return
+
+    c, d = dataconn.accept()
+    
+    list = string.split(c.recv(10240), '\r\n')
+
+    # We don't want to return any empty entries.
+    for item in list:
+        if item == '':
+            list.remove(item)
+    return list
+
+def test(arg):
+    """This is the test for the delete command.  This test will change into
+    a directory and remove all files.  If all files are not removed, an
+    exception is raised.  All commands and results are printed to the log
+    file"""
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    send_cwd(x, 'a')
+
+    passive_sock = x.setup_dataconn(passive=0)
+    files = send_nlst(x, passive_sock, '*')
+
+    for file in files:
+        x.send_command('DELE', file)
+        code, msg = x.get_result()
+        if not x.response_is_valid('DELE', (code,)):
+            raise 'Invalid response from DELE', code
+
+        res = '%scommand: DELE %s \nreturned: \n%s\n\n' %(res, file,
+                                                          string.join(msg)) 
+
+    passive_sock = x.setup_dataconn(passive=0)
+    files = send_nlst(x, passive_sock, '*')
+    if len(files) != 0:
+        raise 'Error, DELE did not remove all files.', files
+    
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/dele.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/help.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/help.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/help.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/help.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,30 @@
+import basic, string
+
+tests = ['STOR', 'REST', 'MKD', 'RMD', 'NOOP', 'INVALID_METHOD']
+
+def send_help(conn, command=''):
+    conn.send_command('HELP', command)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('HELP', (code,)):
+        raise 'Invalid response from HELP', code
+    return code, msg
+
+def test(arg):
+    """This is the test for the TYPE command.  A few tests are sent
+    and the result code is checked."""
+
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    # First send a help message with no arguments.
+    code, msg = send_help(x)
+    res = '%scommand: HELP \nreturned: \n%s\n\n' %(res, string.join(msg))
+
+    # Run through our test cases.
+    for test in tests:
+        code, msg = send_help(x, test)
+        res = '%scommand: HELP %s\nreturned: \n%s\n\n' %(res, test, string.join(msg))
+
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/help.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/list.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/list.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/list.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/list.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,44 @@
+import basic, string, os
+
+# Array of test cases to be passed to LIST
+tests = ['*', '*.html', '2*2', '3*', '*3', 'a*', '*i*', 'a/*',
+         '*.*', '9*', 'q', 'b', 'a*b', 'b*', 'q*', '*q', '12*']
+
+def send_valid_list(conn, dataconn, args):
+    conn.send_command('LIST', args)
+    code1, msg = conn.get_result()  # get the intro message
+    # Return if we detect a permanent error.
+    if conn.error_perm(code1):
+        return
+    code2, msg = conn.get_result()  # Get the real sending message
+    if not conn.response_is_valid("LIST", (code1, code2)):  
+        raise 'Invalid response from LIST', (code1, code2)
+    if conn.error_perm(code2):
+        return
+    
+    c, d = dataconn.accept()
+
+    return map(lambda x: string.replace(x, '\r\n', '\n'),
+                 string.split(c.recv(10240), ' '))
+
+def test(arg):
+    """This is the file list test.  This test runs LIST with a predefined
+    set of arguments.  The command and its output are all printed to the
+    log file.  Checking of the output is not done."""
+    x = basic.FTPControl()
+    x.login()
+    
+    res = ''
+    for test in tests:
+        passive_sock = x.setup_dataconn(passive=0)
+
+    	files = send_valid_list(x, passive_sock, test)
+ 
+        if files == None:
+            res = '%scommand: LIST %s \nreturned: \n%s\n\n' %(res, test, files)
+        else:
+            output = string.join(files)
+            res = '%scommand: LIST %s \nreturned: \n%s\n\n' %(res, test, output)
+
+    x.logout()
+    return res

Propchange: incubator/mod_ftp/trunk/tests/tests/list.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/mdtm.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/mdtm.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/mdtm.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/mdtm.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,54 @@
+import basic, string
+
+def send_mdtm(conn, file):
+    conn.send_command('MDTM', file)
+    code, msg = conn.get_result()
+    #
+    # MDTM is not in our RFC vals since it is not defined in 959.
+    # 
+    #if not conn.response_is_valid('MDTM', (code,)):
+    #    raise 'Invalid response from MDTM', code
+
+    return code, msg
+
+def get_filelist(conn, dataconn, args):
+    """Uses NLST to get a list of files to be checked."""
+
+    conn.send_command('NLST', args)
+    code1, msg = conn.get_result()
+    if conn.error_perm(code1):
+        return
+    code2, msg = conn.get_result()
+    if not conn.response_is_valid("NLST", (code1, code2)):
+        raise 'Invalid response from NLST'
+    if conn.error_perm(code2):
+        return
+
+    c, d = dataconn.accept()
+    
+    list = string.split(c.recv(10240), '\r\n')
+
+    # We don't want to return any empty entries.
+    for item in list:
+        if item == '':
+            list.remove(item)
+    return list
+
+def test(arg):
+    """This is the test for the MDTM command."""
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    passive_sock = x.setup_dataconn(passive=0)
+    files = get_filelist(x, passive_sock, '*')
+
+    for file in files:
+        code, msg = send_mdtm(x, file)
+        res = '%scommand: MDTM %s \nreturned: \n%s\n\n' %(res, file,
+                                                          string.join(msg)) 
+
+        # XXX: check results
+    
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/mdtm.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/mkd.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/mkd.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/mkd.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/mkd.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,34 @@
+import basic, string, os
+
+def send_mkd(conn, dir):
+    conn.send_command('MKD', dir)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('MKD', (code,)):
+        raise 'Invalid response from MKD', code
+
+    return code, msg
+
+def test(arg):
+    """This is the test for the mkdir command.  This test creates
+    26 new directories aa - az.  The test also verifies that the
+    directories were actually created.  These directories are
+    deleted by the rmd test."""
+    
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    dirs = string.letters
+    for i in range(26):
+        dir = 'a' + dirs[i]
+        code, msg = send_mkd(x, dir)
+        res = '%scommand: MKD %s \nreturned: \n%s\n\n' %(res, dir, msg[0])
+
+        # Check the filesystem if the directory was actually created
+        documentroot = arg.find_serverroot() + '/htdocs'
+        path = os.path.join(documentroot, dir)
+        if not os.path.exists(path):
+            raise 'Directory not created', path
+
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/mkd.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/nlst.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/nlst.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/nlst.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/nlst.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,73 @@
+import basic, string, os, glob
+
+# Array of test cases to be passed to NLST
+tests = ['*', '*.html', '2*2', '3*', '*3', 'a*', '*i*', 'a* b*',
+         '*.*', '9*', 'q', 'b', 'a*b', 'b*', 'q*', '*q', '12*']
+
+def send_bogus_nlst(conn):
+    # First send a request even without a port given
+    # should return a 425
+    conn.send_command('NLST')
+    code, msg = conn.get_result()
+    if not conn.response_is_valid("NLST", (code,)):  # Verify RFC standard
+        raise 'Invalid response from NLST', code
+    if code != 425:
+        raise 'Expected return value not found'
+
+def send_valid_nlst(conn, dataconn, args):
+    conn.send_command('NLST', args)
+    code1, msg = conn.get_result()  # get the intro message
+    # Return if we detect a permanent error.
+    if conn.error_perm(code1):
+        return
+    code2, msg = conn.get_result()  # Get the real sending message
+    if not conn.response_is_valid("NLST", (code1, code2)):  
+        raise 'Invalid response from NLST', (code1, code2)
+    if conn.error_perm(code2):
+        return
+    
+    c, d = dataconn.accept()
+
+    return map(lambda x: string.replace(x, '\r\n', '\n'),
+                 string.split(c.recv(10240), ' '))
+
+def test(arg):
+    """This is the file list test.  The purpose of NLST is to return a list
+    of files to the client.  The client usually issues NLST requests for
+    multiple gets.  This test runs NLST with a predefined set of arguments.
+    The command and its output are all printed to the log file."""
+    x = basic.FTPControl()
+    x.login()
+    send_bogus_nlst(x)
+    res = ''
+    for test in tests:
+        passive_sock = x.setup_dataconn(passive=0)
+
+    	files = send_valid_nlst(x, passive_sock, test)
+        
+        # Find which files NLST should actually return
+        matches = []
+        path = arg.find_serverroot() + '/htdocs/' + test
+        list = glob.glob(path)
+        list.sort()
+        for item in list:
+            if not os.path.isdir(item):
+                matches.append(os.path.basename(item))
+                
+        if files == None:
+            res = '%scommand: NLST %s \nreturned: \n%s\n\n' %(res, test, files)
+        else:
+            # First convert the output to a list
+            filelist = string.split(files[0], '\n')
+            for item in filelist:
+                if item == '':
+                    filelist.remove(item)
+
+            # Check that the lists are identical.
+            if filelist != matches:
+                'raise NLST returned unexpected values', filelist
+            
+            res = '%scommand: NLST %s \nreturned: \n%s\n\n' %(res, test, files[0])
+
+    x.logout()
+    return res

Propchange: incubator/mod_ftp/trunk/tests/tests/nlst.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/noop.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/noop.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/noop.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/noop.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,21 @@
+import basic, string
+
+def send_noop(conn):
+    conn.send_command('NOOP')
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('NOOP', (code,)):
+        raise 'Invalid response from NOOP', code
+    return code, msg
+
+def test(arg):
+    """This is the test for the NOOP command.  All this does is send a
+    NOOP command and check the return code.  Nothing too complicated."""
+
+    x = basic.FTPControl()
+    x.login()
+
+    code, msg = send_noop(x)
+
+    res = 'command: NOOP \nreturned: \n%s\n\n' %(string.join(msg))
+
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/noop.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/rename.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/rename.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/rename.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/rename.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,73 @@
+import basic, string, os
+
+def send_rnfr(conn, file):
+    conn.send_command('RNFR', file)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid("RNFR", (code,)):
+        raise 'Invalid response from RNFR', code
+    
+    return code, msg
+
+def send_rnto(conn, file):
+    conn.send_command('RNTO', file)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid("RNTO", (code,)):
+        raise 'Invalid response from RNTO', code
+    
+    return code, msg
+
+def test(arg):
+    """This is the rename test.  The rename operation is defined in
+    a sequence of commands in the FTP protocol.  RNFR 'file' tells
+    the server we want to rename the file 'file'.  This command must
+    be followed by a RNTO command that will tell the server what the
+    new file name should be.  If these commands happen out of sequence,
+    a sequence error (503) should be returned."""
+
+    x = basic.FTPControl()
+    x.login()
+
+    # Buffer to hold our results
+    buf = ''
+
+    # Let's rename all the known directories
+    dirs = string.letters
+    for i in range(26):
+        newfile = 'renamed' + dirs[i]
+
+        # First let's rename
+        code, msg = send_rnfr(x, dirs[i])
+        buf = '%scommand: %s %s \nreturned: \n%s\n\n' %(buf, 'RNFR', dirs[i],
+                                                       string.join(msg))
+        
+        code, msg = send_rnto(x, newfile)
+        
+        buf = '%scommand: %s %s \nreturned: \n%s\n\n' %(buf, 'RNTO', newfile,
+                                                     string.join(msg))
+
+        # Now rename them back
+        code, msg = send_rnfr(x, newfile)
+        buf = '%scommand: %s %s \nreturned: \n%s\n\n' %(buf, 'RNFR', newfile,
+                                                       string.join(msg))
+        
+        code, msg = send_rnto(x, dirs[i])
+        buf = '%scommand: %s %s \nreturned: \n%s\n\n' %(buf, 'RNTO', dirs[i],
+                                                     string.join(msg))
+    # Test out of sequence condition
+    newfile = 'sequence_test'
+    code, msg = send_rnto(x, newfile)
+    buf = '%scommand: %s %s\nreturned: \n%s\n\n' %(buf, 'RNTO', newfile,
+                                                 string.join(msg))
+    if code != 503:
+        raise 'Incorrect response from RNTO', code
+
+    # Test rename of a non-existant file
+    newfile = 'foo'
+    code, msg = send_rnfr(x, newfile)
+    buf = '%scommand: %s %s\nreturned: \n%s\n\n' %(buf, 'RNFR', newfile,
+                                                   string.join(msg))
+    if code != 550:
+        raise 'Incorrect response from RNFR', code
+    
+    x.logout()
+    return string.replace(buf, '\r\n', '\n') 

Propchange: incubator/mod_ftp/trunk/tests/tests/rename.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/rest.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/rest.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/rest.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/rest.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,26 @@
+import basic, string
+
+tests = ['0', '1000', '-1000', 'invalid', '100000000000000']
+
+def send_rest(conn, offset):
+    conn.send_command('REST', offset)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('REST', (code,)):
+        raise 'Invalid response from REST', code
+    return code, msg
+
+def test(arg):
+    """This is the tests for the REST command.  For now only the result
+    code is checked."""
+
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    for test in tests:
+        code, msg = send_rest(x, test)
+        res = '%scommand: REST %s\nreturned: \n%s\n\n' %(res, test,
+                                                         string.join(msg))
+
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/rest.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/rmd.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/rmd.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/rmd.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/rmd.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,35 @@
+import basic, string, os
+
+def send_rmd(conn, dir):
+    conn.send_command('RMD', dir)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('RMD', (code,)):
+        raise 'Invalid response from RMD', code
+
+    return code, msg
+
+def test(arg):
+    """This is the test for the rmdir command.  This test relies on the
+    mkdir test to create the directories to be deleted.  The directories
+    aa - az are deleted.  If we detect a bad response, or if a directory
+    is not deleted we raise an error."""
+    
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    dirs = string.letters
+    for i in range(26):
+        dir = 'a' + dirs[i]
+        code, msg = send_rmd(x, dir)
+        res = '%scommand: RMD %s \nreturned: \n%s\n\n' %(res, dir,
+                                                         string.join(msg))
+
+        # Check the filesystem if the directory was actually created
+        documentroot = arg.find_serverroot() + '/htdocs'
+        path = os.path.join(documentroot, dir)
+        if os.path.exists(path):
+            raise 'Directory not deleted', path
+
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/rmd.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/size.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/size.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/size.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/size.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,60 @@
+import basic, string
+
+def send_size(conn, file):
+    conn.send_command('SIZE', file)
+    code, msg = conn.get_result()
+    #
+    # SIZE is not in our RFC vals since it is not defined in 959.
+    # 
+    #if not conn.response_is_valid('SIZE', (code,)):
+    #    raise 'Invalid response from SIZE', code
+
+    return code, msg
+
+def get_filelist(conn, dataconn, args):
+    """Uses NLST to get a list of files to be checked."""
+
+    conn.send_command('NLST', args)
+    code1, msg = conn.get_result()
+    if conn.error_perm(code1):
+        return
+    code2, msg = conn.get_result()
+    if not conn.response_is_valid("NLST", (code1, code2)):
+        raise 'Invalid response from NLST'
+    if conn.error_perm(code2):
+        return
+
+    c, d = dataconn.accept()
+    
+    list = string.split(c.recv(10240), '\r\n')
+
+    # We don't want to return any empty entries.
+    for item in list:
+        if item == '':
+            list.remove(item)
+    return list
+
+def test(arg):
+    """This is the test for the SIZE command."""
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    passive_sock = x.setup_dataconn(passive=0)
+    files = get_filelist(x, passive_sock, '*')
+
+    for file in files:
+        if file == 'aborfile':
+            continue
+        code, msg = send_size(x, file)
+        size = string.split(string.replace(msg[0], '\r\n', ''), ' ')[-1:]
+
+        # Check to see if the size was what we expected.
+        if size[0] != file:
+            raise 'SIZE returned unexpected value', size[0]
+        
+        res = '%scommand: SIZE %s \nreturned: \n%s\n\n' %(res, file,
+                                                          string.join(msg)) 
+    
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/size.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/syst.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/syst.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/syst.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/syst.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,32 @@
+import basic, string
+
+def send_syst(conn):
+    conn.send_command('SYST')
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('SYST', (code,)):
+        raise 'Invalid response from SYST', code
+    return code, msg
+
+def test(arg):
+    """This is the test for the SYST command.  According to RFC 959 SYST
+    must return a name from the official names list defined in RFC 943,
+    but these seem rather worthless.  These are not currently checked."""
+
+    x = basic.FTPControl()
+    x.login()
+
+    # Official system names from RFC 943... these sure seem worthless.
+    offical_names = ['ASP', 'AUGUST', 'BKY', 'CCP', 'DOS/360', 'ELF',
+                     'EPOS', 'EXEC-8', 'GCOS', 'ITS', 'INTERCOM',
+                     'INTERLISP', 'KRONOS', 'MCP', 'MOS', 'MPX-RT',
+                     'MULTICS', 'MVT', 'NOS', 'NOS/BE', 'OS/MVS',
+                     'OS/MVT', 'RIG', 'RSX-11M', 'RT11', 'SCOPE',
+                     'SIGNAL', 'SINTRAN', 'TAC', 'TENEX', 'TOPS-10',
+                     'TOPS-20', 'TSS', 'UNIX', 'VM/370', 'VM/CMS',
+                     'VMS', 'WAITS', 'XDE']
+    
+    code, msg = send_syst(x)
+    
+    res = 'command: SYST \nreturned: \n%s\n\n' %(string.join(msg))
+    
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/syst.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/tests/tests/type.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/tests/tests/type.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/tests/tests/type.py (added)
+++ incubator/mod_ftp/trunk/tests/tests/type.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,27 @@
+import basic, string
+
+# Different types we could come across. (and some we shouldn't)
+tests = ['A', 'B', 'I', 'E', 'ASCII', 'BINARY', 'FOO']
+
+def send_type(conn, type):
+    conn.send_command('TYPE', type)
+    code, msg = conn.get_result()
+    if not conn.response_is_valid('TYPE', (code,)):
+        raise 'Invalid response from TYPE', code
+    return code, msg
+
+def test(arg):
+    """This is the test for the TYPE command.  A few tests are sent
+    and the result code is checked."""
+
+    x = basic.FTPControl()
+    x.login()
+
+    res = ''
+
+    for test in tests:
+        code, msg = send_type(x, test)
+        res = '%scommand: TYPE \nreturned: \n%s\n\n' %(res,
+                                                       string.join(msg))
+
+    return string.replace(res, '\r\n', '\n')

Propchange: incubator/mod_ftp/trunk/tests/tests/type.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/utils/ftp_proxy/.cvsignore
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/utils/ftp_proxy/.cvsignore?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/utils/ftp_proxy/.cvsignore (added)
+++ incubator/mod_ftp/trunk/utils/ftp_proxy/.cvsignore Thu Oct  6 06:16:28 2005
@@ -0,0 +1 @@
+*.pyc

Propchange: incubator/mod_ftp/trunk/utils/ftp_proxy/.cvsignore
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/utils/ftp_proxy/ftp_proxy.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/utils/ftp_proxy/ftp_proxy.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/utils/ftp_proxy/ftp_proxy.py (added)
+++ incubator/mod_ftp/trunk/utils/ftp_proxy/ftp_proxy.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,121 @@
+# A wimpy FTP Proxy
+# JMT April-16-01 (Tax day)
+# Don't try to read this code, its a mess
+
+import string, re, thread, select, UserList
+from transfer_pair import TransferPair, TransferFilter
+from SocketServer import *
+from sys import *
+from socket import *
+
+PassiveCheck = re.compile('227 .*\(([0-9]+,[0-9]+,[0-9]+,[0-9]+),([0-9]+),([0-9]+)\)')
+
+BLOCKSIZE = 10240
+
+def dbg_msg(msg):
+    stderr.write('FTPProxy: %s\n' % msg)
+    
+class PassiveFilter(TransferFilter):
+    def __init__(self, handler):
+        self.buf     = ''
+        self.handler = handler
+
+    def filter(self, data, tosock, output, sockname):
+        res = ''
+        while 1:
+            idx = string.find(data, '\r\n')
+            if idx == -1:
+                self.buf = self.buf + data
+                break
+            self.buf = self.buf + data[:idx+2]
+            data = data[idx+2:]
+
+            match = PassiveCheck.match(self.buf)
+            if match:
+                ip, highport, lowport = map(
+                    lambda (beg, end), s=self.buf: s[beg:end],
+                    match.regs[1:])
+                ip   = string.replace(ip, ',', '.')
+                port = (int(highport) << 8) + int(lowport)
+                server_sock = socket(AF_INET, SOCK_STREAM)
+                server_sock.connect((ip, port))
+                
+                sock = socket(AF_INET, SOCK_STREAM)
+                sock.bind(('', 0))
+                sock.listen(10)
+                proxy_ip = string.replace(self.handler.conn_ip, ".", ",")
+                proxy_port = sock.getsockname()[1]
+                res = res + '227 Entering Passive Mode (%s,%d,%d)\r\n' % (
+                    proxy_ip, proxy_port >> 8, proxy_port & 0x00ff)
+                output('Data sent to %s: "%s"' % (sockname, res))
+                tosock.send(res)
+                res = ''
+                sock, z = sock.accept()
+
+                tpair = TransferPair(server_sock, 'server->proxy(Passive)',
+                                     sock, 'proxy->client(Passive)',
+                                     output)
+                self.handler.add_tpair(server_sock, sock, tpair)
+            else:
+                res = res + self.buf
+
+            self.buf = ''
+                
+        if len(res):
+            output('Data sent to %s: "%s"' % (sockname, res))
+            tosock.send(res)
+
+
+class FTPRequestHandler(StreamRequestHandler):
+    def add_tpair(self, sock1, sock2, tpair):
+        self.active_sockets.extend([sock1, sock2])
+        self.transfer_pairs.append(tpair)
+        
+    def handle(self):
+        request = self.request
+        self.conn_ip = request.getsockname()[0]
+        dbg_msg('Client connected (%s)' % self.client_address[0])
+        svr = socket(AF_INET, SOCK_STREAM)
+        svr.connect((self.server.ftp_host, self.server.ftp_port))
+        dbg_msg('Connected to real server')
+
+        tpair = TransferPair(request, 'client->proxy', svr, 'proxy->server',
+                             dbg_msg)
+        tpair.add_filter(PassiveFilter(self).filter)
+        self.transfer_pairs = [tpair]
+        self.active_sockets = [request, svr]
+        while len(self.active_sockets):
+            rfds, z, z = select.select(self.active_sockets, [], [])
+            for tpair in self.transfer_pairs:
+                if tpair.do_transfer(rfds, self.active_sockets):
+                    del self.transfer_pairs[self.transfer_pairs.index(tpair)]
+                    
+    def finish(self):
+        dbg_msg('Client finished (%s)' % self.client_address[0])
+        
+
+class FTPProxyServer(ThreadingMixIn, TCPServer):
+    def __init__(self, *args, **kwargs):
+        self.ftp_host = kwargs['ftp_host']
+        self.ftp_port = kwargs['ftp_port']
+        del kwargs['ftp_host']
+        del kwargs['ftp_port']
+        apply(TCPServer.__init__, (self,)+args, kwargs)
+
+    def server_bind(self):
+        TCPServer.server_bind(self)
+        # Make sure we can reuse this address 
+        self.socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
+        
+if __name__ == '__main__':
+    if len(argv) != 4:
+        sys.stderr.write('Syntax: %s <proxy_port> <real_host> <real_port>\n' %(
+            argv[0],))
+        sys.exit(1)
+        
+    x = FTPProxyServer(('', int(argv[1])), FTPRequestHandler, ftp_host=argv[2],
+                       ftp_port=int(argv[3]))
+
+    dbg_msg('Starting proxy on port %s' % (argv[1]))
+    dbg_msg('Real host is %s:%s' % (argv[2], argv[3]))
+    x.serve_forever()

Propchange: incubator/mod_ftp/trunk/utils/ftp_proxy/ftp_proxy.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/utils/ftp_proxy/transfer_pair.py
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/utils/ftp_proxy/transfer_pair.py?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/utils/ftp_proxy/transfer_pair.py (added)
+++ incubator/mod_ftp/trunk/utils/ftp_proxy/transfer_pair.py Thu Oct  6 06:16:28 2005
@@ -0,0 +1,55 @@
+from UserList import UserList
+
+BLOCKSIZE = 10240
+
+class TransferPair:
+    def __init__(self, sock1, sock1name, sock2, sock2name, output_routine):
+        self.__sock1  = sock1
+        self.__sock2  = sock2
+        self.__names  = { sock1 : sock1name, sock2 : sock2name }
+        self.__output = output_routine
+        self.filters  = []
+        
+    def _send_data(self, data, tosock):
+        if not len(self.filters):
+            self.__output('Data sent to %s: "%s"' % (self.__names[tosock],
+                                                     data))
+            tosock.send(data)
+        else:
+            for filter in self.filters:
+                filter(data, tosock, self.__output, self.__names[tosock])
+
+    def _do_transfer(self, fromsock, tosock):
+        data = fromsock.recv(BLOCKSIZE)
+        if not len(data):
+            self.__output('%s closed connection' % (self.__names[fromsock]))
+            fromsock.close()
+            self.__output('Closing connection %s' % (self.__names[tosock]))
+            tosock.close()
+            return -1
+        else:
+            self._send_data(data, tosock)
+        
+    def do_transfer(self, selected, active_sockets):
+        deletion = 0
+        for sock in (self.__sock1, self.__sock2):
+            if sock in selected and sock in active_sockets and not deletion:
+                if sock == self.__sock1: othersock = self.__sock2
+                else: othersock = self.__sock1
+                if self._do_transfer(sock, othersock) == -1:
+                    deletion = 1
+
+        if deletion:
+            del active_sockets[active_sockets.index(self.__sock1)]
+            del active_sockets[active_sockets.index(self.__sock2)]
+
+        return deletion
+
+    def add_filter(self, filterfunc):
+        self.filters.append(filterfunc)
+
+
+class TransferFilter:
+    def filter(self, data, tosock, output, sockname):
+        pass
+

Propchange: incubator/mod_ftp/trunk/utils/ftp_proxy/transfer_pair.py
------------------------------------------------------------------------------
    svn:executable = 

Added: incubator/mod_ftp/trunk/utils/static_build/Makefile.in
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/utils/static_build/Makefile.in?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/utils/static_build/Makefile.in (added)
+++ incubator/mod_ftp/trunk/utils/static_build/Makefile.in Thu Oct  6 06:16:28 2005
@@ -0,0 +1 @@
+include $(top_srcdir)/build/special.mk

Added: incubator/mod_ftp/trunk/utils/static_build/README
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/utils/static_build/README?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/utils/static_build/README (added)
+++ incubator/mod_ftp/trunk/utils/static_build/README Thu Oct  6 06:16:28 2005
@@ -0,0 +1,10 @@
+The files in this directory can be used to compile the FTP module statically
+into Apache.  This procedure has not been automated, so you will need to do
+it by hand.
+
+Create the directory httpd-2.0/modules/ftp.  Copy the config.m4 and 
+Makefile.in files in this directory there.  Then copy all .c files from
+mod_ftp/src and all .h files from mod_ftp/include into httpd-2.0/modules/ftp.
+
+Change into the toplevel Apache directory, rerun buildconf, then configure
+with --enable-ftp.

Added: incubator/mod_ftp/trunk/utils/static_build/config.m4
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/utils/static_build/config.m4?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/utils/static_build/config.m4 (added)
+++ incubator/mod_ftp/trunk/utils/static_build/config.m4 Thu Oct  6 06:16:28 2005
@@ -0,0 +1,21 @@
+APACHE_MODPATH_INIT(ftp)
+
+ftp_objs="dnl
+ftp_commands.lo dnl
+ftp_data_connection.lo dnl
+ftp_data_filters.lo dnl
+ftp_connection.lo dnl
+ftp_filters.lo dnl
+ftp_glob.lo dnl
+ftp_inet_pton.lo dnl
+ftp_limitlogin.lo dnl
+ftp_log.lo dnl
+ftp_message.lo dnl
+ftp_protocol.lo dnl
+ftp_request.lo dnl
+ftp_util.lo dnl
+mod_ftp.lo"
+
+APACHE_MODULE(ftp, FTP Server, $ftp_objs, , no)
+
+APACHE_MODPATH_FINISH

Added: incubator/mod_ftp/trunk/utils/stresstest/.cvsignore
URL: http://svn.apache.org/viewcvs/incubator/mod_ftp/trunk/utils/stresstest/.cvsignore?rev=306631&view=auto
==============================================================================
--- incubator/mod_ftp/trunk/utils/stresstest/.cvsignore (added)
+++ incubator/mod_ftp/trunk/utils/stresstest/.cvsignore Thu Oct  6 06:16:28 2005
@@ -0,0 +1 @@
+*~