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