[Zope-CVS] CVS: Packages/tcpwatch - tcpwatch:1.12

Shane Hathaway shane@cvs.zope.org
Mon, 25 Feb 2002 14:46:56 -0500


Update of /cvs-repository/Packages/tcpwatch
In directory cvs.zope.org:/tmp/cvs-serv6953

Modified Files:
	tcpwatch 
Log Message:
Added comments and made sure:

- Server connections get closed when the client connection is closed.

- Client connections get closed when servers don't finish the response.


=== Packages/tcpwatch/tcpwatch 1.11 => 1.12 ===
 
 class ForwardingEndpoint (asyncore.dispatcher):
+    """A socket wrapper that accepts and generates stream messages.
+    """
     _dests = ()
 
     def __init__(self, conn=None):
@@ -161,7 +163,10 @@
 
 
 class EndpointObserver:
-    """Sends endpoint events to a ConnectionObserver.
+    """Sends stream events to a ConnectionObserver.
+
+    Streams don't distinguish sources, while ConnectionObservers do.
+    This adapter adds source information to stream events.
     """
 
     def __init__(self, obs, from_client):
@@ -183,7 +188,6 @@
 
 
 class ForwardedConnectionInfo:
-
     transaction = 1
 
     def __init__(self, connection_number, client_addr, server_addr=None):
@@ -966,6 +970,8 @@
             if parser.completed:
                 self.finished = 1
                 self.flush()
+                # Note that any extra data returned from the server is
+                # ignored. Should it be? :-(
                 return
             if not data:
                 break
@@ -977,7 +983,8 @@
             self.flush()
 
     def flush(self):
-        """Flushes buffers and, if done, allows the next response to take over.
+        """Flushes buffers and, if the response has been sent, allows
+        the next response to take over.
         """
         if self.held and self._isMyTurn():
             data = ''.join(self.held)
@@ -990,15 +997,29 @@
             if order:
                 order[0].flush()  # kick!
 
-    def close(self):
+    def handle_close(self):
         """The HTTP server closed the connection.
         """
-        ForwardingEndpoint.close(self)
+        ForwardingEndpoint.handle_close(self)
         if not self.finished:
-            # TODO: cancel the proxy connection.
-            pass
-        self.finished = 1
+            # Cancel the proxy connection, even if there are responses
+            # pending, since the HTTP spec provides no way to recover
+            # from an unfinished response.
+            self.proxy_conn.close()
+
+    def close(self):
+        """Close the connection to the server.
+
+        If there is unsent response data, an error is generated.
+        """
         self.flush()
+        if not self.finished:
+            t = IOError
+            v = 'Closed without finishing response to client'
+            for d in self._dests:
+                if hasattr(d, 'error'):
+                    d.error(t, v)
+        ForwardingEndpoint.close(self)
 
 
 
@@ -1106,13 +1127,22 @@
         ptos.connect((host, port))
 
     def close(self):
+        """Closes the connection to the client.
+
+        If there are open connections to proxy servers, the server
+        connections are also closed.
+        """
         ForwardingEndpoint.close(self)
-        # TODO: Close the open connections to HTTP servers.
+        for ptos in self._response_order:
+            ptos.close()
+        del self._response_order[:]
 
 
 class HTTPProxyService (asyncore.dispatcher):
     """A minimal HTTP proxy server"""
 
+    connection_class = HTTPProxyToClientConnection
+
     _counter = 0
 
     def __init__(self, listen_host, listen_port, observer_factory=None):
@@ -1131,7 +1161,7 @@
             conn.setblocking(0)
             counter = self._counter + 1
             self._counter = counter
-            HTTPProxyToClientConnection(conn, self._obs_factory, counter, addr)
+            self.connection_class(conn, self._obs_factory, counter, addr)
 
     def handle_error(self):
         # Don't stop the server.