← Back to team overview

beeseek-devs team mailing list archive

[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.