Basic websocket connection, code cleanup.

This commit is contained in:
Aldo Cortesi 2014-09-17 09:40:25 +12:00
parent 4f56b76b2c
commit f7da58ca9b
6 changed files with 85 additions and 60 deletions

View File

@ -2,11 +2,10 @@
This module provides more sophisticated flow tracking and provides filtering and interception facilities.
"""
from __future__ import absolute_import
import base64
import hashlib, Cookie, cookielib, re, threading
import os
import flask
import requests
import hashlib
import Cookie
import cookielib
import re
from netlib import odict, wsgi
import netlib.http
from . import controller, protocol, tnetstring, filt, script, version
@ -151,10 +150,13 @@ class StreamLargeBodies(object):
def run(self, flow, is_request):
r = flow.request if is_request else flow.response
code = flow.response.code if flow.response else None
expected_size = netlib.http.expected_http_body_size(r.headers, is_request, flow.request.method, code)
expected_size = netlib.http.expected_http_body_size(
r.headers, is_request, flow.request.method, code
)
if not (0 <= expected_size <= self.max_size):
r.stream = True
class ClientPlaybackState:
def __init__(self, flows, exit):
self.flows, self.exit = flows, exit
@ -645,11 +647,11 @@ class FlowMaster(controller.Master):
f.error = None
self.process_new_request(f)
rt = http.RequestReplayThread(
self.server.config,
f,
self.masterq,
self.should_exit
)
self.server.config,
f,
self.masterq,
self.should_exit
)
rt.start() # pragma: no cover
if block:
rt.join()

View File

@ -12,10 +12,10 @@ class Error(stateobject.SimpleStateObject):
"""
An Error.
This is distinct from an protocol error response (say, a HTTP code 500), which
is represented by a normal HTTPResponse object. This class is responsible
for indicating errors that fall outside of normal protocol communications,
like interrupted connections, timeouts, protocol errors.
This is distinct from an protocol error response (say, a HTTP code 500),
which is represented by a normal HTTPResponse object. This class is
responsible for indicating errors that fall outside of normal protocol
communications, like interrupted connections, timeouts, protocol errors.
Exposes the following attributes:
@ -42,7 +42,9 @@ class Error(stateobject.SimpleStateObject):
@classmethod
def _from_state(cls, state):
f = cls(None) # the default implementation assumes an empty constructor. Override accordingly.
# the default implementation assumes an empty constructor. Override
# accordingly.
f = cls(None)
f._load_state(state)
return f
@ -133,31 +135,35 @@ class ProtocolHandler(object):
def handle_messages(self):
"""
This method gets called if a client connection has been made. Depending on the proxy settings,
a server connection might already exist as well.
This method gets called if a client connection has been made. Depending
on the proxy settings, a server connection might already exist as well.
"""
raise NotImplementedError # pragma: nocover
def handle_server_reconnect(self, state):
"""
This method gets called if a server connection needs to reconnect and there's a state associated
with the server connection (e.g. a previously-sent CONNECT request or a SOCKS proxy request).
This method gets called after the connection has been restablished but before SSL is established.
This method gets called if a server connection needs to reconnect and
there's a state associated with the server connection (e.g. a
previously-sent CONNECT request or a SOCKS proxy request). This method
gets called after the connection has been restablished but before SSL is
established.
"""
raise NotImplementedError # pragma: nocover
def handle_error(self, error):
"""
This method gets called should there be an uncaught exception during the connection.
This might happen outside of handle_messages, e.g. if the initial SSL handshake fails in transparent mode.
This method gets called should there be an uncaught exception during the
connection. This might happen outside of handle_messages, e.g. if the
initial SSL handshake fails in transparent mode.
"""
raise error # pragma: nocover
class LiveConnection(object):
"""
This facade allows interested parties (FlowMaster, inline scripts) to interface with a live connection,
without requiring to expose the internals of the ConnectionHandler.
This facade allows interested parties (FlowMaster, inline scripts) to
interface with a live connection, without requiring to expose the internals
of the ConnectionHandler.
"""
def __init__(self, c):
self.c = c
@ -193,7 +199,9 @@ class LiveConnection(object):
if not self._backup_server_conn and not persistent_change:
self._backup_server_conn = self.c.server_conn
self.c.server_conn = None
else: # This is at least the second temporary change. We can kill the current connection.
else:
# This is at least the second temporary change. We can kill the
# current connection.
self.c.del_server_connection()
self.c.set_server_address(address)
@ -204,8 +212,9 @@ class LiveConnection(object):
return False
def restore_server(self):
# TODO: Similar to _backup_server_conn, introduce _cache_server_conn, which keeps the changed connection open
# This may be beneficial if a user is rewriting all requests from http to https or similar.
# TODO: Similar to _backup_server_conn, introduce _cache_server_conn,
# which keeps the changed connection open This may be beneficial if a
# user is rewriting all requests from http to https or similar.
if not self._backup_server_conn:
return

View File

