Rip out old script interface, start replacing with new stubs.

Scripts are broken for now.
This commit is contained in:
Aldo Cortesi 2011-08-03 13:20:36 +12:00
parent 62088a6661
commit 12d2b1f926
15 changed files with 128 additions and 151 deletions

View File

@ -25,9 +25,8 @@ def get_common_options(options):
refresh_server_playback = not options.norefresh,
rheaders = options.rheaders,
rfile = options.rfile,
request_script = options.request_script,
response_script = options.response_script,
server_replay = options.server_replay,
script = options.script,
stickycookie = stickycookie,
stickyauth = stickyauth,
wfile = options.wfile,
@ -41,6 +40,16 @@ def common_options(parser):
action="store", type = "str", dest="addr", default='',
help = "Address to bind proxy to (defaults to all interfaces)"
)
parser.add_option(
"--anticache",
action="store_true", dest="anticache", default=False,
help="Strip out request headers that might cause the server to return 304-not-modified."
)
parser.add_option(
"--confdir",
action="store", type = "str", dest="confdir", default='~/.mitmproxy',
help = "Configuration directory. (~/.mitmproxy)"
)
parser.add_option(
"-d",
action="store_true", dest="autodecode",
@ -51,11 +60,6 @@ def common_options(parser):
action="store_true", dest="eventlog",
help="Show event log."
)
parser.add_option(
"--confdir",
action="store", type = "str", dest="confdir", default='~/.mitmproxy',
help = "Configuration directory. (~/.mitmproxy)"
)
parser.add_option(
"-n",
action="store_true", dest="no_server",
@ -77,19 +81,9 @@ def common_options(parser):
help="Read flows from file."
)
parser.add_option(
"--anticache",
action="store_true", dest="anticache", default=False,
help="Strip out request headers that might cause the server to return 304-not-modified."
)
parser.add_option(
"--reqscript",
action="store", dest="request_script", default=None,
help="Script to run when a request is recieved."
)
parser.add_option(
"--respscript",
action="store", dest="response_script", default=None,
help="Script to run when a response is recieved."
"-s",
action="store", dest="script", default=None,
help="Run a script."
)
parser.add_option(
"-t",
@ -143,7 +137,7 @@ def common_options(parser):
group = optparse.OptionGroup(parser, "Server Replay")
group.add_option(
"-s",
"-S",
action="store", dest="server_replay", default=None, metavar="PATH",
help="Replay server responses from a saved file."
)

View File

@ -852,6 +852,7 @@ class Options(object):
"request_script",
"response_script",
"rfile",
"script",
"rheaders",
"server_replay",
"stickycookie",

View File

@ -462,8 +462,8 @@ class FlowMaster(controller.Master):
self.state = state
self.server_playback = None
self.client_playback = None
self.scripts = {}
self.kill_nonreplay = False
self.plugin = None
self.stickycookie_state = False
self.stickycookie_txt = None
@ -481,11 +481,8 @@ class FlowMaster(controller.Master):
raise NotImplementedError
#end nocover
def set_response_script(self, s):
self.scripts["response"] = s
def set_request_script(self, s):
self.scripts["request"] = s
def set_plugin(self, p):
self.plugin = p
def set_stickycookie(self, txt):
if txt:
@ -582,8 +579,6 @@ class FlowMaster(controller.Master):
if self.stickyauth_state:
self.stickyauth_state.handle_request(f)
if "request" in self.scripts:
self._runscript(f, self.scripts["request"])
if self.anticache:
f.request.anticache()
if self.anticomp:
@ -600,8 +595,6 @@ class FlowMaster(controller.Master):
def process_new_response(self, f):
if self.stickycookie_state:
self.stickycookie_state.handle_response(f)
if "response" in self.scripts:
self._runscript(f, self.scripts["response"])
def replay_request(self, f):
"""

View File

@ -1,46 +0,0 @@
import imp, os, traceback
class Context:
def __init__(self, master, state):
self.master, self.state = master, state
def log(self, *args, **kwargs):
self.master.log(*args, **kwargs)
class Plugin:
def __init__(self, path, master):
self.path = path
self.ctx = Context(master, master.state)
self.mod = None
self.ns = None
self.load()
def load(self):
"""
Loads a module and runs the start method.
"""
ns = {}
self.mod = execfile(os.path.expanduser(self.path), {}, ns)
self.ns = ns
self.run("start")
def run(self, name, *args, **kwargs):
"""
Runs a plugin method.
Returns:
(True, retval) on success.
(False, None) on nonexistent method.
(Fals, (exc, traceback string)) if there was an exception.
"""
f = self.ns.get(name)
if f:
try:
return (True, f(self.ctx, *args, **kwargs))
except Exception, v:
return (False, (v, traceback.format_exc(v)))
else:
return (False, None)

View File

@ -1,26 +1,59 @@
"""
The mitmproxy scripting interface is simple - a serialized representation
of a flow is passed to the script on stdin, and a possibly modified flow is
then read by mitmproxy from the scripts stdout. This module provides two
convenience functions to make loading and returning data from scripts
simple.
"""
import sys
import flow
import imp, os, traceback
#begin nocover
def load_flow():
"""
Load a flow from the stdin. Returns a Flow object.
"""
data = sys.stdin.read()
return flow.Flow.script_deserialize(data)
class ScriptError(Exception):
pass
class Context:
def __init__(self, master, state):
self.master, self.state = master, state
def log(self, *args, **kwargs):
self.master.log(*args, **kwargs)
def return_flow(f):
class Script:
"""
Print a flow to stdout.
"""
print >> sys.stdout, f.script_serialize()
The instantiator should do something along this vein:
s = Script(path, master)
s.load()
s.run("start")
"""
def __init__(self, path, master):
self.path = path
self.ctx = Context(master, master.state)
self.mod = None
self.ns = None
def load(self):
"""
Loads a module.
Raises ScriptError on failure, with argument equal to an error
message that may be a formatted traceback.
"""
ns = {}
try:
self.mod = execfile(os.path.expanduser(self.path), {}, ns)
except Exception, v:
raise ScriptError(traceback.format_exc(v))
self.ns = ns
def run(self, name, *args, **kwargs):
"""
Runs a plugin method.
Returns:
(True, retval) on success.
(False, None) on nonexistent method.
(Fals, (exc, traceback string)) if there was an exception.
"""
f = self.ns.get(name)
if f:
try:
return (True, f(self.ctx, *args, **kwargs))
except Exception, v:
return (False, (v, traceback.format_exc(v)))
else:
return (False, None)

View File

@ -1,9 +0,0 @@
#!/usr/bin/env python
import sys
sys.path.insert(0, "..")
from libmproxy import script
f = script.load_flow()
f.request.host = "TESTOK"
print >> sys.stderr, "DEBUG"
script.return_flow(f)

View File

@ -1,2 +0,0 @@
#!/usr/bin/env python
print "NONSENSE"

View File

@ -1,6 +0,0 @@
#!/usr/bin/env python
import sys
sys.path.insert(0, "..")
print >> sys.stderr, "output"
sys.exit(1)

3
test/scripts/loaderr.py Normal file
View File

@ -0,0 +1,3 @@
a = x

View File

@ -1,35 +0,0 @@
import os
from libmproxy import plugins, flow
import libpry
class uPlugin(libpry.AutoTree):
def test_simple(self):
s = flow.State()
fm = flow.FlowMaster(None, s)
p = plugins.Plugin(os.path.join("plugins", "a.py"), fm)
assert "here" in p.ns
assert p.run("here") == (True, 1)
assert p.run("here") == (True, 2)
ret = p.run("errargs")
assert not ret[0]
assert len(ret[1]) == 2
# Check reload
p.load()
assert p.run("here") == (True, 1)
def test_err(self):
s = flow.State()
fm = flow.FlowMaster(None, s)
libpry.raises(IOError, plugins.Plugin, "nonexistent", fm)
libpry.raises(SyntaxError, plugins.Plugin, os.path.join("plugins", "syntaxerr.py"), fm)
tests = [
uPlugin(),
]

View File

@ -1,6 +1,6 @@
import cStringIO, time, re
import libpry
from libmproxy import proxy, controller, utils, dump, script
from libmproxy import proxy, controller, utils, dump
import email.utils
import tutils

51
test/test_script.py Normal file
View File

@ -0,0 +1,51 @@
import os
from libmproxy import script, flow
import libpry
class uScript(libpry.AutoTree):
def test_simple(self):
s = flow.State()
fm = flow.FlowMaster(None, s)
p = script.Script(os.path.join("scripts", "a.py"), fm)
p.load()
assert "here" in p.ns
assert p.run("here") == (True, 1)
assert p.run("here") == (True, 2)
ret = p.run("errargs")
assert not ret[0]
assert len(ret[1]) == 2
# Check reload
p.load()
assert p.run("here") == (True, 1)
def test_err(self):
s = flow.State()
fm = flow.FlowMaster(None, s)
s = script.Script("nonexistent", fm)
libpry.raises(
script.ScriptError,
s.load
)
s = script.Script(os.path.join("scripts", "syntaxerr.py"), fm)
libpry.raises(
script.ScriptError,
s.load
)
s = script.Script(os.path.join("scripts", "loaderr.py"), fm)
libpry.raises(
script.ScriptError,
s.load
)
tests = [
uScript(),
]