Commit b9e5da32 authored by Andreas Jung's avatar Andreas Jung

we *hate* tabs - lets get rid of them

parent 91134442
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: asynchat.py,v 1.16 2001/04/25 19:07:29 andreas Exp $ # $Id: asynchat.py,v 1.17 2001/05/01 11:44:48 andreas Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# ====================================================================== # ======================================================================
...@@ -270,20 +270,20 @@ class fifo: ...@@ -270,20 +270,20 @@ class fifo:
else: else:
return (0, None) return (0, None)
# Given 'haystack', see if any prefix of 'needle' is at its end. This # Given 'haystack', see if any prefix of 'needle' is at its end. This
# assumes an exact match has already been checked. Return the number of # assumes an exact match has already been checked. Return the number of
# characters matched. # characters matched.
# for example: # for example:
# f_p_a_e ("qwerty\r", "\r\n") => 1 # f_p_a_e ("qwerty\r", "\r\n") => 1
# f_p_a_e ("qwertydkjf", "\r\n") => 0 # f_p_a_e ("qwertydkjf", "\r\n") => 0
# f_p_a_e ("qwerty\r\n", "\r\n") => <undefined> # f_p_a_e ("qwerty\r\n", "\r\n") => <undefined>
# this could maybe be made faster with a computed regex? # this could maybe be made faster with a computed regex?
# [answer: no; circa Python-2.0, Jan 2001] # [answer: no; circa Python-2.0, Jan 2001]
# new python: 28961/s # new python: 28961/s
# old python: 18307/s # old python: 18307/s
# re: 12820/s # re: 12820/s
# regex: 14035/s # regex: 14035/s
def find_prefix_at_end (haystack, needle): def find_prefix_at_end (haystack, needle):
l = len(needle) - 1 l = len(needle) - 1
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: auth_handler.py,v 1.2 2001/04/25 19:07:30 andreas Exp $' RCS_ID = '$Id: auth_handler.py,v 1.3 2001/05/01 11:44:48 andreas Exp $'
# support for 'basic' authenticaion. # support for 'basic' authenticaion.
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: chat_server.py,v 1.2 2001/04/25 19:07:30 andreas Exp $' RCS_ID = '$Id: chat_server.py,v 1.3 2001/05/01 11:44:48 andreas Exp $'
import string import string
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: default_handler.py,v 1.6 2001/04/25 19:07:30 andreas Exp $' RCS_ID = '$Id: default_handler.py,v 1.7 2001/05/01 11:44:48 andreas Exp $'
# standard python modules # standard python modules
import os import os
...@@ -190,9 +190,9 @@ class default_handler: ...@@ -190,9 +190,9 @@ class default_handler:
+ '</ul>' + '</ul>'
) )
# HTTP/1.0 doesn't say anything about the "; length=nnnn" addition # HTTP/1.0 doesn't say anything about the "; length=nnnn" addition
# to this header. I suppose it's purpose is to avoid the overhead # to this header. I suppose it's purpose is to avoid the overhead
# of parsing dates... # of parsing dates...
IF_MODIFIED_SINCE = re.compile ( IF_MODIFIED_SINCE = re.compile (
'If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)', 'If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)',
re.IGNORECASE re.IGNORECASE
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: filesys.py,v 1.8 2001/04/27 18:25:42 andreas Exp $ # $Id: filesys.py,v 1.9 2001/05/01 11:44:48 andreas Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# #
# Generic filesystem interface. # Generic filesystem interface.
...@@ -59,15 +59,15 @@ class abstract_filesystem: ...@@ -59,15 +59,15 @@ class abstract_filesystem:
[for the output of the LIST command]""" [for the output of the LIST command]"""
pass pass
# standard wrapper around a unix-like filesystem, with a 'false root' # standard wrapper around a unix-like filesystem, with a 'false root'
# capability. # capability.
# security considerations: can symbolic links be used to 'escape' the # security considerations: can symbolic links be used to 'escape' the
# root? should we allow it? if not, then we could scan the # root? should we allow it? if not, then we could scan the
# filesystem on startup, but that would not help if they were added # filesystem on startup, but that would not help if they were added
# later. We will probably need to check for symlinks in the cwd method. # later. We will probably need to check for symlinks in the cwd method.
# what to do if wd is an invalid directory? # what to do if wd is an invalid directory?
import os,re import os,re
import stat import stat
...@@ -251,88 +251,88 @@ if os.name == 'posix': ...@@ -251,88 +251,88 @@ if os.name == 'posix':
finally: finally:
self.become_nobody() self.become_nobody()
# This hasn't been very reliable across different platforms. # This hasn't been very reliable across different platforms.
# maybe think about a separate 'directory server'. # maybe think about a separate 'directory server'.
# #
# import posixpath # import posixpath
# import fcntl # import fcntl
# import FCNTL # import FCNTL
# import select # import select
# import asyncore # import asyncore
# #
# # pipes /bin/ls for directory listings. # # pipes /bin/ls for directory listings.
# class unix_filesystem (os_filesystem): # class unix_filesystem (os_filesystem):
# pass # pass
# path_module = posixpath # path_module = posixpath
# #
# def listdir (self, path, long=0): # def listdir (self, path, long=0):
# p = self.translate (path) # p = self.translate (path)
# if not long: # if not long:
# return list_producer (os.listdir (p), 0, None) # return list_producer (os.listdir (p), 0, None)
# else: # else:
# command = '/bin/ls -l %s' % p # command = '/bin/ls -l %s' % p
# print 'opening pipe to "%s"' % command # print 'opening pipe to "%s"' % command
# fd = os.popen (command, 'rt') # fd = os.popen (command, 'rt')
# return pipe_channel (fd) # return pipe_channel (fd)
# #
# # this is both a dispatcher, _and_ a producer # # this is both a dispatcher, _and_ a producer
# class pipe_channel (asyncore.file_dispatcher): # class pipe_channel (asyncore.file_dispatcher):
# buffer_size = 4096 # buffer_size = 4096
# #
# def __init__ (self, fd): # def __init__ (self, fd):
# asyncore.file_dispatcher.__init__ (self, fd) # asyncore.file_dispatcher.__init__ (self, fd)
# self.fd = fd # self.fd = fd
# self.done = 0 # self.done = 0
# self.data = '' # self.data = ''
# #
# def handle_read (self): # def handle_read (self):
# if len (self.data) < self.buffer_size: # if len (self.data) < self.buffer_size:
# self.data = self.data + self.fd.read (self.buffer_size) # self.data = self.data + self.fd.read (self.buffer_size)
# #print '%s.handle_read() => len(self.data) == %d' % (self, len(self.data)) # #print '%s.handle_read() => len(self.data) == %d' % (self, len(self.data))
# #
# def handle_expt (self): # def handle_expt (self):
# #print '%s.handle_expt()' % self # #print '%s.handle_expt()' % self
# self.done = 1 # self.done = 1
# #
# def ready (self): # def ready (self):
# #print '%s.ready() => %d' % (self, len(self.data)) # #print '%s.ready() => %d' % (self, len(self.data))
# return ((len (self.data) > 0) or self.done) # return ((len (self.data) > 0) or self.done)
# #
# def more (self): # def more (self):
# if self.data: # if self.data:
# r = self.data # r = self.data
# self.data = '' # self.data = ''
# elif self.done: # elif self.done:
# self.close() # self.close()
# self.downstream.finished() # self.downstream.finished()
# r = '' # r = ''
# else: # else:
# r = None # r = None
# #print '%s.more() => %s' % (self, (r and len(r))) # #print '%s.more() => %s' % (self, (r and len(r)))
# return r # return r
# For the 'real' root, we could obtain a list of drives, and then # For the 'real' root, we could obtain a list of drives, and then
# use that. Doesn't win32 provide such a 'real' filesystem? # use that. Doesn't win32 provide such a 'real' filesystem?
# [yes, I think something like this "\\.\c\windows"] # [yes, I think something like this "\\.\c\windows"]
class msdos_filesystem (os_filesystem): class msdos_filesystem (os_filesystem):
def longify (self, (path, stat_info)): def longify (self, (path, stat_info)):
return msdos_longify (path, stat_info) return msdos_longify (path, stat_info)
# A merged filesystem will let you plug other filesystems together. # A merged filesystem will let you plug other filesystems together.
# We really need the equivalent of a 'mount' capability - this seems # We really need the equivalent of a 'mount' capability - this seems
# to be the most general idea. So you'd use a 'mount' method to place # to be the most general idea. So you'd use a 'mount' method to place
# another filesystem somewhere in the hierarchy. # another filesystem somewhere in the hierarchy.
# Note: this is most likely how I will handle ~user directories # Note: this is most likely how I will handle ~user directories
# with the http server. # with the http server.
class merged_filesystem: class merged_filesystem:
def __init__ (self, *fsys): def __init__ (self, *fsys):
pass pass
# this matches the output of NT's ftp server (when in # this matches the output of NT's ftp server (when in
# MSDOS mode) exactly. # MSDOS mode) exactly.
def msdos_longify (file, stat_info): def msdos_longify (file, stat_info):
if stat.S_ISDIR (stat_info[stat.ST_MODE]): if stat.S_ISDIR (stat_info[stat.ST_MODE]):
...@@ -403,12 +403,12 @@ def unix_longify (file, stat_info): ...@@ -403,12 +403,12 @@ def unix_longify (file, stat_info):
file file
) )
# Emulate the unix 'ls' command's date field. # Emulate the unix 'ls' command's date field.
# it has two formats - if the date is more than 180 # it has two formats - if the date is more than 180
# days in the past, then it's like this: # days in the past, then it's like this:
# Oct 19 1995 # Oct 19 1995
# otherwise, it looks like this: # otherwise, it looks like this:
# Oct 19 17:33 # Oct 19 17:33
def ls_date (now, t): def ls_date (now, t):
try: try:
...@@ -430,9 +430,9 @@ def ls_date (now, t): ...@@ -430,9 +430,9 @@ def ls_date (now, t):
info[4] info[4]
) )
# =========================================================================== # ===========================================================================
# Producers # Producers
# =========================================================================== # ===========================================================================
class list_producer: class list_producer:
def __init__ (self, file_list, long, longify): def __init__ (self, file_list, long, longify):
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: ftp_server.py,v 1.16 2001/04/27 18:26:51 andreas Exp $' RCS_ID = '$Id: ftp_server.py,v 1.17 2001/05/01 11:44:48 andreas Exp $'
# An extensible, configurable, asynchronous FTP server. # An extensible, configurable, asynchronous FTP server.
# #
...@@ -99,8 +99,8 @@ class ftp_channel (asynchat.async_chat): ...@@ -99,8 +99,8 @@ class ftp_channel (asynchat.async_chat):
) )
) )
# def __del__ (self): # def __del__ (self):
# print 'ftp_channel.__del__()' # print 'ftp_channel.__del__()'
# -------------------------------------------------- # --------------------------------------------------
# async-library methods # async-library methods
...@@ -633,15 +633,15 @@ class ftp_channel (asynchat.async_chat): ...@@ -633,15 +633,15 @@ class ftp_channel (asynchat.async_chat):
else: else:
self.respond ('502 Unimplemented MODE type') self.respond ('502 Unimplemented MODE type')
# The stat command has two personalities. Normally it returns status # The stat command has two personalities. Normally it returns status
# information about the current connection. But if given an argument, # information about the current connection. But if given an argument,
# it is equivalent to the LIST command, with the data sent over the # it is equivalent to the LIST command, with the data sent over the
# control connection. Strange. But wuftpd, ftpd, and nt's ftp server # control connection. Strange. But wuftpd, ftpd, and nt's ftp server
# all support it. # all support it.
# #
## def cmd_stat (self, line): ## def cmd_stat (self, line):
## 'return status of server' ## 'return status of server'
## pass ## pass
def cmd_syst (self, line): def cmd_syst (self, line):
'show operating system type of server system' 'show operating system type of server system'
...@@ -777,32 +777,32 @@ class ftp_server (asyncore.dispatcher): ...@@ -777,32 +777,32 @@ class ftp_server (asyncore.dispatcher):
] ]
) )
# ====================================================================== # ======================================================================
# Data Channel Classes # Data Channel Classes
# ====================================================================== # ======================================================================
# This socket accepts a data connection, used when the server has been # This socket accepts a data connection, used when the server has been
# placed in passive mode. Although the RFC implies that we ought to # placed in passive mode. Although the RFC implies that we ought to
# be able to use the same acceptor over and over again, this presents # be able to use the same acceptor over and over again, this presents
# a problem: how do we shut it off, so that we are accepting # a problem: how do we shut it off, so that we are accepting
# connections only when we expect them? [we can't] # connections only when we expect them? [we can't]
# #
# wuftpd, and probably all the other servers, solve this by allowing # wuftpd, and probably all the other servers, solve this by allowing
# only one connection to hit this acceptor. They then close it. Any # only one connection to hit this acceptor. They then close it. Any
# subsequent data-connection command will then try for the default # subsequent data-connection command will then try for the default
# port on the client side [which is of course never there]. So the # port on the client side [which is of course never there]. So the
# 'always-send-PORT/PASV' behavior seems required. # 'always-send-PORT/PASV' behavior seems required.
# #
# Another note: wuftpd will also be listening on the channel as soon # Another note: wuftpd will also be listening on the channel as soon
# as the PASV command is sent. It does not wait for a data command # as the PASV command is sent. It does not wait for a data command
# first. # first.
# --- we need to queue up a particular behavior: # --- we need to queue up a particular behavior:
# 1) xmit : queue up producer[s] # 1) xmit : queue up producer[s]
# 2) recv : the file object # 2) recv : the file object
# #
# It would be nice if we could make both channels the same. Hmmm.. # It would be nice if we could make both channels the same. Hmmm..
# #
class passive_acceptor (asyncore.dispatcher): class passive_acceptor (asyncore.dispatcher):
ready = None ready = None
...@@ -821,8 +821,8 @@ class passive_acceptor (asyncore.dispatcher): ...@@ -821,8 +821,8 @@ class passive_acceptor (asyncore.dispatcher):
self.addr = self.getsockname() self.addr = self.getsockname()
self.listen (1) self.listen (1)
# def __del__ (self): # def __del__ (self):
# print 'passive_acceptor.__del__()' # print 'passive_acceptor.__del__()'
def log (self, *ignore): def log (self, *ignore):
pass pass
...@@ -854,8 +854,8 @@ class xmit_channel (asynchat.async_chat): ...@@ -854,8 +854,8 @@ class xmit_channel (asynchat.async_chat):
self.client_addr = client_addr self.client_addr = client_addr
asynchat.async_chat.__init__ (self) asynchat.async_chat.__init__ (self)
# def __del__ (self): # def __del__ (self):
# print 'xmit_channel.__del__()' # print 'xmit_channel.__del__()'
def log (*args): def log (*args):
pass pass
...@@ -962,9 +962,9 @@ class anon_authorizer: ...@@ -962,9 +962,9 @@ class anon_authorizer:
else: else:
return 0, 'Password invalid.', None return 0, 'Password invalid.', None
# =========================================================================== # ===========================================================================
# Unix-specific improvements # Unix-specific improvements
# =========================================================================== # ===========================================================================
if os.name == 'posix': if os.name == 'posix':
...@@ -1046,9 +1046,9 @@ class file_producer: ...@@ -1046,9 +1046,9 @@ class file_producer:
self.done = 1 self.done = 1
return block return block
# usage: ftp_server /PATH/TO/FTP/ROOT PORT # usage: ftp_server /PATH/TO/FTP/ROOT PORT
# for example: # for example:
# $ ftp_server /home/users/ftp 8021 # $ ftp_server /home/users/ftp 8021
if os.name == 'posix': if os.name == 'posix':
def test (port='8021'): def test (port='8021'):
...@@ -1067,17 +1067,17 @@ if os.name == 'posix': ...@@ -1067,17 +1067,17 @@ if os.name == 'posix':
if __name__ == '__main__': if __name__ == '__main__':
test (sys.argv[1]) test (sys.argv[1])
# not unix # not unix
else: else:
def test (): def test ():
fs = ftp_server (dummy_authorizer()) fs = ftp_server (dummy_authorizer())
if __name__ == '__main__': if __name__ == '__main__':
test () test ()
# this is the command list from the wuftpd man page # this is the command list from the wuftpd man page
# '*' means we've implemented it. # '*' means we've implemented it.
# '!' requires write access # '!' requires write access
# #
command_documentation = { command_documentation = {
'abor': 'abort previous command', #* 'abor': 'abort previous command', #*
'acct': 'specify account (ignored)', 'acct': 'specify account (ignored)',
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import string import string
import regex import regex
RCS_ID = '$Id: http_bobo.py,v 1.3 2001/04/26 00:07:52 andreas Exp $' RCS_ID = '$Id: http_bobo.py,v 1.4 2001/05/01 11:44:48 andreas Exp $'
VERSION_STRING = string.split(RCS_ID)[2] VERSION_STRING = string.split(RCS_ID)[2]
class bobo_extension: class bobo_extension:
......
...@@ -68,7 +68,7 @@ def unpack_rfc822 (m): ...@@ -68,7 +68,7 @@ def unpack_rfc822 (m):
0 0
) )
# rfc850 format # rfc850 format
rfc850_date = join ( rfc850_date = join (
[concat (long_day_reg,','), [concat (long_day_reg,','),
join ( join (
...@@ -101,8 +101,8 @@ def unpack_rfc850 (m): ...@@ -101,8 +101,8 @@ def unpack_rfc850 (m):
0 0
) )
# parsdate.parsedate - ~700/sec. # parsdate.parsedate - ~700/sec.
# parse_http_date - ~1333/sec. # parse_http_date - ~1333/sec.
def build_http_date (when): def build_http_date (when):
return time.strftime ('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(when)) return time.strftime ('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(when))
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: http_server.py,v 1.23 2001/04/30 14:38:40 andreas Exp $' RCS_ID = '$Id: http_server.py,v 1.24 2001/05/01 11:44:48 andreas Exp $'
# python modules # python modules
import os import os
...@@ -331,9 +331,9 @@ class http_request: ...@@ -331,9 +331,9 @@ class http_request:
) )
# =========================================================================== # ===========================================================================
# HTTP Channel Object # HTTP Channel Object
# =========================================================================== # ===========================================================================
class http_channel (asynchat.async_chat): class http_channel (asynchat.async_chat):
...@@ -523,9 +523,9 @@ class http_channel (asynchat.async_chat): ...@@ -523,9 +523,9 @@ class http_channel (asynchat.async_chat):
else: else:
return 1 return 1
# =========================================================================== # ===========================================================================
# HTTP Server Object # HTTP Server Object
# =========================================================================== # ===========================================================================
class http_server (asyncore.dispatcher): class http_server (asyncore.dispatcher):
...@@ -748,7 +748,7 @@ def compute_timezone_for_log (): ...@@ -748,7 +748,7 @@ def compute_timezone_for_log ():
else: else:
return '+%02d%02d' % (h, m) return '+%02d%02d' % (h, m)
# if you run this program over a TZ change boundary, this will be invalid. # if you run this program over a TZ change boundary, this will be invalid.
tz_for_log = compute_timezone_for_log() tz_for_log = compute_timezone_for_log()
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -76,11 +76,11 @@ class file_logger: ...@@ -76,11 +76,11 @@ class file_logger:
else: else:
self.write (message) self.write (message)
# like a file_logger, but it must be attached to a filename. # like a file_logger, but it must be attached to a filename.
# When the log gets too full, or a certain time has passed, # When the log gets too full, or a certain time has passed,
# it backs up the log and starts a new one. Note that backing # it backs up the log and starts a new one. Note that backing
# up the log is done via "mv" because anything else (cp, gzip) # up the log is done via "mv" because anything else (cp, gzip)
# would take time, during which medusa would do nothing else. # would take time, during which medusa would do nothing else.
class rotating_file_logger (file_logger): class rotating_file_logger (file_logger):
...@@ -142,14 +142,14 @@ class rotating_file_logger (file_logger): ...@@ -142,14 +142,14 @@ class rotating_file_logger (file_logger):
except: except:
pass pass
# syslog is a line-oriented log protocol - this class would be # syslog is a line-oriented log protocol - this class would be
# appropriate for FTP or HTTP logs, but not for dumping stderr to. # appropriate for FTP or HTTP logs, but not for dumping stderr to.
# TODO: a simple safety wrapper that will ensure that the line sent # TODO: a simple safety wrapper that will ensure that the line sent
# to syslog is reasonable. # to syslog is reasonable.
# TODO: async version of syslog_client: now, log entries use blocking # TODO: async version of syslog_client: now, log entries use blocking
# send() # send()
import m_syslog import m_syslog
syslog_logger = m_syslog.syslog_client syslog_logger = m_syslog.syslog_client
...@@ -171,7 +171,7 @@ class syslog_logger (m_syslog.syslog_client): ...@@ -171,7 +171,7 @@ class syslog_logger (m_syslog.syslog_client):
priority=m_syslog.LOG_INFO priority=m_syslog.LOG_INFO
) )
# log to a stream socket, asynchronously # log to a stream socket, asynchronously
class socket_logger (asynchat.async_chat): class socket_logger (asynchat.async_chat):
...@@ -194,7 +194,7 @@ class socket_logger (asynchat.async_chat): ...@@ -194,7 +194,7 @@ class socket_logger (asynchat.async_chat):
else: else:
self.socket.push (message) self.socket.push (message)
# log to multiple places # log to multiple places
class multi_logger: class multi_logger:
def __init__ (self, loggers): def __init__ (self, loggers):
self.loggers = loggers self.loggers = loggers
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = '$Id: async_mysql.py,v 1.2 2001/04/25 19:09:49 andreas Exp $' VERSION_STRING = '$Id: async_mysql.py,v 1.3 2001/05/01 11:45:26 andreas Exp $'
import exceptions import exceptions
import math import math
...@@ -17,18 +17,18 @@ from fifo import fifo ...@@ -17,18 +17,18 @@ from fifo import fifo
class mysql_error (exceptions.Exception): class mysql_error (exceptions.Exception):
pass pass
# =========================================================================== # ===========================================================================
# Authentication # Authentication
# =========================================================================== # ===========================================================================
# Note: I've ignored the stuff to support an older version of the protocol. # Note: I've ignored the stuff to support an older version of the protocol.
# #
# The code is based on the file mysql-3.21.33/client/password.c # The code is based on the file mysql-3.21.33/client/password.c
# #
# The auth scheme is challenge/response. Upon connection the server # The auth scheme is challenge/response. Upon connection the server
# sends an 8-byte challenge message. This is hashed with the password # sends an 8-byte challenge message. This is hashed with the password
# to produce an 8-byte response. The server side performs an identical # to produce an 8-byte response. The server side performs an identical
# hash to verify the password is correct. # hash to verify the password is correct.
class random_state: class random_state:
...@@ -73,9 +73,9 @@ def scramble (message, password): ...@@ -73,9 +73,9 @@ def scramble (message, password):
to[i] = to[i] ^ extra to[i] = to[i] ^ extra
return to return to
# =========================================================================== # ===========================================================================
# Packet Protocol # Packet Protocol
# =========================================================================== # ===========================================================================
def unpacket (p): def unpacket (p):
# 3-byte length, one-byte packet number, followed by packet data # 3-byte length, one-byte packet number, followed by packet data
...@@ -110,7 +110,7 @@ def net_field_length (data, pos=0): ...@@ -110,7 +110,7 @@ def net_field_length (data, pos=0):
# libmysql adds 6, why? # libmysql adds 6, why?
return n_byte_num (data, 4), 5 return n_byte_num (data, 4), 5
# used to generate the dumps below # used to generate the dumps below
def dump_hex (s): def dump_hex (s):
r1 = [] r1 = []
r2 = [] r2 = []
...@@ -122,9 +122,9 @@ def dump_hex (s): ...@@ -122,9 +122,9 @@ def dump_hex (s):
r2.append (' ') r2.append (' ')
return string.join (r1, ''), string.join (r2, '') return string.join (r1, ''), string.join (r2, '')
# =========================================================================== # ===========================================================================
# MySQL Client # MySQL Client
# =========================================================================== # ===========================================================================
class mysql_client (asynchat.async_chat): class mysql_client (asynchat.async_chat):
...@@ -305,9 +305,9 @@ class mysql_client (asynchat.async_chat): ...@@ -305,9 +305,9 @@ class mysql_client (asynchat.async_chat):
def cmd_query (self, query, callback=None): def cmd_query (self, query, callback=None):
self.command ('query', query, result_set (callback)) self.command ('query', query, result_set (callback))
# =========================================================================== # ===========================================================================
# Result Set # Result Set
# =========================================================================== # ===========================================================================
class result_set: class result_set:
...@@ -440,59 +440,59 @@ if __name__ == '__main__': ...@@ -440,59 +440,59 @@ if __name__ == '__main__':
c = mysql_client (username, password, go, (host, 3306)) c = mysql_client (username, password, go, (host, 3306))
asyncore.loop() asyncore.loop()
# greeting: # greeting:
# * first byte is the protocol version (currently 10) # * first byte is the protocol version (currently 10)
# * null-terminated version string # * null-terminated version string
# * 4-byte thread id. # * 4-byte thread id.
# * 8-byte challenge # * 8-byte challenge
# * 2-byte server capabilities? # * 2-byte server capabilities?
# message = [0x00, 0x39, 0x4d, 0x59, 0x59, 0x31, 0x29, 0x79, 0x47] # message = [0x00, 0x39, 0x4d, 0x59, 0x59, 0x31, 0x29, 0x79, 0x47]
# password = [0x66, 0x6e, 0x6f, 0x72, 0x64] # password = [0x66, 0x6e, 0x6f, 0x72, 0x64]
# Handshake: # Handshake:
#---------------------------------------- #----------------------------------------
#<== 000 0a 33 2e 32 32 2e 31 30 2d 62 65 74 61 00 1b 00 00 00 39 4d 59 59 31 29 79 47 00 0c 00 #<== 000 0a 33 2e 32 32 2e 31 30 2d 62 65 74 61 00 1b 00 00 00 39 4d 59 59 31 29 79 47 00 0c 00
# 3 2 2 1 0 b e t a 9 M Y Y 1 y G # 3 2 2 1 0 b e t a 9 M Y Y 1 y G
#---------------------------------------- #----------------------------------------
#==> 1 #==> 1
# 05 00 00 00 10 72 75 73 68 69 6e 67 00 48 51 42 50 5d 4a 54 57 # 05 00 00 00 10 72 75 73 68 69 6e 67 00 48 51 42 50 5d 4a 54 57
# r u s h i n g H Q B P J T W # r u s h i n g H Q B P J T W
#---------------------------------------- #----------------------------------------
#<== 002 00 00 00 #<== 002 00 00 00
# Insertion/Query (no result set) # Insertion/Query (no result set)
#---------------------------------------- #----------------------------------------
#==> 0 #==> 0
# 03 69 6e 73 65 72 74 20 69 6e 74 6f 20 75 73 65 72 73 20 76 61 6c 75 65 73 20 28 22 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 22 2c 20 22 6e 22 29 # 03 69 6e 73 65 72 74 20 69 6e 74 6f 20 75 73 65 72 73 20 76 61 6c 75 65 73 20 28 22 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 22 2c 20 22 6e 22 29
# i n s e r t i n t o u s e r s v a l u e s a s d f a s d f a s d f n # i n s e r t i n t o u s e r s v a l u e s a s d f a s d f a s d f n
#---------------------------------------- #----------------------------------------
#<== 001 00 01 00 #<== 001 00 01 00
# Query (with result set) # Query (with result set)
#---------------------------------------- #----------------------------------------
#==> 0 #==> 0
# 03 73 65 6c 65 63 74 20 2a 20 66 72 6f 6d 20 75 73 65 72 73 # 03 73 65 6c 65 63 74 20 2a 20 66 72 6f 6d 20 75 73 65 72 73
# s e l e c t f r o m u s e r s # s e l e c t f r o m u s e r s
#---------------------------------------- #----------------------------------------
#<== 001 02 #<== 001 02
# #
#<== 002 05 75 73 65 72 73 04 6e 61 6d 65 03 80 00 00 01 fe 03 00 00 00 #<== 002 05 75 73 65 72 73 04 6e 61 6d 65 03 80 00 00 01 fe 03 00 00 00
# u s e r s n a m e # u s e r s n a m e
#<== 003 05 75 73 65 72 73 0a 69 73 62 6f 75 6e 63 69 6e 67 03 01 00 00 01 fe 03 00 00 00 #<== 003 05 75 73 65 72 73 0a 69 73 62 6f 75 6e 63 69 6e 67 03 01 00 00 01 fe 03 00 00 00
# u s e r s i s b o u n c i n g # u s e r s i s b o u n c i n g
#<== 004 fe #<== 004 fe
# #
#<== 005 15 72 75 73 68 69 6e 67 40 6e 69 67 68 74 6d 61 72 65 2e 63 6f 6d 01 6e #<== 005 15 72 75 73 68 69 6e 67 40 6e 69 67 68 74 6d 61 72 65 2e 63 6f 6d 01 6e
# r u s h i n g n i g h t m a r e c o m n # r u s h i n g n i g h t m a r e c o m n
#<== 006 0e 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 01 6e #<== 006 0e 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 01 6e
# a s d f a s d f a s d f n # a s d f a s d f a s d f n
#<== 007 fe #<== 007 fe
# "use bouncer_test" # "use bouncer_test"
#==> 0 #==> 0
# 02 62 6f 75 6e 63 65 72 5f 74 65 73 74 # 02 62 6f 75 6e 63 65 72 5f 74 65 73 74
# b o u n c e r t e s t # b o u n c e r t e s t
#---------------------------------------- #----------------------------------------
#<== 001 00 00 00 #<== 001 00 00 00
...@@ -35,7 +35,7 @@ class recorder_server (asyncore.dispatcher): ...@@ -35,7 +35,7 @@ class recorder_server (asyncore.dispatcher):
print 'incoming connection',addr print 'incoming connection',addr
recorder_channel (conn, addr) recorder_channel (conn, addr)
# force a clean shutdown # force a clean shutdown
def shutdown(): def shutdown():
sm = asyncore.socket_map sm = asyncore.socket_map
asyncore.socket_map = {} asyncore.socket_map = {}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# python REPL channel. # python REPL channel.
# #
RCS_ID = '$Id: monitor.py,v 1.11 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: monitor.py,v 1.12 2001/05/01 11:44:48 andreas Exp $'
import md5 import md5
import socket import socket
...@@ -268,8 +268,8 @@ class secure_monitor_server (monitor_server): ...@@ -268,8 +268,8 @@ class secure_monitor_server (monitor_server):
p.data = p.data + ('<br><b>Failed Authorizations:</b> %d' % self.failed_auths) p.data = p.data + ('<br><b>Failed Authorizations:</b> %d' % self.failed_auths)
return p return p
# don't try to print from within any of the methods # don't try to print from within any of the methods
# of this object. 8^) # of this object. 8^)
class output_producer: class output_producer:
def __init__ (self, channel, real_stderr): def __init__ (self, channel, real_stderr):
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
RCS_ID = '$Id: producers.py,v 1.9 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: producers.py,v 1.10 2001/05/01 11:44:48 andreas Exp $'
import string import string
...@@ -107,12 +107,12 @@ class file_producer: ...@@ -107,12 +107,12 @@ class file_producer:
else: else:
return data return data
# A simple output producer. This one does not [yet] have # A simple output producer. This one does not [yet] have
# the safety feature builtin to the monitor channel: runaway # the safety feature builtin to the monitor channel: runaway
# output will not be caught. # output will not be caught.
# don't try to print from within any of the methods # don't try to print from within any of the methods
# of this object. # of this object.
class output_producer: class output_producer:
"Acts like an output file; suitable for capturing sys.stdout" "Acts like an output file; suitable for capturing sys.stdout"
...@@ -215,13 +215,13 @@ class hooked_producer: ...@@ -215,13 +215,13 @@ class hooked_producer:
else: else:
return '' return ''
# HTTP 1.1 emphasizes that an advertised Content-Length header MUST be # HTTP 1.1 emphasizes that an advertised Content-Length header MUST be
# correct. In the face of Strange Files, it is conceivable that # correct. In the face of Strange Files, it is conceivable that
# reading a 'file' may produce an amount of data not matching that # reading a 'file' may produce an amount of data not matching that
# reported by os.stat() [text/binary mode issues, perhaps the file is # reported by os.stat() [text/binary mode issues, perhaps the file is
# being appended to, etc..] This makes the chunked encoding a True # being appended to, etc..] This makes the chunked encoding a True
# Blessing, and it really ought to be used even with normal files. # Blessing, and it really ought to be used even with normal files.
# How beautifully it blends with the concept of the producer. # How beautifully it blends with the concept of the producer.
class chunked_producer: class chunked_producer:
"""A producer that implements the 'chunked' transfer coding for HTTP/1.1. """A producer that implements the 'chunked' transfer coding for HTTP/1.1.
...@@ -254,10 +254,10 @@ class chunked_producer: ...@@ -254,10 +254,10 @@ class chunked_producer:
else: else:
return '' return ''
# Unfortunately this isn't very useful right now (Aug 97), because # Unfortunately this isn't very useful right now (Aug 97), because
# apparently the browsers don't do on-the-fly decompression. Which # apparently the browsers don't do on-the-fly decompression. Which
# is sad, because this could _really_ speed things up, especially for # is sad, because this could _really_ speed things up, especially for
# low-bandwidth clients (i.e., most everyone). # low-bandwidth clients (i.e., most everyone).
try: try:
import zlib import zlib
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: put_handler.py,v 1.2 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: put_handler.py,v 1.3 2001/05/01 11:44:48 andreas Exp $'
import re import re
import string import string
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: redirecting_handler.py,v 1.2 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: redirecting_handler.py,v 1.3 2001/05/01 11:44:49 andreas Exp $'
import re import re
import counter import counter
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# #
RCS_ID = '$Id: resolver.py,v 1.8 2001/04/25 19:07:34 andreas Exp $' RCS_ID = '$Id: resolver.py,v 1.9 2001/05/01 11:44:49 andreas Exp $'
# Fast, low-overhead asynchronous name resolver. uses 'pre-cooked' # Fast, low-overhead asynchronous name resolver. uses 'pre-cooked'
...@@ -114,27 +114,27 @@ def unpack_ttl (r,pos): ...@@ -114,27 +114,27 @@ def unpack_ttl (r,pos):
map (ord, r[pos:pos+4]) map (ord, r[pos:pos+4])
) )
# resource record # resource record
# 1 1 1 1 1 1 # 1 1 1 1 1 1
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | | # | |
# / / # / /
# / NAME / # / NAME /
# | | # | |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | TYPE | # | TYPE |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | CLASS | # | CLASS |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | TTL | # | TTL |
# | | # | |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | RDLENGTH | # | RDLENGTH |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
# / RDATA / # / RDATA /
# / / # / /
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
def unpack_address_reply (r): def unpack_address_reply (r):
ancount = (ord(r[6])<<8) + (ord(r[7])) ancount = (ord(r[6])<<8) + (ord(r[7]))
...@@ -183,18 +183,18 @@ def unpack_ptr_reply (r): ...@@ -183,18 +183,18 @@ def unpack_ptr_reply (r):
return 0, None return 0, None
# This is a UDP (datagram) resolver. # This is a UDP (datagram) resolver.
# #
# It may be useful to implement a TCP resolver. This would presumably # It may be useful to implement a TCP resolver. This would presumably
# give us more reliable behavior when things get too busy. A TCP # give us more reliable behavior when things get too busy. A TCP
# client would have to manage the connection carefully, since the # client would have to manage the connection carefully, since the
# server is allowed to close it at will (the RFC recommends closing # server is allowed to close it at will (the RFC recommends closing
# after 2 minutes of idle time). # after 2 minutes of idle time).
# #
# Note also that the TCP client will have to prepend each request # Note also that the TCP client will have to prepend each request
# with a 2-byte length indicator (see rfc1035). # with a 2-byte length indicator (see rfc1035).
# #
class resolver (asyncore.dispatcher): class resolver (asyncore.dispatcher):
id = counter() id = counter()
...@@ -366,28 +366,28 @@ class caching_resolver (resolver): ...@@ -366,28 +366,28 @@ class caching_resolver (resolver):
+ '<br>Cache Hits: %s' % self.cache_hits + '<br>Cache Hits: %s' % self.cache_hits
) )
#test_reply = """\000\000\205\200\000\001\000\001\000\002\000\002\006squirl\011nightmare\003com\000\000\001\000\001\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\011nightmare\003com\000\000\002\000\001\000\001Q\200\000\002\300\014\3006\000\002\000\001\000\001Q\200\000\015\003ns1\003iag\003net\000\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\300]\000\001\000\001\000\000\350\227\000\004\314\033\322\005""" #test_reply = """\000\000\205\200\000\001\000\001\000\002\000\002\006squirl\011nightmare\003com\000\000\001\000\001\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\011nightmare\003com\000\000\002\000\001\000\001Q\200\000\002\300\014\3006\000\002\000\001\000\001Q\200\000\015\003ns1\003iag\003net\000\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\300]\000\001\000\001\000\000\350\227\000\004\314\033\322\005"""
# def test_unpacker (): # def test_unpacker ():
# print unpack_address_reply (test_reply) # print unpack_address_reply (test_reply)
# #
# import time # import time
# class timer: # class timer:
# def __init__ (self): # def __init__ (self):
# self.start = time.time() # self.start = time.time()
# def end (self): # def end (self):
# return time.time() - self.start # return time.time() - self.start
# #
# # I get ~290 unpacks per second for the typical case, compared to ~48 # # I get ~290 unpacks per second for the typical case, compared to ~48
# # using dnslib directly. also, that latter number does not include # # using dnslib directly. also, that latter number does not include
# # picking the actual data out. # # picking the actual data out.
# #
# def benchmark_unpacker(): # def benchmark_unpacker():
# #
# r = range(1000) # r = range(1000)
# t = timer() # t = timer()
# for i in r: # for i in r:
# unpack_address_reply (test_reply) # unpack_address_reply (test_reply)
# print '%.2f unpacks per second' % (1000.0 / t.end()) # print '%.2f unpacks per second' % (1000.0 / t.end())
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
......
...@@ -47,16 +47,16 @@ import errno ...@@ -47,16 +47,16 @@ import errno
class RPC_Error (exceptions.StandardError): class RPC_Error (exceptions.StandardError):
pass pass
# =========================================================================== # ===========================================================================
# RPC Client # RPC Client
# =========================================================================== # ===========================================================================
# request types: # request types:
# 0 call # 0 call
# 1 getattr # 1 getattr
# 2 setattr # 2 setattr
# 3 repr # 3 repr
# 4 del # 4 del
class rpc_proxy: class rpc_proxy:
...@@ -187,9 +187,9 @@ def rpc_connect (address = ('localhost', 8746)): ...@@ -187,9 +187,9 @@ def rpc_connect (address = ('localhost', 8746)):
rpc_connection.cache[address] = rpc_proxy (conn, oid) rpc_connection.cache[address] = rpc_proxy (conn, oid)
return rpc_connection.cache[address] return rpc_connection.cache[address]
# =========================================================================== # ===========================================================================
# fastrpc client # fastrpc client
# =========================================================================== # ===========================================================================
class fastrpc_proxy: class fastrpc_proxy:
...@@ -224,9 +224,9 @@ def fastrpc_connect (address = ('localhost', 8748)): ...@@ -224,9 +224,9 @@ def fastrpc_connect (address = ('localhost', 8748)):
rpc_connection.cache[address] = fastrpc_proxy (conn) rpc_connection.cache[address] = fastrpc_proxy (conn)
return rpc_connection.cache[address] return rpc_connection.cache[address]
# =========================================================================== # ===========================================================================
# async fastrpc client # async fastrpc client
# =========================================================================== # ===========================================================================
import asynchat import asynchat
import fifo import fifo
......
...@@ -202,21 +202,21 @@ class rpc_server (asyncore.dispatcher): ...@@ -202,21 +202,21 @@ class rpc_server (asyncore.dispatcher):
rpc_channel (self.root, conn, addr) rpc_channel (self.root, conn, addr)
# =========================================================================== # ===========================================================================
# Fast RPC server # Fast RPC server
# =========================================================================== # ===========================================================================
# no proxies, request consists # no proxies, request consists
# of a 'chain' of getattrs terminated by a __call__. # of a 'chain' of getattrs terminated by a __call__.
# Protocol: # Protocol:
# <path>.<to>.<object> ( <param1>, <param2>, ... ) # <path>.<to>.<object> ( <param1>, <param2>, ... )
# => ( <value1>, <value2>, ... ) # => ( <value1>, <value2>, ... )
# #
# #
# (<path>, <params>) # (<path>, <params>)
# path: tuple of strings # path: tuple of strings
# params: tuple of objects # params: tuple of objects
class fastrpc_channel (asynchat.async_chat): class fastrpc_channel (asynchat.async_chat):
...@@ -285,7 +285,7 @@ class fastrpc_server (asyncore.dispatcher): ...@@ -285,7 +285,7 @@ class fastrpc_server (asyncore.dispatcher):
conn, addr = self.accept() conn, addr = self.accept()
fastrpc_channel (self.root, conn, addr) fastrpc_channel (self.root, conn, addr)
# =========================================================================== # ===========================================================================
if __name__ == '__main__': if __name__ == '__main__':
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
RCS_ID = '$Id: asynchat_sendfile.py,v 1.2 2001/04/25 19:09:54 andreas Exp $' RCS_ID = '$Id: asynchat_sendfile.py,v 1.3 2001/05/01 11:45:27 andreas Exp $'
import sendfile import sendfile
import asynchat import asynchat
...@@ -49,9 +49,9 @@ class async_chat_with_sendfile (async_chat): ...@@ -49,9 +49,9 @@ class async_chat_with_sendfile (async_chat):
if callback is not None: if callback is not None:
callback (0, fd) callback (0, fd)
# here's how you might use this: # here's how you might use this:
# fd = os.open (filename, os.O_RDONLY, 0644) # fd = os.open (filename, os.O_RDONLY, 0644)
# size = os.lseek (fd, 0, 2) # size = os.lseek (fd, 0, 2)
# os.lseek (fd, 0, 0) # os.lseek (fd, 0, 0)
# self.push ('%08x' % size) # self.push ('%08x' % size)
# self.push_sendfile (fd, 0, size) # self.push_sendfile (fd, 0, size)
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
RCS_ID = '$Id: test_sendfile.py,v 1.2 2001/04/25 19:09:54 andreas Exp $' RCS_ID = '$Id: test_sendfile.py,v 1.3 2001/05/01 11:45:27 andreas Exp $'
import asyncore import asyncore
import os import os
......
...@@ -115,13 +115,13 @@ if os.name == 'posix': ...@@ -115,13 +115,13 @@ if os.name == 'posix':
uh = unix_user_handler.unix_user_handler ('public_html') uh = unix_user_handler.unix_user_handler ('public_html')
hs.install_handler (uh) hs.install_handler (uh)
# =========================================================================== # ===========================================================================
# FTP Server # FTP Server
# =========================================================================== # ===========================================================================
# Here we create an 'anonymous' ftp server. # Here we create an 'anonymous' ftp server.
# Note: the ftp server is read-only by default. [in this mode, all # Note: the ftp server is read-only by default. [in this mode, all
# 'write-capable' commands are unavailable] # 'write-capable' commands are unavailable]
ftp = ftp_server.ftp_server ( ftp = ftp_server.ftp_server (
ftp_server.anon_authorizer ( ftp_server.anon_authorizer (
...@@ -192,7 +192,7 @@ if os.name == 'posix': ...@@ -192,7 +192,7 @@ if os.name == 'posix':
os.setegid (gid) os.setegid (gid)
os.seteuid (uid) os.seteuid (uid)
# Finally, start up the server loop! This loop will not exit until # Finally, start up the server loop! This loop will not exit until
# all clients and servers are closed. You may cleanly shut the system # all clients and servers are closed. You may cleanly shut the system
# down by sending SIGINT (a.k.a. KeyboardInterrupt). # down by sending SIGINT (a.k.a. KeyboardInterrupt).
asyncore.loop() asyncore.loop()
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = "$Id: status_handler.py,v 1.6 2001/04/25 19:07:34 andreas Exp $" VERSION_STRING = "$Id: status_handler.py,v 1.7 2001/05/01 11:44:49 andreas Exp $"
# #
# medusa status extension # medusa status extension
...@@ -215,7 +215,7 @@ class channel_list_producer (lines_producer): ...@@ -215,7 +215,7 @@ class channel_list_producer (lines_producer):
) )
# this really needs a full-blown quoter... # this really needs a full-blown quoter...
def sanitize (s): def sanitize (s):
if '<' in s: if '<' in s:
s = string.join (string.split (s, '<'), '&lt;') s = string.join (string.split (s, '<'), '&lt;')
...@@ -238,11 +238,11 @@ def html_reprs (list, front='', back=''): ...@@ -238,11 +238,11 @@ def html_reprs (list, front='', back=''):
reprs.sort() reprs.sort()
return reprs return reprs
# for example, tera, giga, mega, kilo # for example, tera, giga, mega, kilo
# p_d (n, (1024, 1024, 1024, 1024)) # p_d (n, (1024, 1024, 1024, 1024))
# smallest divider goes first - for example # smallest divider goes first - for example
# minutes, hours, days # minutes, hours, days
# p_d (n, (60, 60, 24)) # p_d (n, (60, 60, 24))
def progressive_divide (n, parts): def progressive_divide (n, parts):
result = [] result = []
...@@ -252,7 +252,7 @@ def progressive_divide (n, parts): ...@@ -252,7 +252,7 @@ def progressive_divide (n, parts):
result.append (n) result.append (n)
return result return result
# b,k,m,g,t # b,k,m,g,t
def split_by_units (n, units, dividers, format_string): def split_by_units (n, units, dividers, format_string):
divs = progressive_divide (n, dividers) divs = progressive_divide (n, dividers)
result = [] result = []
......
...@@ -28,17 +28,17 @@ class http_client (asyncore.dispatcher_with_send): ...@@ -28,17 +28,17 @@ class http_client (asyncore.dispatcher_with_send):
def handle_connect (self): def handle_connect (self):
self.connected = 1 self.connected = 1
# blurt ('o') # blurt ('o')
self.send ('GET %s HTTP/1.0\r\n\r\n' % self.uri) self.send ('GET %s HTTP/1.0\r\n\r\n' % self.uri)
def handle_read (self): def handle_read (self):
# blurt ('.') # blurt ('.')
d = self.recv (8192) d = self.recv (8192)
self.bytes = self.bytes + len(d) self.bytes = self.bytes + len(d)
def handle_close (self): def handle_close (self):
global total_sessions global total_sessions
# blurt ('(%d)' % (self.bytes)) # blurt ('(%d)' % (self.bytes))
self.close() self.close()
total_sessions = total_sessions + 1 total_sessions = total_sessions + 1
if self.num: if self.num:
...@@ -89,10 +89,10 @@ if __name__ == '__main__': ...@@ -89,10 +89,10 @@ if __name__ == '__main__':
print 'Max. number of concurrent sessions: %d' % (MAX) print 'Max. number of concurrent sessions: %d' % (MAX)
# linux 2.x, talking to medusa # linux 2.x, talking to medusa
# 50 clients # 50 clients
# 1000 hits/client # 1000 hits/client
# total_hits:50000 # total_hits:50000
# 2255.858 seconds # 2255.858 seconds
# total hits/sec:22.165 # total hits/sec:22.165
# Max. number of concurrent sessions: 50 # Max. number of concurrent sessions: 50
...@@ -62,12 +62,12 @@ class test_server (asyncore.dispatcher): ...@@ -62,12 +62,12 @@ class test_server (asyncore.dispatcher):
conn, addr = self.accept() conn, addr = self.accept()
test_channel (conn, addr) test_channel (conn, addr)
# ================================================== # ==================================================
# client # client
# ================================================== # ==================================================
# pretty much the same behavior, except that we kick # pretty much the same behavior, except that we kick
# off the exchange and decide when to quit # off the exchange and decide when to quit
class test_client (test_channel): class test_client (test_channel):
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = "$Id: select_trigger.py,v 1.2 2001/04/25 19:09:56 andreas Exp $" VERSION_STRING = "$Id: select_trigger.py,v 1.3 2001/05/01 11:45:27 andreas Exp $"
import asyncore import asyncore
import asynchat import asynchat
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = "$Id: thread_channel.py,v 1.2 2001/04/25 19:09:56 andreas Exp $" VERSION_STRING = "$Id: thread_channel.py,v 1.3 2001/05/01 11:45:27 andreas Exp $"
# This will probably only work on Unix. # This will probably only work on Unix.
...@@ -72,7 +72,7 @@ class thread_channel (asyncore.file_dispatcher): ...@@ -72,7 +72,7 @@ class thread_channel (asyncore.file_dispatcher):
# the parent channel here. # the parent channel here.
self.close() self.close()
# Yeah, it's bad when the test code is bigger than the library code. # Yeah, it's bad when the test code is bigger than the library code.
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -320,9 +320,9 @@ class request_loop_thread (threading.Thread): ...@@ -320,9 +320,9 @@ class request_loop_thread (threading.Thread):
function (env, stdin, stdout) function (env, stdin, stdout)
stdout.close() stdout.close()
# =========================================================================== # ===========================================================================
# Testing # Testing
# =========================================================================== # ===========================================================================
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: unix_user_handler.py,v 1.2 2001/04/25 19:07:34 andreas Exp $' RCS_ID = '$Id: unix_user_handler.py,v 1.3 2001/05/01 11:44:49 andreas Exp $'
# support for `~user/public_html'. # support for `~user/public_html'.
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# Based on "xmlrpcserver.py" by Fredrik Lundh (fredrik@pythonware.com) # Based on "xmlrpcserver.py" by Fredrik Lundh (fredrik@pythonware.com)
VERSION = "$Id: xmlrpc_handler.py,v 1.2 2001/04/25 19:07:34 andreas Exp $" VERSION = "$Id: xmlrpc_handler.py,v 1.3 2001/05/01 11:44:49 andreas Exp $"
import http_server import http_server
import xmlrpclib import xmlrpclib
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: asynchat.py,v 1.16 2001/04/25 19:07:29 andreas Exp $ # $Id: asynchat.py,v 1.17 2001/05/01 11:44:48 andreas Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# ====================================================================== # ======================================================================
...@@ -270,20 +270,20 @@ class fifo: ...@@ -270,20 +270,20 @@ class fifo:
else: else:
return (0, None) return (0, None)
# Given 'haystack', see if any prefix of 'needle' is at its end. This # Given 'haystack', see if any prefix of 'needle' is at its end. This
# assumes an exact match has already been checked. Return the number of # assumes an exact match has already been checked. Return the number of
# characters matched. # characters matched.
# for example: # for example:
# f_p_a_e ("qwerty\r", "\r\n") => 1 # f_p_a_e ("qwerty\r", "\r\n") => 1
# f_p_a_e ("qwertydkjf", "\r\n") => 0 # f_p_a_e ("qwertydkjf", "\r\n") => 0
# f_p_a_e ("qwerty\r\n", "\r\n") => <undefined> # f_p_a_e ("qwerty\r\n", "\r\n") => <undefined>
# this could maybe be made faster with a computed regex? # this could maybe be made faster with a computed regex?
# [answer: no; circa Python-2.0, Jan 2001] # [answer: no; circa Python-2.0, Jan 2001]
# new python: 28961/s # new python: 28961/s
# old python: 18307/s # old python: 18307/s
# re: 12820/s # re: 12820/s
# regex: 14035/s # regex: 14035/s
def find_prefix_at_end (haystack, needle): def find_prefix_at_end (haystack, needle):
l = len(needle) - 1 l = len(needle) - 1
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: auth_handler.py,v 1.2 2001/04/25 19:07:30 andreas Exp $' RCS_ID = '$Id: auth_handler.py,v 1.3 2001/05/01 11:44:48 andreas Exp $'
# support for 'basic' authenticaion. # support for 'basic' authenticaion.
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: chat_server.py,v 1.2 2001/04/25 19:07:30 andreas Exp $' RCS_ID = '$Id: chat_server.py,v 1.3 2001/05/01 11:44:48 andreas Exp $'
import string import string
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: default_handler.py,v 1.6 2001/04/25 19:07:30 andreas Exp $' RCS_ID = '$Id: default_handler.py,v 1.7 2001/05/01 11:44:48 andreas Exp $'
# standard python modules # standard python modules
import os import os
...@@ -190,9 +190,9 @@ class default_handler: ...@@ -190,9 +190,9 @@ class default_handler:
+ '</ul>' + '</ul>'
) )
# HTTP/1.0 doesn't say anything about the "; length=nnnn" addition # HTTP/1.0 doesn't say anything about the "; length=nnnn" addition
# to this header. I suppose it's purpose is to avoid the overhead # to this header. I suppose it's purpose is to avoid the overhead
# of parsing dates... # of parsing dates...
IF_MODIFIED_SINCE = re.compile ( IF_MODIFIED_SINCE = re.compile (
'If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)', 'If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)',
re.IGNORECASE re.IGNORECASE
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
# $Id: filesys.py,v 1.8 2001/04/27 18:25:42 andreas Exp $ # $Id: filesys.py,v 1.9 2001/05/01 11:44:48 andreas Exp $
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# #
# Generic filesystem interface. # Generic filesystem interface.
...@@ -59,15 +59,15 @@ class abstract_filesystem: ...@@ -59,15 +59,15 @@ class abstract_filesystem:
[for the output of the LIST command]""" [for the output of the LIST command]"""
pass pass
# standard wrapper around a unix-like filesystem, with a 'false root' # standard wrapper around a unix-like filesystem, with a 'false root'
# capability. # capability.
# security considerations: can symbolic links be used to 'escape' the # security considerations: can symbolic links be used to 'escape' the
# root? should we allow it? if not, then we could scan the # root? should we allow it? if not, then we could scan the
# filesystem on startup, but that would not help if they were added # filesystem on startup, but that would not help if they were added
# later. We will probably need to check for symlinks in the cwd method. # later. We will probably need to check for symlinks in the cwd method.
# what to do if wd is an invalid directory? # what to do if wd is an invalid directory?
import os,re import os,re
import stat import stat
...@@ -251,88 +251,88 @@ if os.name == 'posix': ...@@ -251,88 +251,88 @@ if os.name == 'posix':
finally: finally:
self.become_nobody() self.become_nobody()
# This hasn't been very reliable across different platforms. # This hasn't been very reliable across different platforms.
# maybe think about a separate 'directory server'. # maybe think about a separate 'directory server'.
# #
# import posixpath # import posixpath
# import fcntl # import fcntl
# import FCNTL # import FCNTL
# import select # import select
# import asyncore # import asyncore
# #
# # pipes /bin/ls for directory listings. # # pipes /bin/ls for directory listings.
# class unix_filesystem (os_filesystem): # class unix_filesystem (os_filesystem):
# pass # pass
# path_module = posixpath # path_module = posixpath
# #
# def listdir (self, path, long=0): # def listdir (self, path, long=0):
# p = self.translate (path) # p = self.translate (path)
# if not long: # if not long:
# return list_producer (os.listdir (p), 0, None) # return list_producer (os.listdir (p), 0, None)
# else: # else:
# command = '/bin/ls -l %s' % p # command = '/bin/ls -l %s' % p
# print 'opening pipe to "%s"' % command # print 'opening pipe to "%s"' % command
# fd = os.popen (command, 'rt') # fd = os.popen (command, 'rt')
# return pipe_channel (fd) # return pipe_channel (fd)
# #
# # this is both a dispatcher, _and_ a producer # # this is both a dispatcher, _and_ a producer
# class pipe_channel (asyncore.file_dispatcher): # class pipe_channel (asyncore.file_dispatcher):
# buffer_size = 4096 # buffer_size = 4096
# #
# def __init__ (self, fd): # def __init__ (self, fd):
# asyncore.file_dispatcher.__init__ (self, fd) # asyncore.file_dispatcher.__init__ (self, fd)
# self.fd = fd # self.fd = fd
# self.done = 0 # self.done = 0
# self.data = '' # self.data = ''
# #
# def handle_read (self): # def handle_read (self):
# if len (self.data) < self.buffer_size: # if len (self.data) < self.buffer_size:
# self.data = self.data + self.fd.read (self.buffer_size) # self.data = self.data + self.fd.read (self.buffer_size)
# #print '%s.handle_read() => len(self.data) == %d' % (self, len(self.data)) # #print '%s.handle_read() => len(self.data) == %d' % (self, len(self.data))
# #
# def handle_expt (self): # def handle_expt (self):
# #print '%s.handle_expt()' % self # #print '%s.handle_expt()' % self
# self.done = 1 # self.done = 1
# #
# def ready (self): # def ready (self):
# #print '%s.ready() => %d' % (self, len(self.data)) # #print '%s.ready() => %d' % (self, len(self.data))
# return ((len (self.data) > 0) or self.done) # return ((len (self.data) > 0) or self.done)
# #
# def more (self): # def more (self):
# if self.data: # if self.data:
# r = self.data # r = self.data
# self.data = '' # self.data = ''
# elif self.done: # elif self.done:
# self.close() # self.close()
# self.downstream.finished() # self.downstream.finished()
# r = '' # r = ''
# else: # else:
# r = None # r = None
# #print '%s.more() => %s' % (self, (r and len(r))) # #print '%s.more() => %s' % (self, (r and len(r)))
# return r # return r
# For the 'real' root, we could obtain a list of drives, and then # For the 'real' root, we could obtain a list of drives, and then
# use that. Doesn't win32 provide such a 'real' filesystem? # use that. Doesn't win32 provide such a 'real' filesystem?
# [yes, I think something like this "\\.\c\windows"] # [yes, I think something like this "\\.\c\windows"]
class msdos_filesystem (os_filesystem): class msdos_filesystem (os_filesystem):
def longify (self, (path, stat_info)): def longify (self, (path, stat_info)):
return msdos_longify (path, stat_info) return msdos_longify (path, stat_info)
# A merged filesystem will let you plug other filesystems together. # A merged filesystem will let you plug other filesystems together.
# We really need the equivalent of a 'mount' capability - this seems # We really need the equivalent of a 'mount' capability - this seems
# to be the most general idea. So you'd use a 'mount' method to place # to be the most general idea. So you'd use a 'mount' method to place
# another filesystem somewhere in the hierarchy. # another filesystem somewhere in the hierarchy.
# Note: this is most likely how I will handle ~user directories # Note: this is most likely how I will handle ~user directories
# with the http server. # with the http server.
class merged_filesystem: class merged_filesystem:
def __init__ (self, *fsys): def __init__ (self, *fsys):
pass pass
# this matches the output of NT's ftp server (when in # this matches the output of NT's ftp server (when in
# MSDOS mode) exactly. # MSDOS mode) exactly.
def msdos_longify (file, stat_info): def msdos_longify (file, stat_info):
if stat.S_ISDIR (stat_info[stat.ST_MODE]): if stat.S_ISDIR (stat_info[stat.ST_MODE]):
...@@ -403,12 +403,12 @@ def unix_longify (file, stat_info): ...@@ -403,12 +403,12 @@ def unix_longify (file, stat_info):
file file
) )
# Emulate the unix 'ls' command's date field. # Emulate the unix 'ls' command's date field.
# it has two formats - if the date is more than 180 # it has two formats - if the date is more than 180
# days in the past, then it's like this: # days in the past, then it's like this:
# Oct 19 1995 # Oct 19 1995
# otherwise, it looks like this: # otherwise, it looks like this:
# Oct 19 17:33 # Oct 19 17:33
def ls_date (now, t): def ls_date (now, t):
try: try:
...@@ -430,9 +430,9 @@ def ls_date (now, t): ...@@ -430,9 +430,9 @@ def ls_date (now, t):
info[4] info[4]
) )
# =========================================================================== # ===========================================================================
# Producers # Producers
# =========================================================================== # ===========================================================================
class list_producer: class list_producer:
def __init__ (self, file_list, long, longify): def __init__ (self, file_list, long, longify):
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: ftp_server.py,v 1.16 2001/04/27 18:26:51 andreas Exp $' RCS_ID = '$Id: ftp_server.py,v 1.17 2001/05/01 11:44:48 andreas Exp $'
# An extensible, configurable, asynchronous FTP server. # An extensible, configurable, asynchronous FTP server.
# #
...@@ -99,8 +99,8 @@ class ftp_channel (asynchat.async_chat): ...@@ -99,8 +99,8 @@ class ftp_channel (asynchat.async_chat):
) )
) )
# def __del__ (self): # def __del__ (self):
# print 'ftp_channel.__del__()' # print 'ftp_channel.__del__()'
# -------------------------------------------------- # --------------------------------------------------
# async-library methods # async-library methods
...@@ -633,15 +633,15 @@ class ftp_channel (asynchat.async_chat): ...@@ -633,15 +633,15 @@ class ftp_channel (asynchat.async_chat):
else: else:
self.respond ('502 Unimplemented MODE type') self.respond ('502 Unimplemented MODE type')
# The stat command has two personalities. Normally it returns status # The stat command has two personalities. Normally it returns status
# information about the current connection. But if given an argument, # information about the current connection. But if given an argument,
# it is equivalent to the LIST command, with the data sent over the # it is equivalent to the LIST command, with the data sent over the
# control connection. Strange. But wuftpd, ftpd, and nt's ftp server # control connection. Strange. But wuftpd, ftpd, and nt's ftp server
# all support it. # all support it.
# #
## def cmd_stat (self, line): ## def cmd_stat (self, line):
## 'return status of server' ## 'return status of server'
## pass ## pass
def cmd_syst (self, line): def cmd_syst (self, line):
'show operating system type of server system' 'show operating system type of server system'
...@@ -777,32 +777,32 @@ class ftp_server (asyncore.dispatcher): ...@@ -777,32 +777,32 @@ class ftp_server (asyncore.dispatcher):
] ]
) )
# ====================================================================== # ======================================================================
# Data Channel Classes # Data Channel Classes
# ====================================================================== # ======================================================================
# This socket accepts a data connection, used when the server has been # This socket accepts a data connection, used when the server has been
# placed in passive mode. Although the RFC implies that we ought to # placed in passive mode. Although the RFC implies that we ought to
# be able to use the same acceptor over and over again, this presents # be able to use the same acceptor over and over again, this presents
# a problem: how do we shut it off, so that we are accepting # a problem: how do we shut it off, so that we are accepting
# connections only when we expect them? [we can't] # connections only when we expect them? [we can't]
# #
# wuftpd, and probably all the other servers, solve this by allowing # wuftpd, and probably all the other servers, solve this by allowing
# only one connection to hit this acceptor. They then close it. Any # only one connection to hit this acceptor. They then close it. Any
# subsequent data-connection command will then try for the default # subsequent data-connection command will then try for the default
# port on the client side [which is of course never there]. So the # port on the client side [which is of course never there]. So the
# 'always-send-PORT/PASV' behavior seems required. # 'always-send-PORT/PASV' behavior seems required.
# #
# Another note: wuftpd will also be listening on the channel as soon # Another note: wuftpd will also be listening on the channel as soon
# as the PASV command is sent. It does not wait for a data command # as the PASV command is sent. It does not wait for a data command
# first. # first.
# --- we need to queue up a particular behavior: # --- we need to queue up a particular behavior:
# 1) xmit : queue up producer[s] # 1) xmit : queue up producer[s]
# 2) recv : the file object # 2) recv : the file object
# #
# It would be nice if we could make both channels the same. Hmmm.. # It would be nice if we could make both channels the same. Hmmm..
# #
class passive_acceptor (asyncore.dispatcher): class passive_acceptor (asyncore.dispatcher):
ready = None ready = None
...@@ -821,8 +821,8 @@ class passive_acceptor (asyncore.dispatcher): ...@@ -821,8 +821,8 @@ class passive_acceptor (asyncore.dispatcher):
self.addr = self.getsockname() self.addr = self.getsockname()
self.listen (1) self.listen (1)
# def __del__ (self): # def __del__ (self):
# print 'passive_acceptor.__del__()' # print 'passive_acceptor.__del__()'
def log (self, *ignore): def log (self, *ignore):
pass pass
...@@ -854,8 +854,8 @@ class xmit_channel (asynchat.async_chat): ...@@ -854,8 +854,8 @@ class xmit_channel (asynchat.async_chat):
self.client_addr = client_addr self.client_addr = client_addr
asynchat.async_chat.__init__ (self) asynchat.async_chat.__init__ (self)
# def __del__ (self): # def __del__ (self):
# print 'xmit_channel.__del__()' # print 'xmit_channel.__del__()'
def log (*args): def log (*args):
pass pass
...@@ -962,9 +962,9 @@ class anon_authorizer: ...@@ -962,9 +962,9 @@ class anon_authorizer:
else: else:
return 0, 'Password invalid.', None return 0, 'Password invalid.', None
# =========================================================================== # ===========================================================================
# Unix-specific improvements # Unix-specific improvements
# =========================================================================== # ===========================================================================
if os.name == 'posix': if os.name == 'posix':
...@@ -1046,9 +1046,9 @@ class file_producer: ...@@ -1046,9 +1046,9 @@ class file_producer:
self.done = 1 self.done = 1
return block return block
# usage: ftp_server /PATH/TO/FTP/ROOT PORT # usage: ftp_server /PATH/TO/FTP/ROOT PORT
# for example: # for example:
# $ ftp_server /home/users/ftp 8021 # $ ftp_server /home/users/ftp 8021
if os.name == 'posix': if os.name == 'posix':
def test (port='8021'): def test (port='8021'):
...@@ -1067,17 +1067,17 @@ if os.name == 'posix': ...@@ -1067,17 +1067,17 @@ if os.name == 'posix':
if __name__ == '__main__': if __name__ == '__main__':
test (sys.argv[1]) test (sys.argv[1])
# not unix # not unix
else: else:
def test (): def test ():
fs = ftp_server (dummy_authorizer()) fs = ftp_server (dummy_authorizer())
if __name__ == '__main__': if __name__ == '__main__':
test () test ()
# this is the command list from the wuftpd man page # this is the command list from the wuftpd man page
# '*' means we've implemented it. # '*' means we've implemented it.
# '!' requires write access # '!' requires write access
# #
command_documentation = { command_documentation = {
'abor': 'abort previous command', #* 'abor': 'abort previous command', #*
'acct': 'specify account (ignored)', 'acct': 'specify account (ignored)',
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import string import string
import regex import regex
RCS_ID = '$Id: http_bobo.py,v 1.3 2001/04/26 00:07:52 andreas Exp $' RCS_ID = '$Id: http_bobo.py,v 1.4 2001/05/01 11:44:48 andreas Exp $'
VERSION_STRING = string.split(RCS_ID)[2] VERSION_STRING = string.split(RCS_ID)[2]
class bobo_extension: class bobo_extension:
......
...@@ -68,7 +68,7 @@ def unpack_rfc822 (m): ...@@ -68,7 +68,7 @@ def unpack_rfc822 (m):
0 0
) )
# rfc850 format # rfc850 format
rfc850_date = join ( rfc850_date = join (
[concat (long_day_reg,','), [concat (long_day_reg,','),
join ( join (
...@@ -101,8 +101,8 @@ def unpack_rfc850 (m): ...@@ -101,8 +101,8 @@ def unpack_rfc850 (m):
0 0
) )
# parsdate.parsedate - ~700/sec. # parsdate.parsedate - ~700/sec.
# parse_http_date - ~1333/sec. # parse_http_date - ~1333/sec.
def build_http_date (when): def build_http_date (when):
return time.strftime ('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(when)) return time.strftime ('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(when))
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: http_server.py,v 1.23 2001/04/30 14:38:40 andreas Exp $' RCS_ID = '$Id: http_server.py,v 1.24 2001/05/01 11:44:48 andreas Exp $'
# python modules # python modules
import os import os
...@@ -331,9 +331,9 @@ class http_request: ...@@ -331,9 +331,9 @@ class http_request:
) )
# =========================================================================== # ===========================================================================
# HTTP Channel Object # HTTP Channel Object
# =========================================================================== # ===========================================================================
class http_channel (asynchat.async_chat): class http_channel (asynchat.async_chat):
...@@ -523,9 +523,9 @@ class http_channel (asynchat.async_chat): ...@@ -523,9 +523,9 @@ class http_channel (asynchat.async_chat):
else: else:
return 1 return 1
# =========================================================================== # ===========================================================================
# HTTP Server Object # HTTP Server Object
# =========================================================================== # ===========================================================================
class http_server (asyncore.dispatcher): class http_server (asyncore.dispatcher):
...@@ -748,7 +748,7 @@ def compute_timezone_for_log (): ...@@ -748,7 +748,7 @@ def compute_timezone_for_log ():
else: else:
return '+%02d%02d' % (h, m) return '+%02d%02d' % (h, m)
# if you run this program over a TZ change boundary, this will be invalid. # if you run this program over a TZ change boundary, this will be invalid.
tz_for_log = compute_timezone_for_log() tz_for_log = compute_timezone_for_log()
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -76,11 +76,11 @@ class file_logger: ...@@ -76,11 +76,11 @@ class file_logger:
else: else:
self.write (message) self.write (message)
# like a file_logger, but it must be attached to a filename. # like a file_logger, but it must be attached to a filename.
# When the log gets too full, or a certain time has passed, # When the log gets too full, or a certain time has passed,
# it backs up the log and starts a new one. Note that backing # it backs up the log and starts a new one. Note that backing
# up the log is done via "mv" because anything else (cp, gzip) # up the log is done via "mv" because anything else (cp, gzip)
# would take time, during which medusa would do nothing else. # would take time, during which medusa would do nothing else.
class rotating_file_logger (file_logger): class rotating_file_logger (file_logger):
...@@ -142,14 +142,14 @@ class rotating_file_logger (file_logger): ...@@ -142,14 +142,14 @@ class rotating_file_logger (file_logger):
except: except:
pass pass
# syslog is a line-oriented log protocol - this class would be # syslog is a line-oriented log protocol - this class would be
# appropriate for FTP or HTTP logs, but not for dumping stderr to. # appropriate for FTP or HTTP logs, but not for dumping stderr to.
# TODO: a simple safety wrapper that will ensure that the line sent # TODO: a simple safety wrapper that will ensure that the line sent
# to syslog is reasonable. # to syslog is reasonable.
# TODO: async version of syslog_client: now, log entries use blocking # TODO: async version of syslog_client: now, log entries use blocking
# send() # send()
import m_syslog import m_syslog
syslog_logger = m_syslog.syslog_client syslog_logger = m_syslog.syslog_client
...@@ -171,7 +171,7 @@ class syslog_logger (m_syslog.syslog_client): ...@@ -171,7 +171,7 @@ class syslog_logger (m_syslog.syslog_client):
priority=m_syslog.LOG_INFO priority=m_syslog.LOG_INFO
) )
# log to a stream socket, asynchronously # log to a stream socket, asynchronously
class socket_logger (asynchat.async_chat): class socket_logger (asynchat.async_chat):
...@@ -194,7 +194,7 @@ class socket_logger (asynchat.async_chat): ...@@ -194,7 +194,7 @@ class socket_logger (asynchat.async_chat):
else: else:
self.socket.push (message) self.socket.push (message)
# log to multiple places # log to multiple places
class multi_logger: class multi_logger:
def __init__ (self, loggers): def __init__ (self, loggers):
self.loggers = loggers self.loggers = loggers
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = '$Id: async_mysql.py,v 1.2 2001/04/25 19:09:49 andreas Exp $' VERSION_STRING = '$Id: async_mysql.py,v 1.3 2001/05/01 11:45:26 andreas Exp $'
import exceptions import exceptions
import math import math
...@@ -17,18 +17,18 @@ from fifo import fifo ...@@ -17,18 +17,18 @@ from fifo import fifo
class mysql_error (exceptions.Exception): class mysql_error (exceptions.Exception):
pass pass
# =========================================================================== # ===========================================================================
# Authentication # Authentication
# =========================================================================== # ===========================================================================
# Note: I've ignored the stuff to support an older version of the protocol. # Note: I've ignored the stuff to support an older version of the protocol.
# #
# The code is based on the file mysql-3.21.33/client/password.c # The code is based on the file mysql-3.21.33/client/password.c
# #
# The auth scheme is challenge/response. Upon connection the server # The auth scheme is challenge/response. Upon connection the server
# sends an 8-byte challenge message. This is hashed with the password # sends an 8-byte challenge message. This is hashed with the password
# to produce an 8-byte response. The server side performs an identical # to produce an 8-byte response. The server side performs an identical
# hash to verify the password is correct. # hash to verify the password is correct.
class random_state: class random_state:
...@@ -73,9 +73,9 @@ def scramble (message, password): ...@@ -73,9 +73,9 @@ def scramble (message, password):
to[i] = to[i] ^ extra to[i] = to[i] ^ extra
return to return to
# =========================================================================== # ===========================================================================
# Packet Protocol # Packet Protocol
# =========================================================================== # ===========================================================================
def unpacket (p): def unpacket (p):
# 3-byte length, one-byte packet number, followed by packet data # 3-byte length, one-byte packet number, followed by packet data
...@@ -110,7 +110,7 @@ def net_field_length (data, pos=0): ...@@ -110,7 +110,7 @@ def net_field_length (data, pos=0):
# libmysql adds 6, why? # libmysql adds 6, why?
return n_byte_num (data, 4), 5 return n_byte_num (data, 4), 5
# used to generate the dumps below # used to generate the dumps below
def dump_hex (s): def dump_hex (s):
r1 = [] r1 = []
r2 = [] r2 = []
...@@ -122,9 +122,9 @@ def dump_hex (s): ...@@ -122,9 +122,9 @@ def dump_hex (s):
r2.append (' ') r2.append (' ')
return string.join (r1, ''), string.join (r2, '') return string.join (r1, ''), string.join (r2, '')
# =========================================================================== # ===========================================================================
# MySQL Client # MySQL Client
# =========================================================================== # ===========================================================================
class mysql_client (asynchat.async_chat): class mysql_client (asynchat.async_chat):
...@@ -305,9 +305,9 @@ class mysql_client (asynchat.async_chat): ...@@ -305,9 +305,9 @@ class mysql_client (asynchat.async_chat):
def cmd_query (self, query, callback=None): def cmd_query (self, query, callback=None):
self.command ('query', query, result_set (callback)) self.command ('query', query, result_set (callback))
# =========================================================================== # ===========================================================================
# Result Set # Result Set
# =========================================================================== # ===========================================================================
class result_set: class result_set:
...@@ -440,59 +440,59 @@ if __name__ == '__main__': ...@@ -440,59 +440,59 @@ if __name__ == '__main__':
c = mysql_client (username, password, go, (host, 3306)) c = mysql_client (username, password, go, (host, 3306))
asyncore.loop() asyncore.loop()
# greeting: # greeting:
# * first byte is the protocol version (currently 10) # * first byte is the protocol version (currently 10)
# * null-terminated version string # * null-terminated version string
# * 4-byte thread id. # * 4-byte thread id.
# * 8-byte challenge # * 8-byte challenge
# * 2-byte server capabilities? # * 2-byte server capabilities?
# message = [0x00, 0x39, 0x4d, 0x59, 0x59, 0x31, 0x29, 0x79, 0x47] # message = [0x00, 0x39, 0x4d, 0x59, 0x59, 0x31, 0x29, 0x79, 0x47]
# password = [0x66, 0x6e, 0x6f, 0x72, 0x64] # password = [0x66, 0x6e, 0x6f, 0x72, 0x64]
# Handshake: # Handshake:
#---------------------------------------- #----------------------------------------
#<== 000 0a 33 2e 32 32 2e 31 30 2d 62 65 74 61 00 1b 00 00 00 39 4d 59 59 31 29 79 47 00 0c 00 #<== 000 0a 33 2e 32 32 2e 31 30 2d 62 65 74 61 00 1b 00 00 00 39 4d 59 59 31 29 79 47 00 0c 00
# 3 2 2 1 0 b e t a 9 M Y Y 1 y G # 3 2 2 1 0 b e t a 9 M Y Y 1 y G
#---------------------------------------- #----------------------------------------
#==> 1 #==> 1
# 05 00 00 00 10 72 75 73 68 69 6e 67 00 48 51 42 50 5d 4a 54 57 # 05 00 00 00 10 72 75 73 68 69 6e 67 00 48 51 42 50 5d 4a 54 57
# r u s h i n g H Q B P J T W # r u s h i n g H Q B P J T W
#---------------------------------------- #----------------------------------------
#<== 002 00 00 00 #<== 002 00 00 00
# Insertion/Query (no result set) # Insertion/Query (no result set)
#---------------------------------------- #----------------------------------------
#==> 0 #==> 0
# 03 69 6e 73 65 72 74 20 69 6e 74 6f 20 75 73 65 72 73 20 76 61 6c 75 65 73 20 28 22 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 22 2c 20 22 6e 22 29 # 03 69 6e 73 65 72 74 20 69 6e 74 6f 20 75 73 65 72 73 20 76 61 6c 75 65 73 20 28 22 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 22 2c 20 22 6e 22 29
# i n s e r t i n t o u s e r s v a l u e s a s d f a s d f a s d f n # i n s e r t i n t o u s e r s v a l u e s a s d f a s d f a s d f n
#---------------------------------------- #----------------------------------------
#<== 001 00 01 00 #<== 001 00 01 00
# Query (with result set) # Query (with result set)
#---------------------------------------- #----------------------------------------
#==> 0 #==> 0
# 03 73 65 6c 65 63 74 20 2a 20 66 72 6f 6d 20 75 73 65 72 73 # 03 73 65 6c 65 63 74 20 2a 20 66 72 6f 6d 20 75 73 65 72 73
# s e l e c t f r o m u s e r s # s e l e c t f r o m u s e r s
#---------------------------------------- #----------------------------------------
#<== 001 02 #<== 001 02
# #
#<== 002 05 75 73 65 72 73 04 6e 61 6d 65 03 80 00 00 01 fe 03 00 00 00 #<== 002 05 75 73 65 72 73 04 6e 61 6d 65 03 80 00 00 01 fe 03 00 00 00
# u s e r s n a m e # u s e r s n a m e
#<== 003 05 75 73 65 72 73 0a 69 73 62 6f 75 6e 63 69 6e 67 03 01 00 00 01 fe 03 00 00 00 #<== 003 05 75 73 65 72 73 0a 69 73 62 6f 75 6e 63 69 6e 67 03 01 00 00 01 fe 03 00 00 00
# u s e r s i s b o u n c i n g # u s e r s i s b o u n c i n g
#<== 004 fe #<== 004 fe
# #
#<== 005 15 72 75 73 68 69 6e 67 40 6e 69 67 68 74 6d 61 72 65 2e 63 6f 6d 01 6e #<== 005 15 72 75 73 68 69 6e 67 40 6e 69 67 68 74 6d 61 72 65 2e 63 6f 6d 01 6e
# r u s h i n g n i g h t m a r e c o m n # r u s h i n g n i g h t m a r e c o m n
#<== 006 0e 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 01 6e #<== 006 0e 61 73 64 66 40 61 73 64 66 2e 61 73 64 66 01 6e
# a s d f a s d f a s d f n # a s d f a s d f a s d f n
#<== 007 fe #<== 007 fe
# "use bouncer_test" # "use bouncer_test"
#==> 0 #==> 0
# 02 62 6f 75 6e 63 65 72 5f 74 65 73 74 # 02 62 6f 75 6e 63 65 72 5f 74 65 73 74
# b o u n c e r t e s t # b o u n c e r t e s t
#---------------------------------------- #----------------------------------------
#<== 001 00 00 00 #<== 001 00 00 00
...@@ -35,7 +35,7 @@ class recorder_server (asyncore.dispatcher): ...@@ -35,7 +35,7 @@ class recorder_server (asyncore.dispatcher):
print 'incoming connection',addr print 'incoming connection',addr
recorder_channel (conn, addr) recorder_channel (conn, addr)
# force a clean shutdown # force a clean shutdown
def shutdown(): def shutdown():
sm = asyncore.socket_map sm = asyncore.socket_map
asyncore.socket_map = {} asyncore.socket_map = {}
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# python REPL channel. # python REPL channel.
# #
RCS_ID = '$Id: monitor.py,v 1.11 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: monitor.py,v 1.12 2001/05/01 11:44:48 andreas Exp $'
import md5 import md5
import socket import socket
...@@ -268,8 +268,8 @@ class secure_monitor_server (monitor_server): ...@@ -268,8 +268,8 @@ class secure_monitor_server (monitor_server):
p.data = p.data + ('<br><b>Failed Authorizations:</b> %d' % self.failed_auths) p.data = p.data + ('<br><b>Failed Authorizations:</b> %d' % self.failed_auths)
return p return p
# don't try to print from within any of the methods # don't try to print from within any of the methods
# of this object. 8^) # of this object. 8^)
class output_producer: class output_producer:
def __init__ (self, channel, real_stderr): def __init__ (self, channel, real_stderr):
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
RCS_ID = '$Id: producers.py,v 1.9 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: producers.py,v 1.10 2001/05/01 11:44:48 andreas Exp $'
import string import string
...@@ -107,12 +107,12 @@ class file_producer: ...@@ -107,12 +107,12 @@ class file_producer:
else: else:
return data return data
# A simple output producer. This one does not [yet] have # A simple output producer. This one does not [yet] have
# the safety feature builtin to the monitor channel: runaway # the safety feature builtin to the monitor channel: runaway
# output will not be caught. # output will not be caught.
# don't try to print from within any of the methods # don't try to print from within any of the methods
# of this object. # of this object.
class output_producer: class output_producer:
"Acts like an output file; suitable for capturing sys.stdout" "Acts like an output file; suitable for capturing sys.stdout"
...@@ -215,13 +215,13 @@ class hooked_producer: ...@@ -215,13 +215,13 @@ class hooked_producer:
else: else:
return '' return ''
# HTTP 1.1 emphasizes that an advertised Content-Length header MUST be # HTTP 1.1 emphasizes that an advertised Content-Length header MUST be
# correct. In the face of Strange Files, it is conceivable that # correct. In the face of Strange Files, it is conceivable that
# reading a 'file' may produce an amount of data not matching that # reading a 'file' may produce an amount of data not matching that
# reported by os.stat() [text/binary mode issues, perhaps the file is # reported by os.stat() [text/binary mode issues, perhaps the file is
# being appended to, etc..] This makes the chunked encoding a True # being appended to, etc..] This makes the chunked encoding a True
# Blessing, and it really ought to be used even with normal files. # Blessing, and it really ought to be used even with normal files.
# How beautifully it blends with the concept of the producer. # How beautifully it blends with the concept of the producer.
class chunked_producer: class chunked_producer:
"""A producer that implements the 'chunked' transfer coding for HTTP/1.1. """A producer that implements the 'chunked' transfer coding for HTTP/1.1.
...@@ -254,10 +254,10 @@ class chunked_producer: ...@@ -254,10 +254,10 @@ class chunked_producer:
else: else:
return '' return ''
# Unfortunately this isn't very useful right now (Aug 97), because # Unfortunately this isn't very useful right now (Aug 97), because
# apparently the browsers don't do on-the-fly decompression. Which # apparently the browsers don't do on-the-fly decompression. Which
# is sad, because this could _really_ speed things up, especially for # is sad, because this could _really_ speed things up, especially for
# low-bandwidth clients (i.e., most everyone). # low-bandwidth clients (i.e., most everyone).
try: try:
import zlib import zlib
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: put_handler.py,v 1.2 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: put_handler.py,v 1.3 2001/05/01 11:44:48 andreas Exp $'
import re import re
import string import string
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: redirecting_handler.py,v 1.2 2001/04/25 19:07:33 andreas Exp $' RCS_ID = '$Id: redirecting_handler.py,v 1.3 2001/05/01 11:44:49 andreas Exp $'
import re import re
import counter import counter
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Author: Sam Rushing <rushing@nightmare.com> # Author: Sam Rushing <rushing@nightmare.com>
# #
RCS_ID = '$Id: resolver.py,v 1.8 2001/04/25 19:07:34 andreas Exp $' RCS_ID = '$Id: resolver.py,v 1.9 2001/05/01 11:44:49 andreas Exp $'
# Fast, low-overhead asynchronous name resolver. uses 'pre-cooked' # Fast, low-overhead asynchronous name resolver. uses 'pre-cooked'
...@@ -114,27 +114,27 @@ def unpack_ttl (r,pos): ...@@ -114,27 +114,27 @@ def unpack_ttl (r,pos):
map (ord, r[pos:pos+4]) map (ord, r[pos:pos+4])
) )
# resource record # resource record
# 1 1 1 1 1 1 # 1 1 1 1 1 1
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | | # | |
# / / # / /
# / NAME / # / NAME /
# | | # | |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | TYPE | # | TYPE |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | CLASS | # | CLASS |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | TTL | # | TTL |
# | | # | |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | RDLENGTH | # | RDLENGTH |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
# / RDATA / # / RDATA /
# / / # / /
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ # +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
def unpack_address_reply (r): def unpack_address_reply (r):
ancount = (ord(r[6])<<8) + (ord(r[7])) ancount = (ord(r[6])<<8) + (ord(r[7]))
...@@ -183,18 +183,18 @@ def unpack_ptr_reply (r): ...@@ -183,18 +183,18 @@ def unpack_ptr_reply (r):
return 0, None return 0, None
# This is a UDP (datagram) resolver. # This is a UDP (datagram) resolver.
# #
# It may be useful to implement a TCP resolver. This would presumably # It may be useful to implement a TCP resolver. This would presumably
# give us more reliable behavior when things get too busy. A TCP # give us more reliable behavior when things get too busy. A TCP
# client would have to manage the connection carefully, since the # client would have to manage the connection carefully, since the
# server is allowed to close it at will (the RFC recommends closing # server is allowed to close it at will (the RFC recommends closing
# after 2 minutes of idle time). # after 2 minutes of idle time).
# #
# Note also that the TCP client will have to prepend each request # Note also that the TCP client will have to prepend each request
# with a 2-byte length indicator (see rfc1035). # with a 2-byte length indicator (see rfc1035).
# #
class resolver (asyncore.dispatcher): class resolver (asyncore.dispatcher):
id = counter() id = counter()
...@@ -366,28 +366,28 @@ class caching_resolver (resolver): ...@@ -366,28 +366,28 @@ class caching_resolver (resolver):
+ '<br>Cache Hits: %s' % self.cache_hits + '<br>Cache Hits: %s' % self.cache_hits
) )
#test_reply = """\000\000\205\200\000\001\000\001\000\002\000\002\006squirl\011nightmare\003com\000\000\001\000\001\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\011nightmare\003com\000\000\002\000\001\000\001Q\200\000\002\300\014\3006\000\002\000\001\000\001Q\200\000\015\003ns1\003iag\003net\000\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\300]\000\001\000\001\000\000\350\227\000\004\314\033\322\005""" #test_reply = """\000\000\205\200\000\001\000\001\000\002\000\002\006squirl\011nightmare\003com\000\000\001\000\001\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\011nightmare\003com\000\000\002\000\001\000\001Q\200\000\002\300\014\3006\000\002\000\001\000\001Q\200\000\015\003ns1\003iag\003net\000\300\014\000\001\000\001\000\001Q\200\000\004\315\240\260\005\300]\000\001\000\001\000\000\350\227\000\004\314\033\322\005"""
# def test_unpacker (): # def test_unpacker ():
# print unpack_address_reply (test_reply) # print unpack_address_reply (test_reply)
# #
# import time # import time
# class timer: # class timer:
# def __init__ (self): # def __init__ (self):
# self.start = time.time() # self.start = time.time()
# def end (self): # def end (self):
# return time.time() - self.start # return time.time() - self.start
# #
# # I get ~290 unpacks per second for the typical case, compared to ~48 # # I get ~290 unpacks per second for the typical case, compared to ~48
# # using dnslib directly. also, that latter number does not include # # using dnslib directly. also, that latter number does not include
# # picking the actual data out. # # picking the actual data out.
# #
# def benchmark_unpacker(): # def benchmark_unpacker():
# #
# r = range(1000) # r = range(1000)
# t = timer() # t = timer()
# for i in r: # for i in r:
# unpack_address_reply (test_reply) # unpack_address_reply (test_reply)
# print '%.2f unpacks per second' % (1000.0 / t.end()) # print '%.2f unpacks per second' % (1000.0 / t.end())
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
......
...@@ -47,16 +47,16 @@ import errno ...@@ -47,16 +47,16 @@ import errno
class RPC_Error (exceptions.StandardError): class RPC_Error (exceptions.StandardError):
pass pass
# =========================================================================== # ===========================================================================
# RPC Client # RPC Client
# =========================================================================== # ===========================================================================
# request types: # request types:
# 0 call # 0 call
# 1 getattr # 1 getattr
# 2 setattr # 2 setattr
# 3 repr # 3 repr
# 4 del # 4 del
class rpc_proxy: class rpc_proxy:
...@@ -187,9 +187,9 @@ def rpc_connect (address = ('localhost', 8746)): ...@@ -187,9 +187,9 @@ def rpc_connect (address = ('localhost', 8746)):
rpc_connection.cache[address] = rpc_proxy (conn, oid) rpc_connection.cache[address] = rpc_proxy (conn, oid)
return rpc_connection.cache[address] return rpc_connection.cache[address]
# =========================================================================== # ===========================================================================
# fastrpc client # fastrpc client
# =========================================================================== # ===========================================================================
class fastrpc_proxy: class fastrpc_proxy:
...@@ -224,9 +224,9 @@ def fastrpc_connect (address = ('localhost', 8748)): ...@@ -224,9 +224,9 @@ def fastrpc_connect (address = ('localhost', 8748)):
rpc_connection.cache[address] = fastrpc_proxy (conn) rpc_connection.cache[address] = fastrpc_proxy (conn)
return rpc_connection.cache[address] return rpc_connection.cache[address]
# =========================================================================== # ===========================================================================
# async fastrpc client # async fastrpc client
# =========================================================================== # ===========================================================================
import asynchat import asynchat
import fifo import fifo
......
...@@ -202,21 +202,21 @@ class rpc_server (asyncore.dispatcher): ...@@ -202,21 +202,21 @@ class rpc_server (asyncore.dispatcher):
rpc_channel (self.root, conn, addr) rpc_channel (self.root, conn, addr)
# =========================================================================== # ===========================================================================
# Fast RPC server # Fast RPC server
# =========================================================================== # ===========================================================================
# no proxies, request consists # no proxies, request consists
# of a 'chain' of getattrs terminated by a __call__. # of a 'chain' of getattrs terminated by a __call__.
# Protocol: # Protocol:
# <path>.<to>.<object> ( <param1>, <param2>, ... ) # <path>.<to>.<object> ( <param1>, <param2>, ... )
# => ( <value1>, <value2>, ... ) # => ( <value1>, <value2>, ... )
# #
# #
# (<path>, <params>) # (<path>, <params>)
# path: tuple of strings # path: tuple of strings
# params: tuple of objects # params: tuple of objects
class fastrpc_channel (asynchat.async_chat): class fastrpc_channel (asynchat.async_chat):
...@@ -285,7 +285,7 @@ class fastrpc_server (asyncore.dispatcher): ...@@ -285,7 +285,7 @@ class fastrpc_server (asyncore.dispatcher):
conn, addr = self.accept() conn, addr = self.accept()
fastrpc_channel (self.root, conn, addr) fastrpc_channel (self.root, conn, addr)
# =========================================================================== # ===========================================================================
if __name__ == '__main__': if __name__ == '__main__':
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
RCS_ID = '$Id: asynchat_sendfile.py,v 1.2 2001/04/25 19:09:54 andreas Exp $' RCS_ID = '$Id: asynchat_sendfile.py,v 1.3 2001/05/01 11:45:27 andreas Exp $'
import sendfile import sendfile
import asynchat import asynchat
...@@ -49,9 +49,9 @@ class async_chat_with_sendfile (async_chat): ...@@ -49,9 +49,9 @@ class async_chat_with_sendfile (async_chat):
if callback is not None: if callback is not None:
callback (0, fd) callback (0, fd)
# here's how you might use this: # here's how you might use this:
# fd = os.open (filename, os.O_RDONLY, 0644) # fd = os.open (filename, os.O_RDONLY, 0644)
# size = os.lseek (fd, 0, 2) # size = os.lseek (fd, 0, 2)
# os.lseek (fd, 0, 0) # os.lseek (fd, 0, 0)
# self.push ('%08x' % size) # self.push ('%08x' % size)
# self.push_sendfile (fd, 0, size) # self.push_sendfile (fd, 0, size)
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
RCS_ID = '$Id: test_sendfile.py,v 1.2 2001/04/25 19:09:54 andreas Exp $' RCS_ID = '$Id: test_sendfile.py,v 1.3 2001/05/01 11:45:27 andreas Exp $'
import asyncore import asyncore
import os import os
......
...@@ -115,13 +115,13 @@ if os.name == 'posix': ...@@ -115,13 +115,13 @@ if os.name == 'posix':
uh = unix_user_handler.unix_user_handler ('public_html') uh = unix_user_handler.unix_user_handler ('public_html')
hs.install_handler (uh) hs.install_handler (uh)
# =========================================================================== # ===========================================================================
# FTP Server # FTP Server
# =========================================================================== # ===========================================================================
# Here we create an 'anonymous' ftp server. # Here we create an 'anonymous' ftp server.
# Note: the ftp server is read-only by default. [in this mode, all # Note: the ftp server is read-only by default. [in this mode, all
# 'write-capable' commands are unavailable] # 'write-capable' commands are unavailable]
ftp = ftp_server.ftp_server ( ftp = ftp_server.ftp_server (
ftp_server.anon_authorizer ( ftp_server.anon_authorizer (
...@@ -192,7 +192,7 @@ if os.name == 'posix': ...@@ -192,7 +192,7 @@ if os.name == 'posix':
os.setegid (gid) os.setegid (gid)
os.seteuid (uid) os.seteuid (uid)
# Finally, start up the server loop! This loop will not exit until # Finally, start up the server loop! This loop will not exit until
# all clients and servers are closed. You may cleanly shut the system # all clients and servers are closed. You may cleanly shut the system
# down by sending SIGINT (a.k.a. KeyboardInterrupt). # down by sending SIGINT (a.k.a. KeyboardInterrupt).
asyncore.loop() asyncore.loop()
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = "$Id: status_handler.py,v 1.6 2001/04/25 19:07:34 andreas Exp $" VERSION_STRING = "$Id: status_handler.py,v 1.7 2001/05/01 11:44:49 andreas Exp $"
# #
# medusa status extension # medusa status extension
...@@ -215,7 +215,7 @@ class channel_list_producer (lines_producer): ...@@ -215,7 +215,7 @@ class channel_list_producer (lines_producer):
) )
# this really needs a full-blown quoter... # this really needs a full-blown quoter...
def sanitize (s): def sanitize (s):
if '<' in s: if '<' in s:
s = string.join (string.split (s, '<'), '&lt;') s = string.join (string.split (s, '<'), '&lt;')
...@@ -238,11 +238,11 @@ def html_reprs (list, front='', back=''): ...@@ -238,11 +238,11 @@ def html_reprs (list, front='', back=''):
reprs.sort() reprs.sort()
return reprs return reprs
# for example, tera, giga, mega, kilo # for example, tera, giga, mega, kilo
# p_d (n, (1024, 1024, 1024, 1024)) # p_d (n, (1024, 1024, 1024, 1024))
# smallest divider goes first - for example # smallest divider goes first - for example
# minutes, hours, days # minutes, hours, days
# p_d (n, (60, 60, 24)) # p_d (n, (60, 60, 24))
def progressive_divide (n, parts): def progressive_divide (n, parts):
result = [] result = []
...@@ -252,7 +252,7 @@ def progressive_divide (n, parts): ...@@ -252,7 +252,7 @@ def progressive_divide (n, parts):
result.append (n) result.append (n)
return result return result
# b,k,m,g,t # b,k,m,g,t
def split_by_units (n, units, dividers, format_string): def split_by_units (n, units, dividers, format_string):
divs = progressive_divide (n, dividers) divs = progressive_divide (n, dividers)
result = [] result = []
......
...@@ -28,17 +28,17 @@ class http_client (asyncore.dispatcher_with_send): ...@@ -28,17 +28,17 @@ class http_client (asyncore.dispatcher_with_send):
def handle_connect (self): def handle_connect (self):
self.connected = 1 self.connected = 1
# blurt ('o') # blurt ('o')
self.send ('GET %s HTTP/1.0\r\n\r\n' % self.uri) self.send ('GET %s HTTP/1.0\r\n\r\n' % self.uri)
def handle_read (self): def handle_read (self):
# blurt ('.') # blurt ('.')
d = self.recv (8192) d = self.recv (8192)
self.bytes = self.bytes + len(d) self.bytes = self.bytes + len(d)
def handle_close (self): def handle_close (self):
global total_sessions global total_sessions
# blurt ('(%d)' % (self.bytes)) # blurt ('(%d)' % (self.bytes))
self.close() self.close()
total_sessions = total_sessions + 1 total_sessions = total_sessions + 1
if self.num: if self.num:
...@@ -89,10 +89,10 @@ if __name__ == '__main__': ...@@ -89,10 +89,10 @@ if __name__ == '__main__':
print 'Max. number of concurrent sessions: %d' % (MAX) print 'Max. number of concurrent sessions: %d' % (MAX)
# linux 2.x, talking to medusa # linux 2.x, talking to medusa
# 50 clients # 50 clients
# 1000 hits/client # 1000 hits/client
# total_hits:50000 # total_hits:50000
# 2255.858 seconds # 2255.858 seconds
# total hits/sec:22.165 # total hits/sec:22.165
# Max. number of concurrent sessions: 50 # Max. number of concurrent sessions: 50
...@@ -62,12 +62,12 @@ class test_server (asyncore.dispatcher): ...@@ -62,12 +62,12 @@ class test_server (asyncore.dispatcher):
conn, addr = self.accept() conn, addr = self.accept()
test_channel (conn, addr) test_channel (conn, addr)
# ================================================== # ==================================================
# client # client
# ================================================== # ==================================================
# pretty much the same behavior, except that we kick # pretty much the same behavior, except that we kick
# off the exchange and decide when to quit # off the exchange and decide when to quit
class test_client (test_channel): class test_client (test_channel):
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = "$Id: select_trigger.py,v 1.2 2001/04/25 19:09:56 andreas Exp $" VERSION_STRING = "$Id: select_trigger.py,v 1.3 2001/05/01 11:45:27 andreas Exp $"
import asyncore import asyncore
import asynchat import asynchat
......
# -*- Mode: Python; tab-width: 4 -*- # -*- Mode: Python; tab-width: 4 -*-
VERSION_STRING = "$Id: thread_channel.py,v 1.2 2001/04/25 19:09:56 andreas Exp $" VERSION_STRING = "$Id: thread_channel.py,v 1.3 2001/05/01 11:45:27 andreas Exp $"
# This will probably only work on Unix. # This will probably only work on Unix.
...@@ -72,7 +72,7 @@ class thread_channel (asyncore.file_dispatcher): ...@@ -72,7 +72,7 @@ class thread_channel (asyncore.file_dispatcher):
# the parent channel here. # the parent channel here.
self.close() self.close()
# Yeah, it's bad when the test code is bigger than the library code. # Yeah, it's bad when the test code is bigger than the library code.
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -320,9 +320,9 @@ class request_loop_thread (threading.Thread): ...@@ -320,9 +320,9 @@ class request_loop_thread (threading.Thread):
function (env, stdin, stdout) function (env, stdin, stdout)
stdout.close() stdout.close()
# =========================================================================== # ===========================================================================
# Testing # Testing
# =========================================================================== # ===========================================================================
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# All Rights Reserved. # All Rights Reserved.
# #
RCS_ID = '$Id: unix_user_handler.py,v 1.2 2001/04/25 19:07:34 andreas Exp $' RCS_ID = '$Id: unix_user_handler.py,v 1.3 2001/05/01 11:44:49 andreas Exp $'
# support for `~user/public_html'. # support for `~user/public_html'.
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment