Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ExeBy/smexe_ro.../usr/lib64/python2....
File: asynchat.py
# -*- Mode: Python; tab-width: 4 -*-
[0] Fix | Delete
# Id: asynchat.py,v 2.26 2000/09/07 22:29:26 rushing Exp
[1] Fix | Delete
# Author: Sam Rushing <rushing@nightmare.com>
[2] Fix | Delete
[3] Fix | Delete
# ======================================================================
[4] Fix | Delete
# Copyright 1996 by Sam Rushing
[5] Fix | Delete
#
[6] Fix | Delete
# All Rights Reserved
[7] Fix | Delete
#
[8] Fix | Delete
# Permission to use, copy, modify, and distribute this software and
[9] Fix | Delete
# its documentation for any purpose and without fee is hereby
[10] Fix | Delete
# granted, provided that the above copyright notice appear in all
[11] Fix | Delete
# copies and that both that copyright notice and this permission
[12] Fix | Delete
# notice appear in supporting documentation, and that the name of Sam
[13] Fix | Delete
# Rushing not be used in advertising or publicity pertaining to
[14] Fix | Delete
# distribution of the software without specific, written prior
[15] Fix | Delete
# permission.
[16] Fix | Delete
#
[17] Fix | Delete
# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
[18] Fix | Delete
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
[19] Fix | Delete
# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR
[20] Fix | Delete
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
[21] Fix | Delete
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
[22] Fix | Delete
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
[23] Fix | Delete
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
[24] Fix | Delete
# ======================================================================
[25] Fix | Delete
[26] Fix | Delete
r"""A class supporting chat-style (command/response) protocols.
[27] Fix | Delete
[28] Fix | Delete
This class adds support for 'chat' style protocols - where one side
[29] Fix | Delete
sends a 'command', and the other sends a response (examples would be
[30] Fix | Delete
the common internet protocols - smtp, nntp, ftp, etc..).
[31] Fix | Delete
[32] Fix | Delete
The handle_read() method looks at the input stream for the current
[33] Fix | Delete
'terminator' (usually '\r\n' for single-line responses, '\r\n.\r\n'
[34] Fix | Delete
for multi-line output), calling self.found_terminator() on its
[35] Fix | Delete
receipt.
[36] Fix | Delete
[37] Fix | Delete
for example:
[38] Fix | Delete
Say you build an async nntp client using this class. At the start
[39] Fix | Delete
of the connection, you'll have self.terminator set to '\r\n', in
[40] Fix | Delete
order to process the single-line greeting. Just before issuing a
[41] Fix | Delete
'LIST' command you'll set it to '\r\n.\r\n'. The output of the LIST
[42] Fix | Delete
command will be accumulated (using your own 'collect_incoming_data'
[43] Fix | Delete
method) up to the terminator, and then control will be returned to
[44] Fix | Delete
you - by calling your self.found_terminator() method.
[45] Fix | Delete
"""
[46] Fix | Delete
[47] Fix | Delete
import asyncore
[48] Fix | Delete
import errno
[49] Fix | Delete
import socket
[50] Fix | Delete
from collections import deque
[51] Fix | Delete
from sys import py3kwarning
[52] Fix | Delete
from warnings import filterwarnings, catch_warnings
[53] Fix | Delete
[54] Fix | Delete
_BLOCKING_IO_ERRORS = (errno.EAGAIN, errno.EALREADY, errno.EINPROGRESS,
[55] Fix | Delete
errno.EWOULDBLOCK)
[56] Fix | Delete
[57] Fix | Delete
[58] Fix | Delete
class async_chat (asyncore.dispatcher):
[59] Fix | Delete
"""This is an abstract class. You must derive from this class, and add
[60] Fix | Delete
the two methods collect_incoming_data() and found_terminator()"""
[61] Fix | Delete
[62] Fix | Delete
# these are overridable defaults
[63] Fix | Delete
[64] Fix | Delete
ac_in_buffer_size = 4096
[65] Fix | Delete
ac_out_buffer_size = 4096
[66] Fix | Delete
[67] Fix | Delete
def __init__ (self, sock=None, map=None):
[68] Fix | Delete
# for string terminator matching
[69] Fix | Delete
self.ac_in_buffer = ''
[70] Fix | Delete
[71] Fix | Delete
# we use a list here rather than cStringIO for a few reasons...
[72] Fix | Delete
# del lst[:] is faster than sio.truncate(0)
[73] Fix | Delete
# lst = [] is faster than sio.truncate(0)
[74] Fix | Delete
# cStringIO will be gaining unicode support in py3k, which
[75] Fix | Delete
# will negatively affect the performance of bytes compared to
[76] Fix | Delete
# a ''.join() equivalent
[77] Fix | Delete
self.incoming = []
[78] Fix | Delete
[79] Fix | Delete
# we toss the use of the "simple producer" and replace it with
[80] Fix | Delete
# a pure deque, which the original fifo was a wrapping of
[81] Fix | Delete
self.producer_fifo = deque()
[82] Fix | Delete
asyncore.dispatcher.__init__ (self, sock, map)
[83] Fix | Delete
[84] Fix | Delete
def collect_incoming_data(self, data):
[85] Fix | Delete
raise NotImplementedError("must be implemented in subclass")
[86] Fix | Delete
[87] Fix | Delete
def _collect_incoming_data(self, data):
[88] Fix | Delete
self.incoming.append(data)
[89] Fix | Delete
[90] Fix | Delete
def _get_data(self):
[91] Fix | Delete
d = ''.join(self.incoming)
[92] Fix | Delete
del self.incoming[:]
[93] Fix | Delete
return d
[94] Fix | Delete
[95] Fix | Delete
def found_terminator(self):
[96] Fix | Delete
raise NotImplementedError("must be implemented in subclass")
[97] Fix | Delete
[98] Fix | Delete
def set_terminator (self, term):
[99] Fix | Delete
"Set the input delimiter. Can be a fixed string of any length, an integer, or None"
[100] Fix | Delete
self.terminator = term
[101] Fix | Delete
[102] Fix | Delete
def get_terminator (self):
[103] Fix | Delete
return self.terminator
[104] Fix | Delete
[105] Fix | Delete
# grab some more data from the socket,
[106] Fix | Delete
# throw it to the collector method,
[107] Fix | Delete
# check for the terminator,
[108] Fix | Delete
# if found, transition to the next state.
[109] Fix | Delete
[110] Fix | Delete
def handle_read (self):
[111] Fix | Delete
[112] Fix | Delete
try:
[113] Fix | Delete
data = self.recv (self.ac_in_buffer_size)
[114] Fix | Delete
except socket.error, why:
[115] Fix | Delete
if why.args[0] in _BLOCKING_IO_ERRORS:
[116] Fix | Delete
return
[117] Fix | Delete
self.handle_error()
[118] Fix | Delete
return
[119] Fix | Delete
[120] Fix | Delete
self.ac_in_buffer = self.ac_in_buffer + data
[121] Fix | Delete
[122] Fix | Delete
# Continue to search for self.terminator in self.ac_in_buffer,
[123] Fix | Delete
# while calling self.collect_incoming_data. The while loop
[124] Fix | Delete
# is necessary because we might read several data+terminator
[125] Fix | Delete
# combos with a single recv(4096).
[126] Fix | Delete
[127] Fix | Delete
while self.ac_in_buffer:
[128] Fix | Delete
lb = len(self.ac_in_buffer)
[129] Fix | Delete
terminator = self.get_terminator()
[130] Fix | Delete
if not terminator:
[131] Fix | Delete
# no terminator, collect it all
[132] Fix | Delete
self.collect_incoming_data (self.ac_in_buffer)
[133] Fix | Delete
self.ac_in_buffer = ''
[134] Fix | Delete
elif isinstance(terminator, (int, long)):
[135] Fix | Delete
# numeric terminator
[136] Fix | Delete
n = terminator
[137] Fix | Delete
if lb < n:
[138] Fix | Delete
self.collect_incoming_data (self.ac_in_buffer)
[139] Fix | Delete
self.ac_in_buffer = ''
[140] Fix | Delete
self.terminator = self.terminator - lb
[141] Fix | Delete
else:
[142] Fix | Delete
self.collect_incoming_data (self.ac_in_buffer[:n])
[143] Fix | Delete
self.ac_in_buffer = self.ac_in_buffer[n:]
[144] Fix | Delete
self.terminator = 0
[145] Fix | Delete
self.found_terminator()
[146] Fix | Delete
else:
[147] Fix | Delete
# 3 cases:
[148] Fix | Delete
# 1) end of buffer matches terminator exactly:
[149] Fix | Delete
# collect data, transition
[150] Fix | Delete
# 2) end of buffer matches some prefix:
[151] Fix | Delete
# collect data to the prefix
[152] Fix | Delete
# 3) end of buffer does not match any prefix:
[153] Fix | Delete
# collect data
[154] Fix | Delete
terminator_len = len(terminator)
[155] Fix | Delete
index = self.ac_in_buffer.find(terminator)
[156] Fix | Delete
if index != -1:
[157] Fix | Delete
# we found the terminator
[158] Fix | Delete
if index > 0:
[159] Fix | Delete
# don't bother reporting the empty string (source of subtle bugs)
[160] Fix | Delete
self.collect_incoming_data (self.ac_in_buffer[:index])
[161] Fix | Delete
self.ac_in_buffer = self.ac_in_buffer[index+terminator_len:]
[162] Fix | Delete
# This does the Right Thing if the terminator is changed here.
[163] Fix | Delete
self.found_terminator()
[164] Fix | Delete
else:
[165] Fix | Delete
# check for a prefix of the terminator
[166] Fix | Delete
index = find_prefix_at_end (self.ac_in_buffer, terminator)
[167] Fix | Delete
if index:
[168] Fix | Delete
if index != lb:
[169] Fix | Delete
# we found a prefix, collect up to the prefix
[170] Fix | Delete
self.collect_incoming_data (self.ac_in_buffer[:-index])
[171] Fix | Delete
self.ac_in_buffer = self.ac_in_buffer[-index:]
[172] Fix | Delete
break
[173] Fix | Delete
else:
[174] Fix | Delete
# no prefix, collect it all
[175] Fix | Delete
self.collect_incoming_data (self.ac_in_buffer)
[176] Fix | Delete
self.ac_in_buffer = ''
[177] Fix | Delete
[178] Fix | Delete
def handle_write (self):
[179] Fix | Delete
self.initiate_send()
[180] Fix | Delete
[181] Fix | Delete
def handle_close (self):
[182] Fix | Delete
self.close()
[183] Fix | Delete
[184] Fix | Delete
def push (self, data):
[185] Fix | Delete
sabs = self.ac_out_buffer_size
[186] Fix | Delete
if len(data) > sabs:
[187] Fix | Delete
for i in xrange(0, len(data), sabs):
[188] Fix | Delete
self.producer_fifo.append(data[i:i+sabs])
[189] Fix | Delete
else:
[190] Fix | Delete
self.producer_fifo.append(data)
[191] Fix | Delete
self.initiate_send()
[192] Fix | Delete
[193] Fix | Delete
def push_with_producer (self, producer):
[194] Fix | Delete
self.producer_fifo.append(producer)
[195] Fix | Delete
self.initiate_send()
[196] Fix | Delete
[197] Fix | Delete
def readable (self):
[198] Fix | Delete
"predicate for inclusion in the readable for select()"
[199] Fix | Delete
# cannot use the old predicate, it violates the claim of the
[200] Fix | Delete
# set_terminator method.
[201] Fix | Delete
[202] Fix | Delete
# return (len(self.ac_in_buffer) <= self.ac_in_buffer_size)
[203] Fix | Delete
return 1
[204] Fix | Delete
[205] Fix | Delete
def writable (self):
[206] Fix | Delete
"predicate for inclusion in the writable for select()"
[207] Fix | Delete
return self.producer_fifo or (not self.connected)
[208] Fix | Delete
[209] Fix | Delete
def close_when_done (self):
[210] Fix | Delete
"automatically close this channel once the outgoing queue is empty"
[211] Fix | Delete
self.producer_fifo.append(None)
[212] Fix | Delete
[213] Fix | Delete
def initiate_send(self):
[214] Fix | Delete
while self.producer_fifo and self.connected:
[215] Fix | Delete
first = self.producer_fifo[0]
[216] Fix | Delete
# handle empty string/buffer or None entry
[217] Fix | Delete
if not first:
[218] Fix | Delete
del self.producer_fifo[0]
[219] Fix | Delete
if first is None:
[220] Fix | Delete
self.handle_close()
[221] Fix | Delete
return
[222] Fix | Delete
[223] Fix | Delete
# handle classic producer behavior
[224] Fix | Delete
obs = self.ac_out_buffer_size
[225] Fix | Delete
try:
[226] Fix | Delete
with catch_warnings():
[227] Fix | Delete
if py3kwarning:
[228] Fix | Delete
filterwarnings("ignore", ".*buffer", DeprecationWarning)
[229] Fix | Delete
data = buffer(first, 0, obs)
[230] Fix | Delete
except TypeError:
[231] Fix | Delete
data = first.more()
[232] Fix | Delete
if data:
[233] Fix | Delete
self.producer_fifo.appendleft(data)
[234] Fix | Delete
else:
[235] Fix | Delete
del self.producer_fifo[0]
[236] Fix | Delete
continue
[237] Fix | Delete
[238] Fix | Delete
# send the data
[239] Fix | Delete
try:
[240] Fix | Delete
num_sent = self.send(data)
[241] Fix | Delete
except socket.error:
[242] Fix | Delete
self.handle_error()
[243] Fix | Delete
return
[244] Fix | Delete
[245] Fix | Delete
if num_sent:
[246] Fix | Delete
if num_sent < len(data) or obs < len(first):
[247] Fix | Delete
self.producer_fifo[0] = first[num_sent:]
[248] Fix | Delete
else:
[249] Fix | Delete
del self.producer_fifo[0]
[250] Fix | Delete
# we tried to send some actual data
[251] Fix | Delete
return
[252] Fix | Delete
[253] Fix | Delete
def discard_buffers (self):
[254] Fix | Delete
# Emergencies only!
[255] Fix | Delete
self.ac_in_buffer = ''
[256] Fix | Delete
del self.incoming[:]
[257] Fix | Delete
self.producer_fifo.clear()
[258] Fix | Delete
[259] Fix | Delete
class simple_producer:
[260] Fix | Delete
[261] Fix | Delete
def __init__ (self, data, buffer_size=512):
[262] Fix | Delete
self.data = data
[263] Fix | Delete
self.buffer_size = buffer_size
[264] Fix | Delete
[265] Fix | Delete
def more (self):
[266] Fix | Delete
if len (self.data) > self.buffer_size:
[267] Fix | Delete
result = self.data[:self.buffer_size]
[268] Fix | Delete
self.data = self.data[self.buffer_size:]
[269] Fix | Delete
return result
[270] Fix | Delete
else:
[271] Fix | Delete
result = self.data
[272] Fix | Delete
self.data = ''
[273] Fix | Delete
return result
[274] Fix | Delete
[275] Fix | Delete
class fifo:
[276] Fix | Delete
def __init__ (self, list=None):
[277] Fix | Delete
if not list:
[278] Fix | Delete
self.list = deque()
[279] Fix | Delete
else:
[280] Fix | Delete
self.list = deque(list)
[281] Fix | Delete
[282] Fix | Delete
def __len__ (self):
[283] Fix | Delete
return len(self.list)
[284] Fix | Delete
[285] Fix | Delete
def is_empty (self):
[286] Fix | Delete
return not self.list
[287] Fix | Delete
[288] Fix | Delete
def first (self):
[289] Fix | Delete
return self.list[0]
[290] Fix | Delete
[291] Fix | Delete
def push (self, data):
[292] Fix | Delete
self.list.append(data)
[293] Fix | Delete
[294] Fix | Delete
def pop (self):
[295] Fix | Delete
if self.list:
[296] Fix | Delete
return (1, self.list.popleft())
[297] Fix | Delete
else:
[298] Fix | Delete
return (0, None)
[299] Fix | Delete
[300] Fix | Delete
# Given 'haystack', see if any prefix of 'needle' is at its end. This
[301] Fix | Delete
# assumes an exact match has already been checked. Return the number of
[302] Fix | Delete
# characters matched.
[303] Fix | Delete
# for example:
[304] Fix | Delete
# f_p_a_e ("qwerty\r", "\r\n") => 1
[305] Fix | Delete
# f_p_a_e ("qwertydkjf", "\r\n") => 0
[306] Fix | Delete
# f_p_a_e ("qwerty\r\n", "\r\n") => <undefined>
[307] Fix | Delete
[308] Fix | Delete
# this could maybe be made faster with a computed regex?
[309] Fix | Delete
# [answer: no; circa Python-2.0, Jan 2001]
[310] Fix | Delete
# new python: 28961/s
[311] Fix | Delete
# old python: 18307/s
[312] Fix | Delete
# re: 12820/s
[313] Fix | Delete
# regex: 14035/s
[314] Fix | Delete
[315] Fix | Delete
def find_prefix_at_end (haystack, needle):
[316] Fix | Delete
l = len(needle) - 1
[317] Fix | Delete
while l and not haystack.endswith(needle[:l]):
[318] Fix | Delete
l -= 1
[319] Fix | Delete
return l
[320] Fix | Delete
[321] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function