[Zope-CVS] CVS: Packages/tcpwatch - CHANGES.txt:1.7 tcpwatch.py:1.10
Shane Hathaway
shane at zope.com
Thu Aug 19 12:16:40 EDT 2004
Update of /cvs-repository/Packages/tcpwatch
In directory cvs.zope.org:/tmp/cvs-serv11320
Modified Files:
CHANGES.txt tcpwatch.py
Log Message:
Added support for CONNECT, allowing tcpwatch to work as an HTTPS proxy
=== Packages/tcpwatch/CHANGES.txt 1.6 => 1.7 ===
--- Packages/tcpwatch/CHANGES.txt:1.6 Wed Jun 16 20:03:46 2004
+++ Packages/tcpwatch/CHANGES.txt Thu Aug 19 12:16:38 2004
@@ -1,4 +1,10 @@
+Next release
+
+ - Added support for HTTP CONNECT, allowing tcpwatch to work as an
+ HTTPS proxy.
+
+
Version 1.3
- Made compatible with versions of tcl that have threads enabled.
=== Packages/tcpwatch/tcpwatch.py 1.9 => 1.10 ===
--- Packages/tcpwatch/tcpwatch.py:1.9 Wed Jun 16 20:03:46 2004
+++ Packages/tcpwatch/tcpwatch.py Thu Aug 19 12:16:38 2004
@@ -73,7 +73,7 @@
from __future__ import nested_scopes
-VERSION = '1.3'
+VERSION = '1.3+'
COPYRIGHT = (
'TCPWatch %s Copyright 2001 Shane Hathaway, Zope Corporation'
% VERSION)
@@ -284,7 +284,9 @@
def escape(s):
- # XXX This might be a brittle trick. :-(
+ # Encode a string with backslashes. For example, a string
+ # containing characters 0 and 1 will be rendered as \x00\x01.
+ # XXX This implementation might be a brittle trick. :-(
return repr('"\'' + str(s))[4:-1]
@@ -1039,11 +1041,21 @@
ForwardingEndpoint.__init__(self)
self.response_parser = HTTPStreamParser(0)
self.proxy_conn = proxy_conn
+ self.direct = 0
self.set_dests(dests)
# Data for the client held until previous responses are sent
self.held = []
+ def set_direct(self):
+ self.direct = 1
+
+ def handle_connect(self):
+ ForwardingEndpoint.handle_connect(self)
+ if self.direct:
+ # Inject the success reply into the stream
+ self.received('HTTP/1.1 200 Connection established\r\n\r\n')
+
def _isMyTurn(self):
"""Returns a true value if it's time for this response
to respond to the client."""
@@ -1054,13 +1066,18 @@
def received(self, data):
"""Receives data from the HTTP server to be sent back to the client."""
+ if self.direct:
+ ForwardingEndpoint.received(self, data)
+ self.held.append(data)
+ self.flush()
+ return
while 1:
parser = self.response_parser
if parser.completed:
self.finished = 1
- self.flush()
- # Note that any extra data returned from the server is
- # ignored. Should it be? :-(
+ self.close()
+ # TODO: it would be nice to reuse proxy connections
+ # rather than close them every time.
return
if not data:
break
@@ -1102,7 +1119,7 @@
If there is unsent response data, an error is generated.
"""
self.flush()
- if not self.finished:
+ if not self.finished and not self.direct:
t = IOError
v = 'Closed without finishing response to client'
for d in self._dests:
@@ -1124,6 +1141,7 @@
self._obs_factory = factory
self._counter = counter
self._client_addr = addr
+ self._direct_receiver = None
self._response_order = []
self._newRequest()
@@ -1143,6 +1161,11 @@
def received(self, data):
"""Accepts data received from the client."""
while data:
+ if self._direct_receiver is not None:
+ # Direct-connect mode
+ self._direct_receiver.write(data)
+ ForwardingEndpoint.received(self, data)
+ return
parser = self._req_parser
if parser is None:
# Begin another request.
@@ -1182,6 +1205,10 @@
else:
host = urlpart
path = '/'
+ elif '/' not in url:
+ # Only a host name (probably using CONNECT)
+ host = url
+ path = ''
else:
# Transparent proxy
host = request.headers.get('HOST')
@@ -1189,15 +1216,15 @@
if not host:
raise ValueError, ('Request type not supported: %s' % url)
+ if '@' in host:
+ username, host = host.split('@')
+
if ':' in host:
- host, port = host.split(':')
+ host, port = host.split(':', 1)
port = int(port)
else:
port = 80
- if '@' in host:
- username, host = host.split('@')
-
obs = self._obs
if obs is not None:
eo = EndpointObserver(obs, 0)
@@ -1207,14 +1234,20 @@
self._response_order.append(ptos)
- ptos.write('%s %s %s\r\n' % (command, path, protocol))
- # Duplicate the headers sent by the client.
- if request.header:
- ptos.write(request.header)
+ if command == 'CONNECT':
+ # Reply, then send the remainder of the connection
+ # directly to the server.
+ self._direct_receiver = ptos
+ ptos.set_direct()
else:
- ptos.write('\r\n')
- if request.body_data:
- ptos.write(''.join(request.body_data))
+ ptos.write('%s %s %s\r\n' % (command, path, protocol))
+ # Duplicate the headers sent by the client.
+ if request.header:
+ ptos.write(request.header)
+ else:
+ ptos.write('\r\n')
+ if request.body_data:
+ ptos.write(''.join(request.body_data))
ptos.create_socket(socket.AF_INET, socket.SOCK_STREAM)
ptos.connect((host, port))
More information about the Zope-CVS
mailing list