@ -58,6 +58,7 @@ class Options(object):
class WebMaster(flow.FlowMaster):
def __init__(self, server, options):
self.options = options
self.app = app.Application(self.options.wdebug)
flow.FlowMaster.__init__(self, server, WebState())
def tick(self):
@ -70,9 +71,7 @@ class WebMaster(flow.FlowMaster):
)
iol = tornado.ioloop.IOLoop.instance()
http_server = tornado.httpserver.HTTPServer(
app.Application(self.options.wdebug)
)
http_server = tornado.httpserver.HTTPServer(self.app)
http_server.listen(self.options.wport)
tornado.ioloop.PeriodicCallback(self.tick, 5).start()
@ -82,6 +81,7 @@ class WebMaster(flow.FlowMaster):
self.shutdown()
def handle_request(self, f):
print f
flow.FlowMaster.handle_request(self, f)
if f:
f.reply()

View File

@ -1,6 +1,7 @@
import os.path
import tornado.web
import tornado.websocket
import logging
class IndexHandler(tornado.web.RequestHandler):
@ -8,10 +9,29 @@ class IndexHandler(tornado.web.RequestHandler):
self.render("index.html")
class ClientConnection(tornado.websocket.WebSocketHandler):
connections = set()
def open(self):
ClientConnection.connections.add(self)
def on_close(self):
ClientConnection.connections.remove(self)
@classmethod
def broadcast(cls, type, data):
for conn in cls.connections:
try:
conn.write_message(type, data)
except:
logging.error("Error sending message", exc_info=True)
class Application(tornado.web.Application):
def __init__(self, debug):
handlers = [
(r"/", IndexHandler),
(r"/updates", ClientConnection),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),

View File

@ -198,17 +198,14 @@ _.extend(_EventLogStore.prototype, EventEmitter.prototype, {
var EventLogStore = new _EventLogStore();
AppDispatcher.register(EventLogStore.handle.bind(EventLogStore));
function _Connection(root) {"use strict";
if (!root) {
root = location.origin + "/api/v1";
}
this.root = root;
}
_Connection.prototype.init=function() {"use strict";
function _Connection(url) {
this.url = url;
}
_Connection.prototype.init=function() {
this.openWebSocketConnection();
};
_Connection.prototype.openWebSocketConnection=function() {"use strict";
this.ws = new WebSocket(this.root.replace("http", "ws") + "/ws");
_Connection.prototype.openWebSocketConnection=function() {
this.ws = new WebSocket(this.url.replace("http", "ws"));
var ws = this.ws;
ws.onopen = this.onopen.bind(this);
@ -216,21 +213,21 @@ _Connection.prototype.openWebSocketConnection=function() {"use strict";
ws.onerror = this.onerror.bind(this);
ws.onclose = this.onclose.bind(this);
};
_Connection.prototype.onopen=function(open) {"use strict";
_Connection.prototype.onopen=function(open) {
console.log("onopen", this, arguments);
};
_Connection.prototype.onmessage=function(message) {"use strict";
_Connection.prototype.onmessage=function(message) {
//AppDispatcher.dispatchServerAction(...);
console.log("onmessage", this, arguments);
};
_Connection.prototype.onerror=function(error) {"use strict";
_Connection.prototype.onerror=function(error) {
console.log("onerror", this, arguments);
};
_Connection.prototype.onclose=function(close) {"use strict";
_Connection.prototype.onclose=function(close) {
console.log("onclose", this, arguments);
};
var Connection = new _Connection();
var Connection = new _Connection(location.origin + "/updates");
/** @jsx React.DOM */

View File

@ -1,14 +1,11 @@
function _Connection(root) {"use strict";
if (!root) {
root = location.origin + "/api/v1";
}
this.root = root;
}
_Connection.prototype.init=function() {"use strict";
function _Connection(url) {
this.url = url;
}
_Connection.prototype.init=function() {
this.openWebSocketConnection();
};
_Connection.prototype.openWebSocketConnection=function() {"use strict";
this.ws = new WebSocket(this.root.replace("http", "ws") + "/ws");
_Connection.prototype.openWebSocketConnection=function() {
this.ws = new WebSocket(this.url.replace("http", "ws"));
var ws = this.ws;
ws.onopen = this.onopen.bind(this);
@ -16,18 +13,18 @@ _Connection.prototype.openWebSocketConnection=function() {"use strict";
ws.onerror = this.onerror.bind(this);
ws.onclose = this.onclose.bind(this);
};
_Connection.prototype.onopen=function(open) {"use strict";
_Connection.prototype.onopen=function(open) {
console.log("onopen", this, arguments);
};
_Connection.prototype.onmessage=function(message) {"use strict";
_Connection.prototype.onmessage=function(message) {
//AppDispatcher.dispatchServerAction(...);
console.log("onmessage", this, arguments);
};
_Connection.prototype.onerror=function(error) {"use strict";
_Connection.prototype.onerror=function(error) {
console.log("onerror", this, arguments);
};
_Connection.prototype.onclose=function(close) {"use strict";
_Connection.prototype.onclose=function(close) {
console.log("onclose", this, arguments);
};
var Connection = new _Connection();
var Connection = new _Connection(location.origin + "/updates");