From e6eeab60946e61047ed858422badbda189a6f9e8 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 25 Apr 2017 19:06:24 +1200 Subject: Revamp how addons work - Addons now nest, which means that addons can manage addons. This has a number of salutary effects - the scripts addon no longer has to poke into the global addons list, we no longer have to replace/remove/boot-outof parent addons when we load scripts, and this paves the way for making our top-level tools into addons themselves. - All addon calls are now wrapped in a safe execution environment where exceptions are caught, and output to stdout/stderr are intercepted and turned into logs. - We no longer support script arguments in sys.argv - creating an option properly is the only way to pass arguments. This means that all scripts are always directly controllable from interctive tooling, and that arguments are type-checked. For now, I've disabled testing of the har dump example - it needs to be moved to the new argument handling, and become a class addon. I'll address that in a separate patch. --- mitmproxy/test/taddons.py | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) (limited to 'mitmproxy/test') diff --git a/mitmproxy/test/taddons.py b/mitmproxy/test/taddons.py index 8bc174c7..3dbccba2 100644 --- a/mitmproxy/test/taddons.py +++ b/mitmproxy/test/taddons.py @@ -1,3 +1,4 @@ +import sys import contextlib import mitmproxy.master @@ -5,6 +6,7 @@ import mitmproxy.options from mitmproxy import proxy from mitmproxy import addonmanager from mitmproxy import eventsequence +from mitmproxy.addons import script class TestAddons(addonmanager.AddonManager): @@ -26,6 +28,10 @@ class RecordingMaster(mitmproxy.master.Master): self.events = [] self.logs = [] + def dump_log(self, outf=sys.stdout): + for i in self.logs: + print("%s: %s" % (i.level, i.msg), file=outf) + def has_log(self, txt, level=None): for i in self.logs: if level and i.level != level: @@ -51,14 +57,21 @@ class context: provides a number of helper methods for common testing scenarios. """ def __init__(self, master = None, options = None): - self.options = options or mitmproxy.options.Options() + options = options or mitmproxy.options.Options() self.master = master or RecordingMaster( options, proxy.DummyServer(options) ) + self.options = self.master.options self.wrapped = None + def ctx(self): + """ + Returns a new handler context. + """ + return self.master.handlecontext() + def __enter__(self): - self.wrapped = self.master.handlecontext() + self.wrapped = self.ctx() self.wrapped.__enter__() return self @@ -75,11 +88,13 @@ class context: """ f.reply._state = "start" for evt, arg in eventsequence.iterate(f): - h = getattr(addon, evt, None) - if h: - h(arg) - if f.reply.state == "taken": - return + self.master.addons.invoke_addon( + addon, + evt, + arg + ) + if f.reply.state == "taken": + return def configure(self, addon, **kwargs): """ @@ -89,4 +104,17 @@ class context: """ with self.options.rollback(kwargs.keys(), reraise=True): self.options.update(**kwargs) - addon.configure(self.options, kwargs.keys()) + self.master.addons.invoke_addon( + addon, + "configure", + self.options, + kwargs.keys() + ) + + def script(self, path): + sc = script.Script(path) + loader = addonmanager.Loader(self.master) + sc.load(loader) + for a in addonmanager.traverse(sc.addons): + getattr(a, "load", lambda x: None)(loader) + return sc -- cgit v1.2.3