Chromium Code Reviews| Index: lib/cros_test_proxy.py |
| diff --git a/lib/cros_test_proxy.py b/lib/cros_test_proxy.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..2d39c45cdbef5c17ee9d05fc2d2a062c36ce7276 |
| --- /dev/null |
| +++ b/lib/cros_test_proxy.py |
| @@ -0,0 +1,105 @@ |
| +#!/usr/bin/python |
| + |
| +# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +import select |
| +import socket |
| +import SocketServer |
| +import threading |
| + |
| +class Filter(object): |
| + """Base class for data filters. |
| + |
| + Pass an instance of this to CrosTestProxy |
| + """ |
| + |
| + def setup(self): |
| + """This setup method is called once per connection.""" |
| + pass |
| + |
| + def InBound(self, data): |
| + """This method is called once per packet of incoming data. |
| + |
| + The value returned is what is sent through the proxy. If |
| + None is returned, the connection will be closed. |
| + """ |
| + return data |
| + |
| + def OutBound(self, data): |
| + """This method is called once per packet of outgoing data. |
| + |
| + The value returned is what is sent through the proxy. If |
| + None is returned, the connection will be closed. |
| + """ |
| + return data |
| + |
| + |
| +class CrosTestProxy(SocketServer.ThreadingMixIn, SocketServer.TCPServer): |
| + """A transparent proxy for simulating network errors""" |
| + |
| + class _Handler(SocketServer.BaseRequestHandler): |
| + """Proxy connection handler that passes data though a filter""" |
| + |
| + def setup(self): |
|
adlr
2010/12/07 02:26:51
please add a docstring for each method/function
dgarrett
2010/12/07 03:48:18
Done.
|
| + self.server.filter.setup() |
| + |
| + def handle(self): |
| + # Open outgoing socket |
| + s_in = self.request |
| + s_out = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| + s_out.connect( (self.server.address_out, self.server.port_out) ) |
|
sosa
2010/12/07 03:44:36
additional spaces unnecessary
dgarrett
2010/12/07 04:08:51
Done.
|
| + |
| + while True: |
| + rlist, wlist, xlist = select.select([s_in, s_out], [], []) |
| + |
| + if s_in in rlist: |
| + data = s_in.recv(1024) |
| + data = self.server.filter.InBound(data) |
| + if not data: break |
| + try: |
| + s_out.sendall(data) |
| + except: |
| + break |
|
sosa
2010/12/07 03:44:36
when would get either of these exceptions (here an
dgarrett
2010/12/07 04:08:51
Usually because the connections are closed at the
|
| + |
| + if s_out in rlist: |
| + data = s_out.recv(1024) |
| + data = self.server.filter.OutBound(data) |
| + if not data: break |
| + try: |
| + s_in.sendall(data) |
| + except: |
| + break |
| + |
| + s_in.close() |
| + s_out.close() |
| + |
| + def __init__(self, |
|
sosa
2010/12/07 03:44:36
i try to define this at the top of classes...up to
dgarrett
2010/12/07 04:08:51
Done.
|
| + filter, |
| + port_in=8081, |
| + address_out='127.0.0.1', port_out=8080): |
| + self.port_in = port_in |
| + self.address_out = address_out |
| + self.port_out = port_out |
| + self.filter = filter |
| + |
| + SocketServer.TCPServer.__init__(self, |
| + ('', port_in), |
| + self._Handler) |
| + |
| + def serve_forever_in_thread(self): |
| + """Call serve_forever in a new thread""" |
| + server_thread = threading.Thread(target=self.serve_forever) |
| + server_thread.setDaemon(True) |
| + server_thread.start() |
| + |
| + return server_thread |
| + |
| + |
| +def main(): |
| + s = CrosTestProxy(port_in=2222, port_out=22, filter=Filter()) |
| + s.serve_forever() |
| + |
|
sosa
2010/12/07 03:44:36
two lines
dgarrett
2010/12/07 04:08:51
Done.
|
| +if __name__ == '__main__': |
| + main() |