beeseek-devs team mailing list archive
-
beeseek-devs team
-
Mailing list archive
-
Message #00108
[Branch ~beeseek-devs/beeseek/trunk] Rev 194: Merge highlevel-network-phase-2.
------------------------------------------------------------
revno: 194
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: trunk
timestamp: Wed 2009-01-14 13:48:11 +0100
message:
Merge highlevel-network-phase-2.
modified:
beeseek/honeybee/handler.py
beeseek/network/highlevel.py
beeseek/network/http.py
beeseek/network/lowlevel.py
beeseek/session.py
beeseek/utils/__init__.py
------------------------------------------------------------
revno: 186.1.34
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Tue 2009-01-13 17:34:37 +0100
message:
Update CONNECT method.
modified:
beeseek/honeybee/handler.py
beeseek/network/highlevel.py
beeseek/network/lowlevel.py
------------------------------------------------------------
revno: 186.1.33
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Tue 2009-01-13 17:04:40 +0100
message:
Update search code.
modified:
beeseek/honeybee/handler.py
------------------------------------------------------------
revno: 186.1.32
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Tue 2009-01-13 16:22:57 +0100
message:
Rename methods from raw* to raw_* to match the current implementation.
modified:
beeseek/network/http.py
------------------------------------------------------------
revno: 186.1.31
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Tue 2009-01-13 16:22:20 +0100
message:
Add missing methods to BaseApplication.
modified:
beeseek/network/highlevel.py
beeseek/network/lowlevel.py
------------------------------------------------------------
revno: 186.1.30
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Tue 2009-01-13 16:10:46 +0100
message:
Merge HTTPParser in HTTPApplication.
modified:
beeseek/network/http.py
------------------------------------------------------------
revno: 186.1.29
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Mon 2009-01-12 20:14:40 +0100
message:
Improved highlevel interfaces to use __init__ instead of __new__.
modified:
beeseek/network/highlevel.py
beeseek/network/http.py
beeseek/network/lowlevel.py
------------------------------------------------------------
revno: 186.1.28
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Sat 2009-01-10 19:01:57 +0100
message:
Adapt Honeybee code to the new HTTP interface.
modified:
beeseek/honeybee/handler.py
beeseek/session.py
------------------------------------------------------------
revno: 186.1.27
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Sat 2009-01-10 19:01:30 +0100
message:
Correct functioning of pop() method in CaseInsensitiveDict.
modified:
beeseek/utils/__init__.py
------------------------------------------------------------
revno: 186.1.26
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Sat 2009-01-10 19:01:06 +0100
message:
Set the _closed attribute to True when read methods return an empty
string.
modified:
beeseek/network/lowlevel.py
------------------------------------------------------------
revno: 186.1.25
committer: Andrea Corbellini <andrea.corbellini@xxxxxxxxxxx>
branch nick: network
timestamp: Sat 2009-01-10 18:59:40 +0100
message:
* Raise EOFError when starting reading from a closed socket
* Correct chunked connection write method
modified:
beeseek/network/highlevel.py
beeseek/network/http.py
=== modified file 'beeseek/honeybee/handler.py'
--- a/beeseek/honeybee/handler.py 2009-01-14 12:47:29 +0000
+++ b/beeseek/honeybee/handler.py 2009-01-14 12:48:11 +0000
@@ -20,20 +20,24 @@
from urllib import unquote_plus
from beeseek.interfaces import implements
from beeseek import network, log, instance
-from beeseek.network.http import HTTPServerApplication
-from beeseek.network.highlevel import (BaseConnectionHandler,
- IConnectionHandler)
+from beeseek.network.lowlevel import IPSocket
+from beeseek.network.highlevel import IServerApplication
+from beeseek.network.http import HTTPServerApplication, HTTPClientApplication
from beeseek.ui import html
from beeseek.database import nested
-class HoneybeeHandler(HTTPServerApplication, BaseConnectionHandler):
+class HoneybeeHandler(HTTPServerApplication):
- implements(IConnectionHandler)
+ __slots__ = ()
+ implements(IServerApplication)
def handle(self):
- self.readheaders()
- if self.requestline[0] == 'CONNECT':
+ try:
+ self.read_request()
+ except EOFError:
+ return
+ if self.requestline[0] == self.CONNECT:
self.handle_connect()
self.close()
return
@@ -48,23 +52,23 @@
page = ''
if hostname in ('beeseek.org', 'www.beeseek.org'):
+ headers = {'Server': 'Honeybee',
+ 'Transfer-Encoding': 'chunked'}
if page in ('search', 'search/'):
- if self.requestline[0] == 'POST':
+ if self.requestline[0] == self.POST:
keyword = self.read().split('=')[1]
- self.statusline[1:2] = ['301', 'Moved Permanently']
- self.serverheaders['Location'] = '/'.join(
- ('', 'search', keyword))
- self.writeheaders()
+ headers['Location'] = '/search/%s' % keyword
+ self.start_response(301, 'Moved Permanently',
+ headers)
self.write('Redirect')
- self.close()
- return
else:
- self.writeheaders()
+ self.start_response(200, 'OK', headers)
self.write(html.searchpage.format({'keywords': ''}))
- self.close()
- return
+ self.end_response()
+ self.flush()
+ return
elif page.startswith('search/'):
- self.writeheaders()
+ self.start_response(200, 'OK', headers)
keywords = unquote_plus(page.split('/', 1)[1])
results = self.handle_search(keywords)
try:
@@ -72,7 +76,8 @@
iterator=results))
except KeyError:
self.write('No results found.')
- self.close()
+ self.end_response()
+ self.flush()
return
if ':' in hostname:
@@ -83,44 +88,60 @@
page = '/' + page
headers = self.clientheaders
- if 'proxy-connection' in headers:
- close = headers.pop('proxy-connection').lower() == 'close'
+ if 'Proxy-Connection' in headers:
+ close = headers.pop('Proxy-Connection') == 'Close'
else:
close = True
- host = http.HTTPClient(connect=(hostname, port))
- host.clientheaders.update(headers)
- host.requestline[:] = self.requestline[:]
- host.requestline[1] = page
- host.writeheaders()
+ host = HTTPClientApplication()
+ host.connect((hostname, port))
+ info = self.requestline
+ host.start_request(info[0], page, headers, version=info[2])
host.write(self.read())
host.flush()
- host.readheaders()
- self.statusline[:] = host.statusline[:]
- self.serverheaders.update(host.serverheaders)
- self.writeheaders()
- self.write(host.read())
+ host.read_response()
+ info = host.statusline
+ self.start_response(info[0], info[1],
+ host.serverheaders, version=info[2])
+ data = host.read()
+ self.write(data)
+ self.end_response()
self.flush()
if close:
self.close()
+ # XXX Hey, the handler should set this automatically!
+ self.closed = True
def handle_connect(self):
- hostname, port = tuple(self.page.split(':'))
- host = network.BaseHandler(connect=(hostname, int(port)))
- self.statusexplanation = 'Connection established'
+ hostname, port = self.requestline[1].split(':')
+ host = IPSocket()
+ host.connect((hostname, int(port)))
+ self.start_response(200, 'Connection established', {})
self.flush()
- self.raw_transfer()
sockets = self, host
while True:
- for read in network.wait(*sockets):
- write = [sock for sock in sockets if sock is not read][0]
- data = read.recv(4096)
- if not data:
- return
- write.send(data)
+ for ready in select.select(sockets, (), ())[0]:
+ if ready is self:
+ data = self.raw_recv(4096)
+ if not data:
+ return
+ host.write(data)
+ host.flush()
+ else:
+ data = host.recv(4096)
+ if not data:
+ return
+ self.raw_write(data)
+ self.flush()
+# write = [sock for sock in sockets if sock is not read][0]
+# data = read.recv(4096)
+# if not data:
+# return
+# write.write(data)
+# write.flush()
def handle_search(self, keywords):
keywords = keywords.lower().split()
@@ -172,11 +193,4 @@
def error(self):
- # TODO adapt to new code
- self.clearbuffer()
- self.status = '500'
- self.statusexplanation = 'Internal Server Error'
- self.write(html.error.format({'traceback': log.get_traceback()}))
- self.flush()
- self.close()
- super(HoneybeeHandler, self).error(exc)
+ raise
=== modified file 'beeseek/network/highlevel.py'
--- a/beeseek/network/highlevel.py 2009-01-08 16:23:40 +0000
+++ b/beeseek/network/highlevel.py 2009-01-13 16:34:37 +0000
@@ -62,38 +62,30 @@
# """Close the response."""
-_applications_cache = []
-class BaseApplication(BaseProtocol):
+class BaseApplication(object):
- __slots__ = '_protocol'
+ __slots__ = ('recv', 'raw_recv', 'read', 'raw_read',
+ 'readline', 'raw_readline', 'write', 'raw_write',
+ 'writelines', 'raw_writelines', 'protocol', '_bufsize',
+ 'end_request', 'end_response', '_sock')
implements(IApplicationProtocol, isbase=True)
- def __new__(cls, bufsize=-1, protocol=IPSocket, sock=None, addr=None):
- if IProtocol not in getattr(protocol, 'implements', ()):
- raise TypeError('protocol should implement IProtocol.')
- if protocol not in _applications_cache:
- bases = cls.__bases__
- if protocol not in bases:
- bases = tuple(base for base in cls.__bases__
- if base is not BaseProtocol) + (protocol,)
- newtype = type(cls)(cls.__name__, bases, dict(cls.__dict__))
- _applications_cache.append(newtype)
+ def __init__(self, bufsize=-1, sock=IPSocket):
+ if isinstance(sock, BaseProtocol):
+ # This may be a socket object
+ protocol = sock.__class__.__base__
else:
- newtype = _applications_cache[protocol]
- obj = object.__new__(newtype, bufsize, protocol)
- obj.__init__(bufsize, protocol, sock, addr)
- return obj
-
- def __init__(self, bufsize, protocol, sock=None, addr=None):
- protocol.__init__(self, bufsize, sock, addr)
- self._protocol = protocol
-
- rawrecv = BaseProtocol.recv
- rawread = BaseProtocol.read
- rawreadline = BaseProtocol.readline
- rawwrite = BaseProtocol.write
- rawwritelines = BaseProtocol.writelines
+ protocol = sock
+ sock = sock(bufsize)
+ self._sock = sock
+ self.protocol = protocol
+
+ self.raw_recv = sock.recv
+ self.raw_read = sock.read
+ self.raw_readline = sock.readline
+ self.raw_write = sock.write
+ self.raw_writelines = sock.writelines
def writelines(self, data):
# Most of the applications may implement the ``writelines`` method in
@@ -101,13 +93,19 @@
for item in data:
self.write(data)
- def end_request(self):
- raise ValueError('Request not started')
-
- def accept(self):
- cls = type(self)
- sock, addr = self._sock.accept()
- return cls(self._bufsize, self._protocol, sock, addr)
+ def bind(self, address):
+ self._sock.bind(address)
+
+ def listen(self, backlog):
+ self._sock.listen(backlog)
+
+ def accept(self, cls=None):
+ cls = cls or type(self)
+ sock = self._sock.accept()
+ return cls(self._sock._bufsize, sock)
+
+ def connect(self, address):
+ self._sock.connect(address)
def start_loop(self):
while not self.closed:
@@ -121,4 +119,27 @@
pass
def error(self):
- raise exc
+ raise
+
+ def close(self):
+ self._sock.close()
+
+ @property
+ def closed(self):
+ return self._sock.closed
+
+ def fileno(self):
+ return self._sock.fileno()
+
+ @property
+ def peername(self):
+ return self._sock.peername
+
+ def waitinput(self):
+ self._sock.waitinput()
+
+ def flush(self):
+ self._sock.flush()
+
+ def __del__(self):
+ del self._sock
=== modified file 'beeseek/network/http.py'
--- a/beeseek/network/http.py 2009-01-14 12:47:29 +0000
+++ b/beeseek/network/http.py 2009-01-14 12:48:11 +0000
@@ -18,13 +18,13 @@
from beeseek.interfaces import implements
from beeseek.utils import CaseInsensitiveDict
from beeseek.network.highlevel import (IClientApplication, IServerApplication,
- BaseApplication)
-
-class HTTPParser(object):
- """HTTP parser for both request and responses.
-
- This class provides a set of staticmethod and classmethod objects to parse
- the parts of HTTP request and responses as defined in RFC 1945 and 2616:
+ IApplicationProtocol, BaseApplication)
+
+class HTTPApplication(BaseApplication):
+ """Base class for HTTP applications.
+
+ This class provides a set of methods to parse the parts of HTTP requests
+ and responses as defined in RFC 1945 and RFC 2616:
http://www.w3.org/Protocols/rfc1945/rfc1945
http://www.w3.org/Protocols/rfc2616/rfc2616
This class fully supports both HTTP/1.1 and HTTP/1.0; HTTP/0.9 is
@@ -32,6 +32,12 @@
and untested but may work in some cases.
"""
+ __slots__ = ('write', 'recv', 'read', 'readline', '_contentlen',
+ 'end_request', 'end_response', 'statusline', 'serverheaders',
+ 'requestline', 'clientheaders')
+ implements(IApplicationProtocol, isbase=True)
+
+
# Method definitions
OPTION, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT = range(0, 8)
@@ -63,53 +69,49 @@
# Methods to read the parts of a request or a response
- @classmethod
- def read_request_line(cls, fp):
+ def read_request_line(self):
"""Read and parse the request line from the client.
- :param fp: A file-like object to read from.
:return: A three-items tuple in the format (method, page, version).
"""
# XXX HTTP/0.9 clients may not send the protocol version
# (see http://www.w3.org/Protocols/HTTP/Request.html)
- method, page, version = fp.readline().split(' ')
- return cls._methods[method], page, cls._versions[version.rstrip()]
+ data = self.raw_readline()
+ if not data:
+ raise EOFError
+ method, page, version = data.split(' ')
+ return self._methods[method], page, self._versions[version.rstrip()]
- @classmethod
- def read_status_line(cls, fp):
+ def read_status_line(self):
"""Read and parse a response from the server.
- :param fp: A file-like object to read from.
:return: A three-items tuple in the format (status, reason, version).
"""
# XXX HTTP/0.9 servers may not send the protocol version
# XXX Status line and headers are optional in responses
- version, status, reason = fp.readline().split(' ', 2)
- return int(status), reason.rstrip(), cls._versions[version]
+ version, status, reason = self.raw_readline().split(' ', 2)
+ return int(status), reason.rstrip(), self._versions[version]
- @classmethod
- def read_headers(cls, fp):
+ def read_headers(self):
"""Return a dict with the headers as returned by iter_headers()."""
- return CaseInsensitiveDict(cls.iter_headers(fp))
+ return CaseInsensitiveDict(self.iter_headers())
- @staticmethod
- def iter_headers(fp):
+ def iter_headers(self):
"""Read the headers from the socket.
This method yields the headers read in the format (name, value).
"""
while True:
- line = fp.readline()
+ line = self.raw_readline()
if line == '\r\n':
return
name, value = line.split(':', 1)
yield name, value.strip()
- @staticmethod
- def read_chunksize(fp):
- line = fp.readline()
+ def read_chunksize(self):
+ line = self.raw_readline()
if line == '\r\n':
- line = fp.readline()
+ line = self.raw_readline()
if line == '\r\n':
return 0
return int(line, 16)
@@ -117,11 +119,9 @@
# Methods to send parts of a request or a response
- @classmethod
- def send_request_line(cls, fp, method, path, version=None):
+ def send_request_line(self, method, path, version=None):
"""Send a request line through the specified socket.
- :param fp: A file-like object to write to.
:param method: One of the available methods specified in this class
(e.g. GET or POST).
:param path: The page to request. It should not contain any blank
@@ -131,15 +131,13 @@
values available in this class (e.g. HTTP10). If not
specified or None, HTTP11 will be used.
"""
- fp.write('%s %s %s\r\n' % (cls._methods[method],
- path,
- cls._versions[version or cls.HTTP11]))
+ self.raw_write('%s %s %s\r\n' % (self._methods[method],
+ path,
+ self._versions[version or self.HTTP11]))
- @classmethod
- def send_status_line(cls, fp, status, reason, version=None):
+ def send_status_line(self, status, reason, version=None):
"""Send a status line through the specified socket.
- :param fp: A file-like object to write to.
:param status: An integer or a string with the response status (e.g.
100 or 404).
:param reason: A string with a human-readable explanation for the
@@ -148,31 +146,26 @@
values available in this class (e.g. HTTP10). If not
specified or None, HTTP11 will be used.
"""
- fp.write('%s %s %s\r\n' % (cls._versions[version or cls.HTTP11],
- status, reason))
+ self.raw_write('%s %s %s\r\n' % (self._versions[version or self.HTTP11],
+ status, reason))
- @staticmethod
- def send_headers(fp, headers):
+ def send_headers(self, headers):
"""Send the given headers to the connected peer.
- :param fp: A file-like object to write to.
:param headers: The headers to send. It can be both a dictionary or an
iter. If it is an iter, it should be in the format
(headername, headervalue).
:type headers: mapping or iter
"""
if isinstance(headers, dict):
- fp.writelines('%s: %s\r\n' % (name, value)
- for name, value in headers.iteritems())
- else:
- fp.writelines('%s: %s\r\n' % value for value in headers)
- fp.write('\r\n')
+ headers = headers.iteritems()
+ self.raw_writelines('%s: %s\r\n' % value for value in headers)
+ self.raw_write('\r\n')
# Methods to get information from the read data
- @classmethod
- def get_transfer_style(cls, headers):
+ def get_transfer_style(self, headers):
"""Read the headers and return the transfer style.
It returns an int that tells how to read the content. The first item
@@ -185,38 +178,28 @@
The transfer style is determined with the rules described at:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
"""
- if 'transfer-encoding' in headers:
+ if 'Transfer-Encoding' in headers:
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6
- tokens = headers['transfer-encoding'].lower()
- tokens = HTTPParser.split_tokens(tokens)
+ tokens = headers['Transfer-Encoding'].lower()
+ tokens = self.split_tokens(tokens)
if filter(lambda s: s != 'identity', tokens):
return 3
- if 'content-length' in headers:
+ if 'Content-Length' in headers:
return 2
- if ('connection' in headers and
- headers['connection'].lower() == 'close'):
+ if ('Connection' in headers and
+ headers['Connection'].lower() == 'close'):
return 1
return 0
- @staticmethod
- def split_tokens(value):
+ def split_tokens(self, value):
return tuple(s.strip() for s in value.split(';'))
-class HTTPApplication(BaseApplication):
- """Base class for HTTP applications."""
-
- __slots__ = ('write', 'recv', 'read', 'readline', '_contentlen',
- 'end_request', 'end_response', 'statusline', 'serverheaders',
- 'requestline', 'clientheaders')
-
def _write_chunk(self, data):
- self.rawwrite(hex(len(data))[2:])
- self.rawwrite('\r\n')
- self.rawwrite(data)
+ self.raw_write('%x\r\n%s\r\n' % (len(data), data))
def _end_chunked(self):
- self.rawwrite('0\r\n\r\n')
+ self.raw_write('0\r\n\r\n')
def _end(self):
pass
@@ -225,21 +208,21 @@
def _recv_fixedlen(self, size=-1):
if size > self._contentlen or size < 0:
size = self._contentlen
- data = self.rawrecv(size)
+ data = self.raw_recv(size)
self._contentlen -= len(data)
return data
def _read_fixedlen(self, size=-1):
if size > self._contentlen or size < 0:
size = self._contentlen
- data = self.rawread(size)
+ data = self.raw_read(size)
self._contentlen -= len(data)
return data
def _readline_fixedlen(self, size=-1):
if size > self._contentlen or size < 0:
size = self._contentlen
- data = self.rawreadline(size)
+ data = self.raw_readline(size)
self._contentlen -= len(data)
return data
@@ -247,8 +230,7 @@
def _recv_chunk(self, size=-1):
chunklen = self._contentlen
if chunklen == 0:
- fp = super(BaseApplication, self)
- chunklen = HTTPParser.read_chunksize(fp)
+ chunklen = self.read_chunksize()
if chunklen == 0:
self._contentlen = -1
return ''
@@ -257,66 +239,64 @@
if size > chunklen or size < 0:
size = chunklen
- data = self.rawrecv(size)
+ data = self.raw_recv(size)
self._contentlen = chunklen - len(data)
return data
def _read_chunk(self, size=-1):
data = ''
chunklen = self._contentlen
- fp = super(BaseApplication, self)
if size < 0:
while True:
- data += self.rawread(chunklen)
- chunklen = HTTPParser.read_chunksize(fp)
+ data += self.raw_read(chunklen)
+ chunklen = self.read_chunksize()
if chunklen == 0:
self._contentlen = -1
return data
else:
while True:
if chunklen < size:
- piece = self.rawread(chunklen)
+ piece = self.raw_read(chunklen)
data += piece
- chunklen = HTTPParser.read_chunksize(fp)
+ chunklen = self.read_chunksize()
if chunklen == 0:
self._contentlen = -1
return data
size -= len(piece)
else:
- data += self.rawread(size)
+ data += self.raw_read(size)
self._contentlen = chunklen - size
return data
def _readline_chunk(self, size=-1):
data = piece = ''
chunklen = self._contentlen
- fp = super(BaseApplication, self)
if size < 0:
while True:
- piece = self.rawreadline(chunklen)
+ piece = self.raw_readline(chunklen)
data += piece
if piece.endswith('\n'):
self._contentlen = chunklen - len(piece)
return data
- chunklen = HTTPParser.read_chunksize(fp)
+ chunklen = self.read_chunksize()
if chunklen == 0:
self._contentlen = -1
return data
else:
while True:
if chunklen < size:
- piece = self.rawreadline(chunklen)
+ piece = self.raw_readline(chunklen)
data += piece
if piece.endswith('\n'):
self._contentlen = chunklen - len(piece)
return data
- chunklen = HTTPParser.read_chunksize(fp)
+ chunklen = self.read_chunksize()
if chunklen == 0:
self._contentlen = -1
return data
size -= len(piece)
else:
- piece = self.rawreadline(size)
+ piece = self.raw_readline(size)
data += piece
self._contentlen = chunklen - len(piece)
return data
@@ -329,9 +309,9 @@
if style == 0:
self.recv = self.read = self.readline = self._read_eof
elif style == 1:
- self.recv = self.rawrecv
- self.read = self.rawread
- self.readline = self.rawreadline
+ self.recv = self.raw_recv
+ self.read = self.raw_read
+ self.readline = self.raw_readline
elif style == 2:
self._contentlen = int(headers['content-length'])
self.recv = self._recv_fixedlen
@@ -350,22 +330,20 @@
implements(IClientApplication)
def start_request(self, method, path, headers, version=None):
- fp = super(BaseApplication, self)
- HTTPParser.send_request_line(fp, method, path, version)
- HTTPParser.send_headers(fp, headers)
+ self.send_request_line(method, path, version)
+ self.send_headers(headers)
- if HTTPParser.get_transfer_style(headers) == 3:
+ if self.get_transfer_style(headers) == 3:
self.write = self._write_chunk
self.end_request = self._end_chunked
else:
- self.write = self.rawwrite
+ self.write = self.raw_write
self.end_request = self._end
def read_response(self):
- fp = super(BaseApplication, self)
- self.statusline = HTTPParser.read_status_line(fp)
- self.serverheaders = headers = HTTPParser.read_headers(fp)
- style = HTTPParser.get_transfer_style(headers)
+ self.statusline = self.read_status_line()
+ self.serverheaders = headers = self.read_headers()
+ style = self.get_transfer_style(headers)
self._set_read_methods(style, headers)
@@ -375,20 +353,18 @@
implements(IServerApplication)
def read_request(self):
- fp = super(BaseApplication, self)
- self.requestline = HTTPParser.read_request_line(fp)
- self.clientheaders = headers = HTTPParser.read_headers(fp)
- style = HTTPParser.get_transfer_style(headers)
+ self.requestline = self.read_request_line()
+ self.clientheaders = headers = self.read_headers()
+ style = self.get_transfer_style(headers)
self._set_read_methods(style, headers)
def start_response(self, status, reason, headers, version=None):
- fp = super(BaseApplication, self)
- HTTPParser.send_status_line(fp, status, reason, version)
- HTTPParser.send_headers(fp, headers)
+ self.send_status_line(status, reason, version)
+ self.send_headers(headers)
- if HTTPParser.get_transfer_style(headers) == 3:
+ if self.get_transfer_style(headers) == 3:
self.write = self._write_chunk
self.end_response = self._end_chunked
else:
- self.write = self.rawwrite
+ self.write = self.raw_write
self.end_response = self._end
=== modified file 'beeseek/network/lowlevel.py'
--- a/beeseek/network/lowlevel.py 2009-01-14 12:47:29 +0000
+++ b/beeseek/network/lowlevel.py 2009-01-14 12:48:11 +0000
@@ -20,9 +20,8 @@
from select import select
from beeseek.interfaces import Interface, implements
-__all__ = ['IProtocol', 'BaseProtocol', 'IPSocket', 'has_ipv6', 'IPv6Socket',
- 'has_unix', 'UNIXSocket']
-_has_getpeername = hasattr(_socket.socket, 'getpeername')
+__all__ = ('IProtocol', 'BaseProtocol', 'SocketError', 'IPSocket',
+ 'has_ipv6', 'IPv6Socket', 'has_unix', 'UNIXSocket')
SocketError = _socket.error
@@ -37,6 +36,7 @@
def close(self):
"""Shutdown the connection."""
+ # XXX is it a good thing to use __del__?
def __del__(self):
"""Call close() checking errors.
@@ -47,15 +47,21 @@
# XXX See bug 313272
#__slots__ = tuple
- fileno = int, property
+ def fileno(self):
+ pass
closed = int, property
peername = tuple, property
class IProtocol(IConnector):
- def __init__(self, bufsize=-1, sock=None, addr=None):
- """Initialize the socket with the specified bufsize."""
+ def __init__(self, bufsize=-1, sock=None):
+ """Initialize the socket.
+
+ :param bufsize: The buffer size.
+ :param sock: The socket to use for reading and writing. If None,
+ create a new one.
+ """
def connect(self, address):
"""Connect to the peer."""
@@ -100,31 +106,19 @@
class BaseProtocol(object):
"""Base class for all low-level protocols"""
- __slots__ = ('_sock', '_peername', '_fileno', '_rfile', '_wfile',
- '_closed', '_bufsize')
+ __slots__ = '_sock', '_fileno', '_rfile', '_wfile', '_closed', '_bufsize'
implements(IProtocol, isbase=True)
- def __init__(self, bufsize=-1, sock=None, peername=None):
- if sock is None:
- self._sock = _socket.socket(self._family, _socket.SOCK_STREAM)
- else:
- self._sock = sock
- if not _has_getpeername:
- self._peername = peername
-
+ def __init__(self, bufsize=-1, sock=None):
+ self._sock = sock or _socket.socket(self._family, _socket.SOCK_STREAM)
self._fileno = self._sock.fileno()
self._rfile = os.fdopen(self._fileno, 'r', 0)
self._wfile = os.fdopen(self._fileno, 'w', bufsize)
self._closed = False
self._bufsize = bufsize
- if _has_getpeername:
- def connect(self, address):
- self._sock.connect(address)
- else:
- def connect(self, address):
- self._sock.connect(address)
- self._peername = address
+ def connect(self, address):
+ self._sock.connect(address)
def bind(self, address):
self._sock.bind(address)
@@ -135,27 +129,38 @@
def accept(self):
cls = type(self)
sock, addr = self._sock.accept()
- return cls(self._bufsize, sock, addr)
+ return cls(self._bufsize, sock)
def recv(self, size=-1):
if size < 0:
size = 1024
- return os.read(self._fileno, size)
+ data = os.read(self._fileno, size)
+ if not data:
+ self._closed = True
+ return data
def read(self, size=-1):
- return self._rfile.read(size)
+ data = self._rfile.read(size)
+ if not data:
+ self._closed = True
+ return data
def readline(self, size=-1):
- return self._rfile.readline(size)
+ data = self._rfile.readline(size)
+ if not data:
+ self._closed = True
+ return data
def waitinput(self, timeout=None):
- select((self._fp,), (), (), timeout)
+ select((self._rfile,), (), (), timeout)
def write(self, data):
self._wfile.write(data)
def writelines(self, data):
- self._wfile.writelines(data)
+ # XXX For some reason, _wfile.writelines doesn't work
+ for i in data:
+ self._wfile.write(i)
def flush(self):
self._wfile.flush()
@@ -168,8 +173,6 @@
except SocketError:
pass
self._sock.shutdown(_socket.SHUT_RDWR)
- self._rfile.close()
- self._wfile.close()
self._sock.close()
self._closed = True
@@ -188,7 +191,6 @@
raise StopIteration
return line
- @property
def fileno(self):
return self._fileno
@@ -196,20 +198,10 @@
def closed(self):
return self._closed
- if _has_getpeername:
- @property
- def peername(self):
- return self._sock.getpeername()
- else:
- @property
- def peername(self):
- if self._peername is None:
- raise SocketError(107, 'Transport endpoint is not connected')
- return self._peername
-
-
-if not _has_getpeername:
- _common_slots.append('_peername')
+ @property
+ def peername(self):
+ return self._sock.getpeername()
+
class IPSocket(BaseProtocol):
=== modified file 'beeseek/session.py'
--- a/beeseek/session.py 2009-01-14 12:47:29 +0000
+++ b/beeseek/session.py 2009-01-14 12:48:11 +0000
@@ -27,7 +27,7 @@
from beeseek.commands import *
from beeseek.interfaces import *
from beeseek.version import Version
-from beeseek.network import BaseConnectionHandler
+from beeseek.network.highlevel import BaseApplication
from beeseek.utils import filelocking, get_argcount
@@ -38,7 +38,7 @@
appdescription = basestring, ('A short description of the product to '
'show in the help message')
scriptname = basestring, 'The name of the script launched by the user'
- server = BaseConnectionHandler, 'The main connection handler'
+ server = BaseApplication, 'The main connection handler'
configdir = basestring, 'The default configuration directory'
optionlist = OptionList, None, ('The list of options used by the '
'launched command')
=== modified file 'beeseek/utils/__init__.py'
--- a/beeseek/utils/__init__.py 2009-01-14 12:47:29 +0000
+++ b/beeseek/utils/__init__.py 2009-01-14 12:48:11 +0000
@@ -39,12 +39,6 @@
return minargs, maxargs, bool(haskwargs)
-class NULL(object):
- """This is a special class useful when ``None`` can't be used."""
-
- pass
-
-
class CaseInsensitiveDict(dict):
"""A dict subclass with case-insensitive keys."""
@@ -72,11 +66,13 @@
def __delitem__(self, key):
dict.__delitem__(self, key.lower())
- def pop(self, key, default=NULL):
- if default is NULL:
- return dict.pop(self, key.lower())
+ def pop(self, *args):
+ if len(args) == 1:
+ return dict.pop(self, args[0].lower())[1]
+ elif len(args) == 2:
+ return dict.pop(self, args[0].lower(), args)[1]
else:
- return dict.pop(self, key.lower(), default)
+ raise TypeError
def popitem(self):
return dict.popitem(self)[1]
--
BeeSeek mainline
https://code.launchpad.net/~beeseek-devs/beeseek/trunk
You are receiving this branch notification because you are subscribed to it.