mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 10:16:27 +00:00
streamline event/hook/command naming conventions
This commit is contained in:
parent
90df4168f8
commit
6c0e4f1cb7
@ -4,14 +4,14 @@ import textwrap
|
|||||||
from typing import List, Type
|
from typing import List, Type
|
||||||
|
|
||||||
import mitmproxy.addons.next_layer # noqa
|
import mitmproxy.addons.next_layer # noqa
|
||||||
from mitmproxy import events, log, addonmanager
|
from mitmproxy import event_hooks, log, addonmanager
|
||||||
from mitmproxy.proxy import server_hooks, layer
|
from mitmproxy.proxy import server_hooks, layer
|
||||||
from mitmproxy.proxy.layers import http, tcp, tls, websocket
|
from mitmproxy.proxy.layers import http, tcp, tls, websocket
|
||||||
|
|
||||||
known = set()
|
known = set()
|
||||||
|
|
||||||
|
|
||||||
def category(name: str, hooks: List[Type[events.MitmproxyEvent]]) -> None:
|
def category(name: str, hooks: List[Type[event_hooks.EventHook]]) -> None:
|
||||||
print(f"### {name} Events")
|
print(f"### {name} Events")
|
||||||
print("```python")
|
print("```python")
|
||||||
|
|
||||||
@ -65,10 +65,10 @@ def category(name: str, hooks: List[Type[events.MitmproxyEvent]]) -> None:
|
|||||||
category(
|
category(
|
||||||
"Lifecycle",
|
"Lifecycle",
|
||||||
[
|
[
|
||||||
addonmanager.LoadEvent,
|
addonmanager.LoadEventHook,
|
||||||
events.RunningEvent,
|
event_hooks.RunningEventHook,
|
||||||
events.ConfigureEvent,
|
event_hooks.ConfigureEventHook,
|
||||||
events.DoneEvent,
|
event_hooks.DoneEventHook,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -127,12 +127,12 @@ category(
|
|||||||
"Advanced Lifecycle",
|
"Advanced Lifecycle",
|
||||||
[
|
[
|
||||||
layer.NextLayerHook,
|
layer.NextLayerHook,
|
||||||
events.UpdateEvent,
|
event_hooks.UpdateEventHook,
|
||||||
log.AddLogEvent,
|
log.AddLogEventHook,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
not_documented = set(events.all_events.keys()) - known
|
not_documented = set(event_hooks.all_events.keys()) - known
|
||||||
if not_documented:
|
if not_documented:
|
||||||
raise RuntimeError(f"Not documented: {not_documented}")
|
raise RuntimeError(f"Not documented: {not_documented}")
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: "Events"
|
title: "Event Hooks"
|
||||||
menu:
|
menu:
|
||||||
addons:
|
addons:
|
||||||
weight: 2
|
weight: 2
|
||||||
|
@ -7,7 +7,7 @@ import typing
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from mitmproxy import controller
|
from mitmproxy import controller
|
||||||
from mitmproxy import events
|
from mitmproxy import event_hooks
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import flow
|
from mitmproxy import flow
|
||||||
from . import ctx
|
from . import ctx
|
||||||
@ -112,7 +112,7 @@ def traverse(chain):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LoadEvent(events.MitmproxyEvent):
|
class LoadEventHook(event_hooks.EventHook):
|
||||||
"""
|
"""
|
||||||
Called when an addon is first loaded. This event receives a Loader
|
Called when an addon is first loaded. This event receives a Loader
|
||||||
object, which contains methods for adding options and commands. This
|
object, which contains methods for adding options and commands. This
|
||||||
@ -129,14 +129,14 @@ class AddonManager:
|
|||||||
master.options.changed.connect(self._configure_all)
|
master.options.changed.connect(self._configure_all)
|
||||||
|
|
||||||
def _configure_all(self, options, updated):
|
def _configure_all(self, options, updated):
|
||||||
self.trigger(events.ConfigureEvent(updated))
|
self.trigger(event_hooks.ConfigureEventHook(updated))
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
"""
|
"""
|
||||||
Remove all addons.
|
Remove all addons.
|
||||||
"""
|
"""
|
||||||
for a in self.chain:
|
for a in self.chain:
|
||||||
self.invoke_addon(a, events.DoneEvent())
|
self.invoke_addon(a, event_hooks.DoneEventHook())
|
||||||
self.lookup = {}
|
self.lookup = {}
|
||||||
self.chain = []
|
self.chain = []
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ class AddonManager:
|
|||||||
"An addon called '%s' already exists." % name
|
"An addon called '%s' already exists." % name
|
||||||
)
|
)
|
||||||
l = Loader(self.master)
|
l = Loader(self.master)
|
||||||
self.invoke_addon(addon, LoadEvent(l))
|
self.invoke_addon(addon, LoadEventHook(l))
|
||||||
for a in traverse([addon]):
|
for a in traverse([addon]):
|
||||||
name = _get_name(a)
|
name = _get_name(a)
|
||||||
self.lookup[name] = a
|
self.lookup[name] = a
|
||||||
@ -207,7 +207,7 @@ class AddonManager:
|
|||||||
raise exceptions.AddonManagerError("No such addon: %s" % n)
|
raise exceptions.AddonManagerError("No such addon: %s" % n)
|
||||||
self.chain = [i for i in self.chain if i is not a]
|
self.chain = [i for i in self.chain if i is not a]
|
||||||
del self.lookup[_get_name(a)]
|
del self.lookup[_get_name(a)]
|
||||||
self.invoke_addon(addon, events.DoneEvent())
|
self.invoke_addon(addon, event_hooks.DoneEventHook())
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.chain)
|
return len(self.chain)
|
||||||
@ -219,7 +219,7 @@ class AddonManager:
|
|||||||
name = _get_name(item)
|
name = _get_name(item)
|
||||||
return name in self.lookup
|
return name in self.lookup
|
||||||
|
|
||||||
async def handle_lifecycle(self, event: events.MitmproxyEvent):
|
async def handle_lifecycle(self, event: event_hooks.EventHook):
|
||||||
"""
|
"""
|
||||||
Handle a lifecycle event.
|
Handle a lifecycle event.
|
||||||
"""
|
"""
|
||||||
@ -245,13 +245,13 @@ class AddonManager:
|
|||||||
message.reply.mark_reset()
|
message.reply.mark_reset()
|
||||||
|
|
||||||
if isinstance(message, flow.Flow):
|
if isinstance(message, flow.Flow):
|
||||||
self.trigger(events.UpdateEvent([message]))
|
self.trigger(event_hooks.UpdateEventHook([message]))
|
||||||
|
|
||||||
def invoke_addon(self, addon, event: events.MitmproxyEvent):
|
def invoke_addon(self, addon, event: event_hooks.EventHook):
|
||||||
"""
|
"""
|
||||||
Invoke an event on an addon and all its children.
|
Invoke an event on an addon and all its children.
|
||||||
"""
|
"""
|
||||||
assert isinstance(event, events.MitmproxyEvent)
|
assert isinstance(event, event_hooks.EventHook)
|
||||||
for a in traverse([addon]):
|
for a in traverse([addon]):
|
||||||
func = getattr(a, event.name, None)
|
func = getattr(a, event.name, None)
|
||||||
if func:
|
if func:
|
||||||
@ -268,7 +268,7 @@ class AddonManager:
|
|||||||
f"Addon handler {event.name} ({a}) not callable"
|
f"Addon handler {event.name} ({a}) not callable"
|
||||||
)
|
)
|
||||||
|
|
||||||
def trigger(self, event: events.MitmproxyEvent):
|
def trigger(self, event: event_hooks.EventHook):
|
||||||
"""
|
"""
|
||||||
Trigger an event across all addons.
|
Trigger an event across all addons.
|
||||||
"""
|
"""
|
||||||
|
@ -11,7 +11,7 @@ from mitmproxy import flow
|
|||||||
from mitmproxy import http
|
from mitmproxy import http
|
||||||
from mitmproxy import io
|
from mitmproxy import io
|
||||||
from mitmproxy.addons.proxyserver import AsyncReply
|
from mitmproxy.addons.proxyserver import AsyncReply
|
||||||
from mitmproxy.events import UpdateEvent
|
from mitmproxy.event_hooks import UpdateEventHook
|
||||||
from mitmproxy.net import server_spec
|
from mitmproxy.net import server_spec
|
||||||
from mitmproxy.options import Options
|
from mitmproxy.options import Options
|
||||||
from mitmproxy.proxy.layers.http import HTTPMode
|
from mitmproxy.proxy.layers.http import HTTPMode
|
||||||
@ -85,7 +85,7 @@ class ReplayHandler(server.ConnectionHandler):
|
|||||||
def log(self, message: str, level: str = "info") -> None:
|
def log(self, message: str, level: str = "info") -> None:
|
||||||
ctx.log(f"[replay] {message}", level)
|
ctx.log(f"[replay] {message}", level)
|
||||||
|
|
||||||
async def handle_hook(self, hook: commands.Hook) -> None:
|
async def handle_hook(self, hook: commands.StartHook) -> None:
|
||||||
data, = hook.args()
|
data, = hook.args()
|
||||||
data.reply = AsyncReply(data)
|
data.reply = AsyncReply(data)
|
||||||
await ctx.master.addons.handle_lifecycle(hook)
|
await ctx.master.addons.handle_lifecycle(hook)
|
||||||
@ -185,7 +185,7 @@ class ClientPlayback:
|
|||||||
f.revert()
|
f.revert()
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
|
|
||||||
ctx.master.addons.trigger(UpdateEvent(updated))
|
ctx.master.addons.trigger(UpdateEventHook(updated))
|
||||||
ctx.log.alert("Client replay queue cleared.")
|
ctx.log.alert("Client replay queue cleared.")
|
||||||
|
|
||||||
@command.command("replay.client")
|
@command.command("replay.client")
|
||||||
@ -209,7 +209,7 @@ class ClientPlayback:
|
|||||||
http_flow.error = None
|
http_flow.error = None
|
||||||
self.queue.put_nowait(http_flow)
|
self.queue.put_nowait(http_flow)
|
||||||
updated.append(http_flow)
|
updated.append(http_flow)
|
||||||
ctx.master.addons.trigger(UpdateEvent(updated))
|
ctx.master.addons.trigger(UpdateEventHook(updated))
|
||||||
|
|
||||||
@command.command("replay.client.file")
|
@command.command("replay.client.file")
|
||||||
def load_file(self, path: mitmproxy.types.Path) -> None:
|
def load_file(self, path: mitmproxy.types.Path) -> None:
|
||||||
|
@ -3,7 +3,7 @@ import typing
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
from mitmproxy import ctx, events
|
from mitmproxy import ctx, event_hooks
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import command
|
from mitmproxy import command
|
||||||
from mitmproxy import flow
|
from mitmproxy import flow
|
||||||
@ -99,7 +99,7 @@ class Core:
|
|||||||
intercepted = [i for i in flows if i.intercepted]
|
intercepted = [i for i in flows if i.intercepted]
|
||||||
for f in intercepted:
|
for f in intercepted:
|
||||||
f.resume()
|
f.resume()
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(intercepted))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(intercepted))
|
||||||
|
|
||||||
# FIXME: this will become view.mark later
|
# FIXME: this will become view.mark later
|
||||||
@command.command("flow.mark")
|
@command.command("flow.mark")
|
||||||
@ -112,7 +112,7 @@ class Core:
|
|||||||
if i.marked != boolean:
|
if i.marked != boolean:
|
||||||
i.marked = boolean
|
i.marked = boolean
|
||||||
updated.append(i)
|
updated.append(i)
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
|
|
||||||
# FIXME: this will become view.mark.toggle later
|
# FIXME: this will become view.mark.toggle later
|
||||||
@command.command("flow.mark.toggle")
|
@command.command("flow.mark.toggle")
|
||||||
@ -122,7 +122,7 @@ class Core:
|
|||||||
"""
|
"""
|
||||||
for i in flows:
|
for i in flows:
|
||||||
i.marked = not i.marked
|
i.marked = not i.marked
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(flows))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(flows))
|
||||||
|
|
||||||
@command.command("flow.kill")
|
@command.command("flow.kill")
|
||||||
def kill(self, flows: typing.Sequence[flow.Flow]) -> None:
|
def kill(self, flows: typing.Sequence[flow.Flow]) -> None:
|
||||||
@ -135,7 +135,7 @@ class Core:
|
|||||||
f.kill()
|
f.kill()
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
ctx.log.alert("Killed %s flows." % len(updated))
|
ctx.log.alert("Killed %s flows." % len(updated))
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
|
|
||||||
# FIXME: this will become view.revert later
|
# FIXME: this will become view.revert later
|
||||||
@command.command("flow.revert")
|
@command.command("flow.revert")
|
||||||
@ -149,7 +149,7 @@ class Core:
|
|||||||
f.revert()
|
f.revert()
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
ctx.log.alert("Reverted %s flows." % len(updated))
|
ctx.log.alert("Reverted %s flows." % len(updated))
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
|
|
||||||
@command.command("flow.set.options")
|
@command.command("flow.set.options")
|
||||||
def flow_set_options(self) -> typing.Sequence[str]:
|
def flow_set_options(self) -> typing.Sequence[str]:
|
||||||
@ -218,7 +218,7 @@ class Core:
|
|||||||
if rupdate or supdate:
|
if rupdate or supdate:
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
|
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
ctx.log.alert("Set {} on {} flows.".format(attr, len(updated)))
|
ctx.log.alert("Set {} on {} flows.".format(attr, len(updated)))
|
||||||
|
|
||||||
@command.command("flow.decode")
|
@command.command("flow.decode")
|
||||||
@ -233,7 +233,7 @@ class Core:
|
|||||||
f.backup()
|
f.backup()
|
||||||
p.decode()
|
p.decode()
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
ctx.log.alert("Decoded %s flows." % len(updated))
|
ctx.log.alert("Decoded %s flows." % len(updated))
|
||||||
|
|
||||||
@command.command("flow.encode.toggle")
|
@command.command("flow.encode.toggle")
|
||||||
@ -252,7 +252,7 @@ class Core:
|
|||||||
else:
|
else:
|
||||||
p.decode()
|
p.decode()
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
ctx.log.alert("Toggled encoding on %s flows." % len(updated))
|
ctx.log.alert("Toggled encoding on %s flows." % len(updated))
|
||||||
|
|
||||||
@command.command("flow.encode")
|
@command.command("flow.encode")
|
||||||
@ -275,7 +275,7 @@ class Core:
|
|||||||
f.backup()
|
f.backup()
|
||||||
p.encode(encoding)
|
p.encode(encoding)
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
ctx.log.alert("Encoded %s flows." % len(updated))
|
ctx.log.alert("Encoded %s flows." % len(updated))
|
||||||
|
|
||||||
@command.command("flow.encode.options")
|
@command.command("flow.encode.options")
|
||||||
|
@ -40,7 +40,7 @@ class ProxyConnectionHandler(server.StreamConnectionHandler):
|
|||||||
super().__init__(r, w, options)
|
super().__init__(r, w, options)
|
||||||
self.log_prefix = f"{human.format_address(self.client.peername)}: "
|
self.log_prefix = f"{human.format_address(self.client.peername)}: "
|
||||||
|
|
||||||
async def handle_hook(self, hook: commands.Hook) -> None:
|
async def handle_hook(self, hook: commands.StartHook) -> None:
|
||||||
with self.timeout_watchdog.disarm():
|
with self.timeout_watchdog.disarm():
|
||||||
# We currently only support single-argument hooks.
|
# We currently only support single-argument hooks.
|
||||||
data, = hook.args()
|
data, = hook.args()
|
||||||
@ -53,7 +53,7 @@ class ProxyConnectionHandler(server.StreamConnectionHandler):
|
|||||||
x = log.LogEntry(self.log_prefix + message, level)
|
x = log.LogEntry(self.log_prefix + message, level)
|
||||||
x.reply = controller.DummyReply() # type: ignore
|
x.reply = controller.DummyReply() # type: ignore
|
||||||
asyncio_utils.create_task(
|
asyncio_utils.create_task(
|
||||||
self.master.addons.handle_lifecycle(log.AddLogEvent(x)),
|
self.master.addons.handle_lifecycle(log.AddLogEventHook(x)),
|
||||||
name="ProxyConnectionHandler.log"
|
name="ProxyConnectionHandler.log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import types
|
|||||||
import typing
|
import typing
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from mitmproxy import addonmanager, events
|
from mitmproxy import addonmanager, event_hooks
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import flow
|
from mitmproxy import flow
|
||||||
from mitmproxy import command
|
from mitmproxy import command
|
||||||
@ -104,11 +104,11 @@ class Script:
|
|||||||
if self.ns:
|
if self.ns:
|
||||||
# We're already running, so we have to explicitly register and
|
# We're already running, so we have to explicitly register and
|
||||||
# configure the addon
|
# configure the addon
|
||||||
ctx.master.addons.invoke_addon(self.ns, events.RunningEvent())
|
ctx.master.addons.invoke_addon(self.ns, event_hooks.RunningEventHook())
|
||||||
try:
|
try:
|
||||||
ctx.master.addons.invoke_addon(
|
ctx.master.addons.invoke_addon(
|
||||||
self.ns,
|
self.ns,
|
||||||
events.ConfigureEvent(ctx.options.keys())
|
event_hooks.ConfigureEventHook(ctx.options.keys())
|
||||||
)
|
)
|
||||||
except exceptions.OptionsError as e:
|
except exceptions.OptionsError as e:
|
||||||
script_error_handler(self.fullpath, e, msg=str(e))
|
script_error_handler(self.fullpath, e, msg=str(e))
|
||||||
@ -160,10 +160,10 @@ class ScriptLoader:
|
|||||||
mod = load_script(path)
|
mod = load_script(path)
|
||||||
if mod:
|
if mod:
|
||||||
with addonmanager.safecall():
|
with addonmanager.safecall():
|
||||||
ctx.master.addons.invoke_addon(mod, events.RunningEvent())
|
ctx.master.addons.invoke_addon(mod, event_hooks.RunningEventHook())
|
||||||
ctx.master.addons.invoke_addon(
|
ctx.master.addons.invoke_addon(
|
||||||
mod,
|
mod,
|
||||||
events.ConfigureEvent(ctx.options.keys()),
|
event_hooks.ConfigureEventHook(ctx.options.keys()),
|
||||||
)
|
)
|
||||||
for f in flows:
|
for f in flows:
|
||||||
for evt in eventsequence.iterate(f):
|
for evt in eventsequence.iterate(f):
|
||||||
@ -208,4 +208,4 @@ class ScriptLoader:
|
|||||||
if self.is_running:
|
if self.is_running:
|
||||||
# If we're already running, we configure and tell the addon
|
# If we're already running, we configure and tell the addon
|
||||||
# we're up and running.
|
# we're up and running.
|
||||||
ctx.master.addons.invoke_addon(s, events.RunningEvent())
|
ctx.master.addons.invoke_addon(s, event_hooks.RunningEventHook())
|
||||||
|
@ -3,7 +3,7 @@ import typing
|
|||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
import mitmproxy.types
|
import mitmproxy.types
|
||||||
from mitmproxy import command, events
|
from mitmproxy import command, event_hooks
|
||||||
from mitmproxy import ctx, http
|
from mitmproxy import ctx, http
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import flow
|
from mitmproxy import flow
|
||||||
@ -89,7 +89,7 @@ class ServerPlayback:
|
|||||||
if isinstance(f, http.HTTPFlow):
|
if isinstance(f, http.HTTPFlow):
|
||||||
lst = self.flowmap.setdefault(self._hash(f), [])
|
lst = self.flowmap.setdefault(self._hash(f), [])
|
||||||
lst.append(f)
|
lst.append(f)
|
||||||
ctx.master.addons.trigger(events.UpdateEvent([]))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook([]))
|
||||||
|
|
||||||
@command.command("replay.server.file")
|
@command.command("replay.server.file")
|
||||||
def load_file(self, path: mitmproxy.types.Path) -> None:
|
def load_file(self, path: mitmproxy.types.Path) -> None:
|
||||||
@ -105,7 +105,7 @@ class ServerPlayback:
|
|||||||
Stop server replay.
|
Stop server replay.
|
||||||
"""
|
"""
|
||||||
self.flowmap = {}
|
self.flowmap = {}
|
||||||
ctx.master.addons.trigger(events.UpdateEvent([]))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook([]))
|
||||||
|
|
||||||
@command.command("replay.server.count")
|
@command.command("replay.server.count")
|
||||||
def count(self) -> int:
|
def count(self) -> int:
|
||||||
|
@ -15,7 +15,7 @@ import blinker
|
|||||||
import sortedcontainers
|
import sortedcontainers
|
||||||
|
|
||||||
import mitmproxy.flow
|
import mitmproxy.flow
|
||||||
from mitmproxy import flowfilter, events
|
from mitmproxy import flowfilter, event_hooks
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import command
|
from mitmproxy import command
|
||||||
from mitmproxy import ctx
|
from mitmproxy import ctx
|
||||||
@ -381,7 +381,7 @@ class View(collections.abc.Sequence):
|
|||||||
current = self.settings[f].get("key", "false")
|
current = self.settings[f].get("key", "false")
|
||||||
self.settings[f][key] = "false" if current == "true" else "true"
|
self.settings[f][key] = "false" if current == "true" else "true"
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
|
|
||||||
@command.command("view.settings.setval")
|
@command.command("view.settings.setval")
|
||||||
def setvalue(
|
def setvalue(
|
||||||
@ -396,7 +396,7 @@ class View(collections.abc.Sequence):
|
|||||||
for f in flows:
|
for f in flows:
|
||||||
self.settings[f][key] = value
|
self.settings[f][key] = value
|
||||||
updated.append(f)
|
updated.append(f)
|
||||||
ctx.master.addons.trigger(events.UpdateEvent(updated))
|
ctx.master.addons.trigger(event_hooks.UpdateEventHook(updated))
|
||||||
|
|
||||||
# Flows
|
# Flows
|
||||||
@command.command("view.flows.duplicate")
|
@command.command("view.flows.duplicate")
|
||||||
|
@ -9,7 +9,7 @@ if TYPE_CHECKING:
|
|||||||
import mitmproxy.log
|
import mitmproxy.log
|
||||||
|
|
||||||
|
|
||||||
class MitmproxyEvent:
|
class EventHook:
|
||||||
name: ClassVar[str]
|
name: ClassVar[str]
|
||||||
|
|
||||||
def args(self) -> List[Any]:
|
def args(self) -> List[Any]:
|
||||||
@ -19,7 +19,7 @@ class MitmproxyEvent:
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
if cls is MitmproxyEvent:
|
if cls is EventHook:
|
||||||
raise TypeError("MitmproxyEvent may not be instantiated directly.")
|
raise TypeError("MitmproxyEvent may not be instantiated directly.")
|
||||||
if not is_dataclass(cls):
|
if not is_dataclass(cls):
|
||||||
raise TypeError("Subclass is not a dataclass.")
|
raise TypeError("Subclass is not a dataclass.")
|
||||||
@ -42,11 +42,11 @@ class MitmproxyEvent:
|
|||||||
cls.__eq__ = object.__eq__
|
cls.__eq__ = object.__eq__
|
||||||
|
|
||||||
|
|
||||||
all_events: Dict[str, Type[MitmproxyEvent]] = {}
|
all_events: Dict[str, Type[EventHook]] = {}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ConfigureEvent(MitmproxyEvent):
|
class ConfigureEventHook(EventHook):
|
||||||
"""
|
"""
|
||||||
Called when configuration changes. The updated argument is a
|
Called when configuration changes. The updated argument is a
|
||||||
set-like object containing the keys of all changed options. This
|
set-like object containing the keys of all changed options. This
|
||||||
@ -56,7 +56,7 @@ class ConfigureEvent(MitmproxyEvent):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DoneEvent(MitmproxyEvent):
|
class DoneEventHook(EventHook):
|
||||||
"""
|
"""
|
||||||
Called when the addon shuts down, either by being removed from
|
Called when the addon shuts down, either by being removed from
|
||||||
the mitmproxy instance, or when mitmproxy itself shuts down. On
|
the mitmproxy instance, or when mitmproxy itself shuts down. On
|
||||||
@ -68,7 +68,7 @@ class DoneEvent(MitmproxyEvent):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RunningEvent(MitmproxyEvent):
|
class RunningEventHook(EventHook):
|
||||||
"""
|
"""
|
||||||
Called when the proxy is completely up and running. At this point,
|
Called when the proxy is completely up and running. At this point,
|
||||||
you can expect the proxy to be bound to a port, and all addons to be
|
you can expect the proxy to be bound to a port, and all addons to be
|
||||||
@ -77,7 +77,7 @@ class RunningEvent(MitmproxyEvent):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class UpdateEvent(MitmproxyEvent):
|
class UpdateEventHook(EventHook):
|
||||||
"""
|
"""
|
||||||
Update is called when one or more flow objects have been modified,
|
Update is called when one or more flow objects have been modified,
|
||||||
usually from a different addon.
|
usually from a different addon.
|
@ -1,14 +1,14 @@
|
|||||||
from typing import Iterator, Any, Dict, Type, Callable
|
from typing import Iterator, Any, Dict, Type, Callable
|
||||||
|
|
||||||
from mitmproxy import controller
|
from mitmproxy import controller
|
||||||
from mitmproxy import events
|
from mitmproxy import event_hooks
|
||||||
from mitmproxy import flow
|
from mitmproxy import flow
|
||||||
from mitmproxy import http
|
from mitmproxy import http
|
||||||
from mitmproxy import tcp
|
from mitmproxy import tcp
|
||||||
from mitmproxy import websocket
|
from mitmproxy import websocket
|
||||||
from mitmproxy.proxy import layers
|
from mitmproxy.proxy import layers
|
||||||
|
|
||||||
TEventGenerator = Iterator[events.MitmproxyEvent]
|
TEventGenerator = Iterator[event_hooks.EventHook]
|
||||||
|
|
||||||
|
|
||||||
def _iterate_http(f: http.HTTPFlow) -> TEventGenerator:
|
def _iterate_http(f: http.HTTPFlow) -> TEventGenerator:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from mitmproxy import events
|
from mitmproxy import event_hooks
|
||||||
|
|
||||||
|
|
||||||
class LogEntry:
|
class LogEntry:
|
||||||
@ -60,12 +60,12 @@ class Log:
|
|||||||
|
|
||||||
def __call__(self, text, level="info"):
|
def __call__(self, text, level="info"):
|
||||||
asyncio.get_event_loop().call_soon(
|
asyncio.get_event_loop().call_soon(
|
||||||
self.master.addons.trigger, AddLogEvent(LogEntry(text, level)),
|
self.master.addons.trigger, AddLogEventHook(LogEntry(text, level)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AddLogEvent(events.MitmproxyEvent):
|
class AddLogEventHook(event_hooks.EventHook):
|
||||||
"""
|
"""
|
||||||
Called whenever a new log entry is created through the mitmproxy
|
Called whenever a new log entry is created through the mitmproxy
|
||||||
context. Be careful not to log from this event, which will cause an
|
context. Be careful not to log from this event, which will cause an
|
||||||
|
@ -4,7 +4,7 @@ import sys
|
|||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from mitmproxy import addonmanager, events
|
from mitmproxy import addonmanager, event_hooks
|
||||||
from mitmproxy import command
|
from mitmproxy import command
|
||||||
from mitmproxy import controller
|
from mitmproxy import controller
|
||||||
from mitmproxy import eventsequence
|
from mitmproxy import eventsequence
|
||||||
@ -45,7 +45,7 @@ class Master:
|
|||||||
self.should_exit.clear()
|
self.should_exit.clear()
|
||||||
|
|
||||||
async def running(self):
|
async def running(self):
|
||||||
self.addons.trigger(events.RunningEvent())
|
self.addons.trigger(event_hooks.RunningEventHook())
|
||||||
|
|
||||||
def run_loop(self, loop):
|
def run_loop(self, loop):
|
||||||
self.start()
|
self.start()
|
||||||
@ -71,7 +71,7 @@ class Master:
|
|||||||
print("Please lodge a bug report at:", file=sys.stderr)
|
print("Please lodge a bug report at:", file=sys.stderr)
|
||||||
print("\thttps://github.com/mitmproxy/mitmproxy", file=sys.stderr)
|
print("\thttps://github.com/mitmproxy/mitmproxy", file=sys.stderr)
|
||||||
|
|
||||||
self.addons.trigger(events.DoneEvent())
|
self.addons.trigger(event_hooks.DoneEventHook())
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
@ -8,7 +8,7 @@ The counterpart to commands are events.
|
|||||||
"""
|
"""
|
||||||
from typing import Literal, Union, TYPE_CHECKING
|
from typing import Literal, Union, TYPE_CHECKING
|
||||||
|
|
||||||
import mitmproxy.events
|
import mitmproxy.event_hooks
|
||||||
from mitmproxy.proxy.context import Connection, Server
|
from mitmproxy.proxy.context import Connection, Server
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -86,15 +86,16 @@ class CloseConnection(ConnectionCommand):
|
|||||||
self.half_close = half_close
|
self.half_close = half_close
|
||||||
|
|
||||||
|
|
||||||
class Hook(Command, mitmproxy.events.MitmproxyEvent):
|
class StartHook(Command, mitmproxy.event_hooks.EventHook):
|
||||||
"""
|
"""
|
||||||
Callback to the master (like ".ask()")
|
Start an event hook in the mitmproxy core.
|
||||||
|
This triggers a particular function (derived from the class name) in all addons.
|
||||||
"""
|
"""
|
||||||
blocking = True
|
blocking = True
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
if cls is Hook:
|
if cls is StartHook:
|
||||||
raise TypeError("Hook may not be instantiated directly.")
|
raise TypeError("StartHook may not be instantiated directly.")
|
||||||
return super().__new__(cls, *args, **kwargs)
|
return super().__new__(cls, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ class ConnectionClosed(ConnectionEvent):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CommandReply(Event):
|
class CommandCompleted(Event):
|
||||||
"""
|
"""
|
||||||
Emitted when a command has been finished, e.g.
|
Emitted when a command has been finished, e.g.
|
||||||
when the master has replied or when we have established a server connection.
|
when the master has replied or when we have established a server connection.
|
||||||
@ -64,8 +64,8 @@ class CommandReply(Event):
|
|||||||
reply: typing.Any
|
reply: typing.Any
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
if cls is CommandReply:
|
if cls is CommandCompleted:
|
||||||
raise TypeError("CommandReply may not be instantiated directly.")
|
raise TypeError("CommandCompleted may not be instantiated directly.")
|
||||||
assert is_dataclass(cls)
|
assert is_dataclass(cls)
|
||||||
return super().__new__(cls)
|
return super().__new__(cls)
|
||||||
|
|
||||||
@ -85,23 +85,23 @@ class CommandReply(Event):
|
|||||||
return f"Reply({repr(self.command)})"
|
return f"Reply({repr(self.command)})"
|
||||||
|
|
||||||
|
|
||||||
command_reply_subclasses: typing.Dict[commands.Command, typing.Type[CommandReply]] = {}
|
command_reply_subclasses: typing.Dict[commands.Command, typing.Type[CommandCompleted]] = {}
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
class OpenConnectionReply(CommandReply):
|
class OpenConnectionCompleted(CommandCompleted):
|
||||||
command: commands.OpenConnection
|
command: commands.OpenConnection
|
||||||
reply: typing.Optional[str]
|
reply: typing.Optional[str]
|
||||||
"""error message"""
|
"""error message"""
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
class HookReply(CommandReply):
|
class HookCompleted(CommandCompleted):
|
||||||
command: commands.Hook
|
command: commands.StartHook
|
||||||
reply: None = None
|
reply: None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(repr=False)
|
@dataclass(repr=False)
|
||||||
class GetSocketReply(CommandReply):
|
class GetSocketCompleted(CommandCompleted):
|
||||||
command: commands.GetSocket
|
command: commands.GetSocket
|
||||||
reply: socket.socket
|
reply: socket.socket
|
||||||
|
@ -8,7 +8,7 @@ from dataclasses import dataclass
|
|||||||
from typing import Optional, List, ClassVar, Deque, NamedTuple, Generator, Any, TypeVar
|
from typing import Optional, List, ClassVar, Deque, NamedTuple, Generator, Any, TypeVar
|
||||||
|
|
||||||
from mitmproxy.proxy import commands, events
|
from mitmproxy.proxy import commands, events
|
||||||
from mitmproxy.proxy.commands import Command, Hook
|
from mitmproxy.proxy.commands import Command, StartHook
|
||||||
from mitmproxy.proxy.context import Connection, Context
|
from mitmproxy.proxy.context import Connection, Context
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
@ -35,8 +35,8 @@ class Layer:
|
|||||||
Most layers only implement ._handle_event, which is called by the default implementation of .handle_event.
|
Most layers only implement ._handle_event, which is called by the default implementation of .handle_event.
|
||||||
The default implementation allows layers to emulate blocking code:
|
The default implementation allows layers to emulate blocking code:
|
||||||
When ._handle_event yields a command that has its blocking attribute set to True, .handle_event pauses
|
When ._handle_event yields a command that has its blocking attribute set to True, .handle_event pauses
|
||||||
the execution of ._handle_event and waits until it is called with the corresponding CommandReply. All events
|
the execution of ._handle_event and waits until it is called with the corresponding CommandCompleted event. All
|
||||||
encountered in the meantime are buffered and replayed after execution is resumed.
|
events encountered in the meantime are buffered and replayed after execution is resumed.
|
||||||
|
|
||||||
The result is code that looks like blocking code, but is not blocking:
|
The result is code that looks like blocking code, but is not blocking:
|
||||||
|
|
||||||
@ -96,13 +96,13 @@ class Layer:
|
|||||||
if self._paused:
|
if self._paused:
|
||||||
# did we just receive the reply we were waiting for?
|
# did we just receive the reply we were waiting for?
|
||||||
pause_finished = (
|
pause_finished = (
|
||||||
isinstance(event, events.CommandReply) and
|
isinstance(event, events.CommandCompleted) and
|
||||||
event.command is self._paused.command
|
event.command is self._paused.command
|
||||||
)
|
)
|
||||||
if self.debug is not None:
|
if self.debug is not None:
|
||||||
yield self.__debug(f"{'>>' if pause_finished else '>!'} {event}")
|
yield self.__debug(f"{'>>' if pause_finished else '>!'} {event}")
|
||||||
if pause_finished:
|
if pause_finished:
|
||||||
assert isinstance(event, events.CommandReply)
|
assert isinstance(event, events.CommandCompleted)
|
||||||
yield from self.__continue(event)
|
yield from self.__continue(event)
|
||||||
else:
|
else:
|
||||||
self._paused_event_queue.append(event)
|
self._paused_event_queue.append(event)
|
||||||
@ -142,7 +142,7 @@ class Layer:
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
return
|
return
|
||||||
|
|
||||||
def __continue(self, event: events.CommandReply):
|
def __continue(self, event: events.CommandCompleted):
|
||||||
"""continue processing events after being paused"""
|
"""continue processing events after being paused"""
|
||||||
assert self._paused is not None
|
assert self._paused is not None
|
||||||
command_generator = self._paused.generator
|
command_generator = self._paused.generator
|
||||||
@ -241,7 +241,7 @@ class NextLayer(Layer):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NextLayerHook(Hook):
|
class NextLayerHook(StartHook):
|
||||||
"""
|
"""
|
||||||
Network layers are being switched. You may change which layer will be used by setting data.layer.
|
Network layers are being switched. You may change which layer will be used by setting data.layer.
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class GetHttpConnection(HttpCommand):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class GetHttpConnectionReply(events.CommandReply):
|
class GetHttpConnectionCompleted(events.CommandCompleted):
|
||||||
command: GetHttpConnection
|
command: GetHttpConnection
|
||||||
reply: Union[Tuple[None, str], Tuple[Connection, None]]
|
reply: Union[Tuple[None, str], Tuple[Connection, None]]
|
||||||
"""connection object, error message"""
|
"""connection object, error message"""
|
||||||
@ -554,7 +554,7 @@ class HttpLayer(layer.Layer):
|
|||||||
yield from self.event_to_child(self.connections[self.context.client], event)
|
yield from self.event_to_child(self.connections[self.context.client], event)
|
||||||
if self.mode is HTTPMode.upstream:
|
if self.mode is HTTPMode.upstream:
|
||||||
self.context.server.via = server_spec.parse_with_mode(self.context.options.mode)[1]
|
self.context.server.via = server_spec.parse_with_mode(self.context.options.mode)[1]
|
||||||
elif isinstance(event, events.CommandReply):
|
elif isinstance(event, events.CommandCompleted):
|
||||||
stream = self.command_sources.pop(event.command)
|
stream = self.command_sources.pop(event.command)
|
||||||
yield from self.event_to_child(stream, event)
|
yield from self.event_to_child(stream, event)
|
||||||
elif isinstance(event, events.ConnectionEvent):
|
elif isinstance(event, events.ConnectionEvent):
|
||||||
@ -574,7 +574,7 @@ class HttpLayer(layer.Layer):
|
|||||||
) -> layer.CommandGenerator[None]:
|
) -> layer.CommandGenerator[None]:
|
||||||
for command in child.handle_event(event):
|
for command in child.handle_event(event):
|
||||||
assert isinstance(command, commands.Command)
|
assert isinstance(command, commands.Command)
|
||||||
# Streams may yield blocking commands, which ultimately generate CommandReply events.
|
# Streams may yield blocking commands, which ultimately generate CommandCompleted events.
|
||||||
# Those need to be routed back to the correct stream, so we need to keep track of that.
|
# Those need to be routed back to the correct stream, so we need to keep track of that.
|
||||||
|
|
||||||
if command.blocking:
|
if command.blocking:
|
||||||
@ -624,7 +624,7 @@ class HttpLayer(layer.Layer):
|
|||||||
self.waiting_for_establishment[connection].append(event)
|
self.waiting_for_establishment[connection].append(event)
|
||||||
else:
|
else:
|
||||||
stream = self.command_sources.pop(event)
|
stream = self.command_sources.pop(event)
|
||||||
yield from self.event_to_child(stream, GetHttpConnectionReply(event, (connection, None)))
|
yield from self.event_to_child(stream, GetHttpConnectionCompleted(event, (connection, None)))
|
||||||
return
|
return
|
||||||
|
|
||||||
can_use_context_connection = (
|
can_use_context_connection = (
|
||||||
@ -674,7 +674,7 @@ class HttpLayer(layer.Layer):
|
|||||||
|
|
||||||
for cmd in waiting:
|
for cmd in waiting:
|
||||||
stream = self.command_sources.pop(cmd)
|
stream = self.command_sources.pop(cmd)
|
||||||
yield from self.event_to_child(stream, GetHttpConnectionReply(cmd, reply))
|
yield from self.event_to_child(stream, GetHttpConnectionCompleted(cmd, reply))
|
||||||
|
|
||||||
# Somewhat ugly edge case: If we do HTTP/2 -> HTTP/1 proxying we don't want
|
# Somewhat ugly edge case: If we do HTTP/2 -> HTTP/1 proxying we don't want
|
||||||
# to handle everything over a single connection.
|
# to handle everything over a single connection.
|
||||||
|
@ -5,7 +5,7 @@ from mitmproxy.proxy import commands
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class HttpRequestHeadersHook(commands.Hook):
|
class HttpRequestHeadersHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
HTTP request headers were successfully read. At this point, the body is empty.
|
HTTP request headers were successfully read. At this point, the body is empty.
|
||||||
"""
|
"""
|
||||||
@ -14,7 +14,7 @@ class HttpRequestHeadersHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class HttpRequestHook(commands.Hook):
|
class HttpRequestHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
The full HTTP request has been read.
|
The full HTTP request has been read.
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ class HttpRequestHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class HttpResponseHeadersHook(commands.Hook):
|
class HttpResponseHeadersHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
The full HTTP response has been read.
|
The full HTTP response has been read.
|
||||||
"""
|
"""
|
||||||
@ -35,7 +35,7 @@ class HttpResponseHeadersHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class HttpResponseHook(commands.Hook):
|
class HttpResponseHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
HTTP response headers were successfully read. At this point, the body is empty.
|
HTTP response headers were successfully read. At this point, the body is empty.
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class HttpResponseHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class HttpErrorHook(commands.Hook):
|
class HttpErrorHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
An HTTP error has occurred, e.g. invalid server responses, or
|
An HTTP error has occurred, e.g. invalid server responses, or
|
||||||
interrupted connections. This is distinct from a valid server HTTP
|
interrupted connections. This is distinct from a valid server HTTP
|
||||||
@ -59,7 +59,7 @@ class HttpErrorHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class HttpConnectHook(commands.Hook):
|
class HttpConnectHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
An HTTP CONNECT request was received. This event can be ignored for most practical purposes.
|
An HTTP CONNECT request was received. This event can be ignored for most practical purposes.
|
||||||
|
|
||||||
|
@ -3,13 +3,13 @@ from typing import Optional
|
|||||||
|
|
||||||
from mitmproxy import flow, tcp
|
from mitmproxy import flow, tcp
|
||||||
from mitmproxy.proxy import commands, events, layer
|
from mitmproxy.proxy import commands, events, layer
|
||||||
from mitmproxy.proxy.commands import Hook
|
from mitmproxy.proxy.commands import StartHook
|
||||||
from mitmproxy.proxy.context import ConnectionState, Context, Connection
|
from mitmproxy.proxy.context import ConnectionState, Context, Connection
|
||||||
from mitmproxy.proxy.utils import expect
|
from mitmproxy.proxy.utils import expect
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TcpStartHook(Hook):
|
class TcpStartHook(StartHook):
|
||||||
"""
|
"""
|
||||||
A TCP connection has started.
|
A TCP connection has started.
|
||||||
"""
|
"""
|
||||||
@ -18,7 +18,7 @@ class TcpStartHook(Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TcpMessageHook(Hook):
|
class TcpMessageHook(StartHook):
|
||||||
"""
|
"""
|
||||||
A TCP connection has received a message. The most recent message
|
A TCP connection has received a message. The most recent message
|
||||||
will be flow.messages[-1]. The message is user-modifiable.
|
will be flow.messages[-1]. The message is user-modifiable.
|
||||||
@ -27,7 +27,7 @@ class TcpMessageHook(Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TcpEndHook(Hook):
|
class TcpEndHook(StartHook):
|
||||||
"""
|
"""
|
||||||
A TCP connection has ended.
|
A TCP connection has ended.
|
||||||
"""
|
"""
|
||||||
@ -35,7 +35,7 @@ class TcpEndHook(Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TcpErrorHook(Hook):
|
class TcpErrorHook(StartHook):
|
||||||
"""
|
"""
|
||||||
A TCP error has occurred.
|
A TCP error has occurred.
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ from mitmproxy import certs
|
|||||||
from mitmproxy.net import tls as net_tls
|
from mitmproxy.net import tls as net_tls
|
||||||
from mitmproxy.proxy import commands, events, layer, tunnel
|
from mitmproxy.proxy import commands, events, layer, tunnel
|
||||||
from mitmproxy.proxy import context
|
from mitmproxy.proxy import context
|
||||||
from mitmproxy.proxy.commands import Hook
|
from mitmproxy.proxy.commands import StartHook
|
||||||
from mitmproxy.utils import human
|
from mitmproxy.utils import human
|
||||||
|
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ class ClientHelloData:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TlsClienthelloHook(Hook):
|
class TlsClienthelloHook(StartHook):
|
||||||
"""
|
"""
|
||||||
Mitmproxy has received a TLS ClientHello message.
|
Mitmproxy has received a TLS ClientHello message.
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ class TlsStartData:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TlsStartHook(Hook):
|
class TlsStartHook(StartHook):
|
||||||
"""
|
"""
|
||||||
TLS Negotation is about to start.
|
TLS Negotation is about to start.
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import wsproto.frame_protocol
|
|||||||
import wsproto.utilities
|
import wsproto.utilities
|
||||||
from mitmproxy import flow, websocket, http
|
from mitmproxy import flow, websocket, http
|
||||||
from mitmproxy.proxy import commands, events, layer, context
|
from mitmproxy.proxy import commands, events, layer, context
|
||||||
from mitmproxy.proxy.commands import Hook
|
from mitmproxy.proxy.commands import StartHook
|
||||||
from mitmproxy.proxy.context import Context
|
from mitmproxy.proxy.context import Context
|
||||||
from mitmproxy.proxy.utils import expect
|
from mitmproxy.proxy.utils import expect
|
||||||
from wsproto import ConnectionState
|
from wsproto import ConnectionState
|
||||||
@ -15,7 +15,7 @@ from wsproto.frame_protocol import CloseReason, Opcode
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class WebsocketStartHook(Hook):
|
class WebsocketStartHook(StartHook):
|
||||||
"""
|
"""
|
||||||
A WebSocket connection has commenced.
|
A WebSocket connection has commenced.
|
||||||
"""
|
"""
|
||||||
@ -23,7 +23,7 @@ class WebsocketStartHook(Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class WebsocketMessageHook(Hook):
|
class WebsocketMessageHook(StartHook):
|
||||||
"""
|
"""
|
||||||
Called when a WebSocket message is received from the client or
|
Called when a WebSocket message is received from the client or
|
||||||
server. The most recent message will be flow.messages[-1]. The
|
server. The most recent message will be flow.messages[-1]. The
|
||||||
@ -34,7 +34,7 @@ class WebsocketMessageHook(Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class WebsocketEndHook(Hook):
|
class WebsocketEndHook(StartHook):
|
||||||
"""
|
"""
|
||||||
A WebSocket connection has ended.
|
A WebSocket connection has ended.
|
||||||
"""
|
"""
|
||||||
@ -43,7 +43,7 @@ class WebsocketEndHook(Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class WebsocketErrorHook(Hook):
|
class WebsocketErrorHook(StartHook):
|
||||||
"""
|
"""
|
||||||
A WebSocket connection has had an error.
|
A WebSocket connection has had an error.
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
|
|||||||
async def open_connection(self, command: commands.OpenConnection) -> None:
|
async def open_connection(self, command: commands.OpenConnection) -> None:
|
||||||
if not command.connection.address:
|
if not command.connection.address:
|
||||||
self.log(f"Cannot open connection, no hostname given.")
|
self.log(f"Cannot open connection, no hostname given.")
|
||||||
self.server_event(events.OpenConnectionReply(command, f"Cannot open connection, no hostname given."))
|
self.server_event(events.OpenConnectionCompleted(command, f"Cannot open connection, no hostname given."))
|
||||||
return
|
return
|
||||||
|
|
||||||
hook_data = server_hooks.ServerConnectionHookData(
|
hook_data = server_hooks.ServerConnectionHookData(
|
||||||
@ -143,7 +143,7 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
|
|||||||
await self.handle_hook(server_hooks.ServerConnectHook(hook_data))
|
await self.handle_hook(server_hooks.ServerConnectHook(hook_data))
|
||||||
if command.connection.error:
|
if command.connection.error:
|
||||||
self.log(f"server connection to {human.format_address(command.connection.address)} killed before connect.")
|
self.log(f"server connection to {human.format_address(command.connection.address)} killed before connect.")
|
||||||
self.server_event(events.OpenConnectionReply(command, "Connection killed."))
|
self.server_event(events.OpenConnectionCompleted(command, "Connection killed."))
|
||||||
return
|
return
|
||||||
|
|
||||||
async with self.max_conns[command.connection.address]:
|
async with self.max_conns[command.connection.address]:
|
||||||
@ -156,7 +156,7 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
|
|||||||
err = "connection cancelled"
|
err = "connection cancelled"
|
||||||
self.log(f"error establishing server connection: {err}")
|
self.log(f"error establishing server connection: {err}")
|
||||||
command.connection.error = err
|
command.connection.error = err
|
||||||
self.server_event(events.OpenConnectionReply(command, err))
|
self.server_event(events.OpenConnectionCompleted(command, err))
|
||||||
if isinstance(e, asyncio.CancelledError):
|
if isinstance(e, asyncio.CancelledError):
|
||||||
# From https://docs.python.org/3/library/asyncio-exceptions.html#asyncio.CancelledError:
|
# From https://docs.python.org/3/library/asyncio-exceptions.html#asyncio.CancelledError:
|
||||||
# > In almost all situations the exception must be re-raised.
|
# > In almost all situations the exception must be re-raised.
|
||||||
@ -184,7 +184,7 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
|
|||||||
if not connected_hook:
|
if not connected_hook:
|
||||||
return # this should not be needed, see asyncio_utils.create_task
|
return # this should not be needed, see asyncio_utils.create_task
|
||||||
|
|
||||||
self.server_event(events.OpenConnectionReply(command, None))
|
self.server_event(events.OpenConnectionCompleted(command, None))
|
||||||
|
|
||||||
# during connection opening, this function is the designated handler that can be cancelled.
|
# during connection opening, this function is the designated handler that can be cancelled.
|
||||||
# once we have a connection, we do want the teardown here to happen in any case, so we
|
# once we have a connection, we do want the teardown here to happen in any case, so we
|
||||||
@ -256,13 +256,13 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
|
|||||||
assert handler
|
assert handler
|
||||||
asyncio_utils.cancel_task(handler, "timeout")
|
asyncio_utils.cancel_task(handler, "timeout")
|
||||||
|
|
||||||
async def hook_task(self, hook: commands.Hook) -> None:
|
async def hook_task(self, hook: commands.StartHook) -> None:
|
||||||
await self.handle_hook(hook)
|
await self.handle_hook(hook)
|
||||||
if hook.blocking:
|
if hook.blocking:
|
||||||
self.server_event(events.HookReply(hook))
|
self.server_event(events.HookCompleted(hook))
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
async def handle_hook(self, hook: commands.Hook) -> None:
|
async def handle_hook(self, hook: commands.StartHook) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def log(self, message: str, level: str = "info") -> None:
|
def log(self, message: str, level: str = "info") -> None:
|
||||||
@ -294,8 +294,8 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
|
|||||||
writer = self.transports[command.connection].writer
|
writer = self.transports[command.connection].writer
|
||||||
assert writer
|
assert writer
|
||||||
socket = writer.get_extra_info("socket")
|
socket = writer.get_extra_info("socket")
|
||||||
self.server_event(events.GetSocketReply(command, socket))
|
self.server_event(events.GetSocketCompleted(command, socket))
|
||||||
elif isinstance(command, commands.Hook):
|
elif isinstance(command, commands.StartHook):
|
||||||
asyncio_utils.create_task(
|
asyncio_utils.create_task(
|
||||||
self.hook_task(command),
|
self.hook_task(command),
|
||||||
name=f"handle_hook({command.name})",
|
name=f"handle_hook({command.name})",
|
||||||
@ -354,7 +354,7 @@ class SimpleConnectionHandler(StreamConnectionHandler): # pragma: no cover
|
|||||||
|
|
||||||
async def handle_hook(
|
async def handle_hook(
|
||||||
self,
|
self,
|
||||||
hook: commands.Hook
|
hook: commands.StartHook
|
||||||
) -> None:
|
) -> None:
|
||||||
if hook.name in self.hook_handlers:
|
if hook.name in self.hook_handlers:
|
||||||
self.hook_handlers[hook.name](*hook.args())
|
self.hook_handlers[hook.name](*hook.args())
|
||||||
|
@ -4,7 +4,7 @@ from . import commands, context
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ClientConnectedHook(commands.Hook):
|
class ClientConnectedHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
A client has connected to mitmproxy. Note that a connection can
|
A client has connected to mitmproxy. Note that a connection can
|
||||||
correspond to multiple HTTP requests.
|
correspond to multiple HTTP requests.
|
||||||
@ -15,7 +15,7 @@ class ClientConnectedHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ClientDisconnectedHook(commands.Hook):
|
class ClientDisconnectedHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
A client connection has been closed (either by us or the client).
|
A client connection has been closed (either by us or the client).
|
||||||
"""
|
"""
|
||||||
@ -30,7 +30,7 @@ class ServerConnectionHookData:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ServerConnectHook(commands.Hook):
|
class ServerConnectHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
Mitmproxy is about to connect to a server.
|
Mitmproxy is about to connect to a server.
|
||||||
Note that a connection can correspond to multiple requests.
|
Note that a connection can correspond to multiple requests.
|
||||||
@ -41,7 +41,7 @@ class ServerConnectHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ServerConnectedHook(commands.Hook):
|
class ServerConnectedHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
Mitmproxy has connected to a server.
|
Mitmproxy has connected to a server.
|
||||||
"""
|
"""
|
||||||
@ -50,7 +50,7 @@ class ServerConnectedHook(commands.Hook):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ServerDisconnectedHook(commands.Hook):
|
class ServerDisconnectedHook(commands.StartHook):
|
||||||
"""
|
"""
|
||||||
A server connection has been closed (either by us or the server).
|
A server connection has been closed (either by us or the server).
|
||||||
"""
|
"""
|
||||||
|
@ -89,7 +89,7 @@ class TunnelLayer(layer.Layer):
|
|||||||
else:
|
else:
|
||||||
self.tunnel_state = TunnelState.OPEN
|
self.tunnel_state = TunnelState.OPEN
|
||||||
if self.command_to_reply_to:
|
if self.command_to_reply_to:
|
||||||
yield from self.event_to_child(events.OpenConnectionReply(self.command_to_reply_to, err))
|
yield from self.event_to_child(events.OpenConnectionCompleted(self.command_to_reply_to, err))
|
||||||
self.command_to_reply_to = None
|
self.command_to_reply_to = None
|
||||||
else:
|
else:
|
||||||
for evt in self._event_queue:
|
for evt in self._event_queue:
|
||||||
@ -117,7 +117,7 @@ class TunnelLayer(layer.Layer):
|
|||||||
self.tunnel_state = TunnelState.ESTABLISHING
|
self.tunnel_state = TunnelState.ESTABLISHING
|
||||||
err = yield commands.OpenConnection(self.tunnel_connection)
|
err = yield commands.OpenConnection(self.tunnel_connection)
|
||||||
if err:
|
if err:
|
||||||
yield from self.event_to_child(events.OpenConnectionReply(command, err))
|
yield from self.event_to_child(events.OpenConnectionCompleted(command, err))
|
||||||
self.tunnel_state = TunnelState.CLOSED
|
self.tunnel_state = TunnelState.CLOSED
|
||||||
else:
|
else:
|
||||||
yield from self.start_handshake()
|
yield from self.start_handshake()
|
||||||
|
@ -3,7 +3,7 @@ This module provides a @concurrent decorator primitive to
|
|||||||
offload computations from mitmproxy's main master thread.
|
offload computations from mitmproxy's main master thread.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from mitmproxy import events
|
from mitmproxy import event_hooks
|
||||||
from mitmproxy.coretypes import basethread
|
from mitmproxy.coretypes import basethread
|
||||||
|
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ class ScriptThread(basethread.BaseThread):
|
|||||||
|
|
||||||
|
|
||||||
def concurrent(fn):
|
def concurrent(fn):
|
||||||
if fn.__name__ not in set(events.all_events.keys()) - {"load", "configure"}:
|
if fn.__name__ not in set(event_hooks.all_events.keys()) - {"load", "configure"}:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Concurrent decorator not supported for '%s' method." % fn.__name__
|
"Concurrent decorator not supported for '%s' method." % fn.__name__
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,7 @@ import sys
|
|||||||
|
|
||||||
import mitmproxy.master
|
import mitmproxy.master
|
||||||
import mitmproxy.options
|
import mitmproxy.options
|
||||||
from mitmproxy import addonmanager, events, log
|
from mitmproxy import addonmanager, event_hooks, log
|
||||||
from mitmproxy import command
|
from mitmproxy import command
|
||||||
from mitmproxy import eventsequence
|
from mitmproxy import eventsequence
|
||||||
from mitmproxy.addons import script, core
|
from mitmproxy.addons import script, core
|
||||||
@ -14,8 +14,8 @@ class TestAddons(addonmanager.AddonManager):
|
|||||||
def __init__(self, master):
|
def __init__(self, master):
|
||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
|
|
||||||
def trigger(self, event: events.MitmproxyEvent):
|
def trigger(self, event: event_hooks.EventHook):
|
||||||
if isinstance(event, log.AddLogEvent):
|
if isinstance(event, log.AddLogEventHook):
|
||||||
self.master.logs.append(event.entry)
|
self.master.logs.append(event.entry)
|
||||||
super().trigger(event)
|
super().trigger(event)
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ class context:
|
|||||||
if kwargs:
|
if kwargs:
|
||||||
self.options.update(**kwargs)
|
self.options.update(**kwargs)
|
||||||
else:
|
else:
|
||||||
self.master.addons.invoke_addon(addon, events.ConfigureEvent(set()))
|
self.master.addons.invoke_addon(addon, event_hooks.ConfigureEventHook(set()))
|
||||||
|
|
||||||
def script(self, path):
|
def script(self, path):
|
||||||
"""
|
"""
|
||||||
@ -115,7 +115,7 @@ class context:
|
|||||||
sc = script.Script(path, False)
|
sc = script.Script(path, False)
|
||||||
return sc.addons[0] if sc.addons else None
|
return sc.addons[0] if sc.addons else None
|
||||||
|
|
||||||
def invoke(self, addon, event: events.MitmproxyEvent):
|
def invoke(self, addon, event: event_hooks.EventHook):
|
||||||
"""
|
"""
|
||||||
Recursively invoke an event on an addon and all its children.
|
Recursively invoke an event on an addon and all its children.
|
||||||
"""
|
"""
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from mitmproxy import ctx
|
from mitmproxy import ctx
|
||||||
from mitmproxy import events
|
from mitmproxy import event_hooks
|
||||||
|
|
||||||
|
|
||||||
class Recorder:
|
class Recorder:
|
||||||
@ -9,7 +9,7 @@ class Recorder:
|
|||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
if attr in events.all_events:
|
if attr in event_hooks.all_events:
|
||||||
def prox(*args, **kwargs):
|
def prox(*args, **kwargs):
|
||||||
lg = (self.name, attr, args, kwargs)
|
lg = (self.name, attr, args, kwargs)
|
||||||
if attr != "add_log":
|
if attr != "add_log":
|
||||||
|
@ -2,7 +2,7 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy.events import all_events
|
from mitmproxy.event_hooks import all_events
|
||||||
from mitmproxy.proxy import commands, context
|
from mitmproxy.proxy import commands, context
|
||||||
|
|
||||||
|
|
||||||
@ -21,10 +21,10 @@ def test_dataclasses(tconn):
|
|||||||
|
|
||||||
def test_hook():
|
def test_hook():
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
commands.Hook()
|
commands.StartHook()
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TestHook(commands.Hook):
|
class TestHook(commands.StartHook):
|
||||||
data: bytes
|
data: bytes
|
||||||
|
|
||||||
f = TestHook(b"foo")
|
f = TestHook(b"foo")
|
||||||
|
@ -16,21 +16,21 @@ def test_dataclasses(tconn):
|
|||||||
assert repr(events.ConnectionClosed(tconn))
|
assert repr(events.ConnectionClosed(tconn))
|
||||||
|
|
||||||
|
|
||||||
def test_commandreply():
|
def test_command_completed():
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
events.CommandReply()
|
events.CommandCompleted()
|
||||||
assert repr(events.HookReply(Mock(), None))
|
assert repr(events.HookCompleted(Mock(), None))
|
||||||
|
|
||||||
class FooCommand(commands.Command):
|
class FooCommand(commands.Command):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with pytest.raises(RuntimeError, match="properly annotated"):
|
with pytest.raises(RuntimeError, match="properly annotated"):
|
||||||
class FooReply(events.CommandReply):
|
class FooCompleted(events.CommandCompleted):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class FooReply1(events.CommandReply):
|
class FooCompleted1(events.CommandCompleted):
|
||||||
command: FooCommand
|
command: FooCommand
|
||||||
|
|
||||||
with pytest.raises(RuntimeError, match="conflicting subclasses"):
|
with pytest.raises(RuntimeError, match="conflicting subclasses"):
|
||||||
class FooReply2(events.CommandReply):
|
class FooCompleted2(events.CommandCompleted):
|
||||||
command: FooCommand
|
command: FooCommand
|
||||||
|
@ -22,7 +22,7 @@ class TCommand(commands.Command):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TCommandReply(events.CommandReply):
|
class TCommandCompleted(events.CommandCompleted):
|
||||||
command: TCommand
|
command: TCommand
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ def _merge_sends(lst: typing.List[commands.Command], ignore_hooks: bool, ignore_
|
|||||||
current_send.data += x.data
|
current_send.data += x.data
|
||||||
else:
|
else:
|
||||||
ignore = (
|
ignore = (
|
||||||
(ignore_hooks and isinstance(x, commands.Hook))
|
(ignore_hooks and isinstance(x, commands.StartHook))
|
||||||
or
|
or
|
||||||
(ignore_logs and isinstance(x, commands.Log))
|
(ignore_logs and isinstance(x, commands.Log))
|
||||||
)
|
)
|
||||||
@ -191,7 +191,7 @@ class Playbook:
|
|||||||
for name, value in vars(x).items():
|
for name, value in vars(x).items():
|
||||||
if isinstance(value, _Placeholder):
|
if isinstance(value, _Placeholder):
|
||||||
setattr(x, name, value())
|
setattr(x, name, value())
|
||||||
if isinstance(x, events.OpenConnectionReply) and not x.reply:
|
if isinstance(x, events.OpenConnectionCompleted) and not x.reply:
|
||||||
x.command.connection.state = ConnectionState.OPEN
|
x.command.connection.state = ConnectionState.OPEN
|
||||||
elif isinstance(x, events.ConnectionClosed):
|
elif isinstance(x, events.ConnectionClosed):
|
||||||
x.connection.state &= ~ConnectionState.CAN_READ
|
x.connection.state &= ~ConnectionState.CAN_READ
|
||||||
@ -227,13 +227,13 @@ class Playbook:
|
|||||||
)
|
)
|
||||||
if need_to_emulate_log:
|
if need_to_emulate_log:
|
||||||
self.expected.insert(pos, cmd)
|
self.expected.insert(pos, cmd)
|
||||||
elif isinstance(cmd, commands.Hook) and not self.hooks:
|
elif isinstance(cmd, commands.StartHook) and not self.hooks:
|
||||||
need_to_emulate_hook = (
|
need_to_emulate_hook = (
|
||||||
not self.hooks
|
not self.hooks
|
||||||
and (
|
and (
|
||||||
pos >= len(self.expected) or
|
pos >= len(self.expected) or
|
||||||
(not (
|
(not (
|
||||||
isinstance(self.expected[pos], commands.Hook)
|
isinstance(self.expected[pos], commands.StartHook)
|
||||||
and self.expected[pos].name == cmd.name
|
and self.expected[pos].name == cmd.name
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
@ -243,7 +243,7 @@ class Playbook:
|
|||||||
if cmd.blocking:
|
if cmd.blocking:
|
||||||
# the current event may still have yielded more events, so we need to insert
|
# the current event may still have yielded more events, so we need to insert
|
||||||
# the reply *after* those additional events.
|
# the reply *after* those additional events.
|
||||||
hook_replies.append(events.HookReply(cmd))
|
hook_replies.append(events.HookCompleted(cmd))
|
||||||
self.expected = self.expected[:pos + 1] + hook_replies + self.expected[pos + 1:]
|
self.expected = self.expected[:pos + 1] + hook_replies + self.expected[pos + 1:]
|
||||||
|
|
||||||
eq(self.expected[i:], self.actual[i:]) # compare now already to set placeholders
|
eq(self.expected[i:], self.actual[i:]) # compare now already to set placeholders
|
||||||
@ -288,7 +288,7 @@ class reply(events.Event):
|
|||||||
self.to = to
|
self.to = to
|
||||||
self.side_effect = side_effect
|
self.side_effect = side_effect
|
||||||
|
|
||||||
def playbook_eval(self, playbook: Playbook) -> events.CommandReply:
|
def playbook_eval(self, playbook: Playbook) -> events.CommandCompleted:
|
||||||
if isinstance(self.to, int):
|
if isinstance(self.to, int):
|
||||||
expected = playbook.expected[:playbook.expected.index(self)]
|
expected = playbook.expected[:playbook.expected.index(self)]
|
||||||
assert abs(self.to) < len(expected)
|
assert abs(self.to) < len(expected)
|
||||||
@ -305,9 +305,9 @@ class reply(events.Event):
|
|||||||
raise AssertionError(f"Expected command {self.to} did not occur.")
|
raise AssertionError(f"Expected command {self.to} did not occur.")
|
||||||
|
|
||||||
assert isinstance(self.to, commands.Command)
|
assert isinstance(self.to, commands.Command)
|
||||||
if isinstance(self.to, commands.Hook):
|
if isinstance(self.to, commands.StartHook):
|
||||||
self.side_effect(*self.to.args())
|
self.side_effect(*self.to.args())
|
||||||
reply_cls = events.HookReply
|
reply_cls = events.HookCompleted
|
||||||
else:
|
else:
|
||||||
self.side_effect(self.to)
|
self.side_effect(self.to)
|
||||||
reply_cls = command_reply_subclasses[type(self.to)]
|
reply_cls = command_reply_subclasses[type(self.to)]
|
||||||
|
@ -3,7 +3,7 @@ from unittest import mock
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy import addonmanager
|
from mitmproxy import addonmanager
|
||||||
from mitmproxy import addons, events
|
from mitmproxy import addons, event_hooks
|
||||||
from mitmproxy import command
|
from mitmproxy import command
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import master
|
from mitmproxy import master
|
||||||
@ -66,11 +66,11 @@ def test_halt():
|
|||||||
a.add(end)
|
a.add(end)
|
||||||
|
|
||||||
assert not end.running_called
|
assert not end.running_called
|
||||||
a.trigger(events.RunningEvent())
|
a.trigger(event_hooks.RunningEventHook())
|
||||||
assert not end.running_called
|
assert not end.running_called
|
||||||
|
|
||||||
a.remove(halt)
|
a.remove(halt)
|
||||||
a.trigger(events.RunningEvent())
|
a.trigger(event_hooks.RunningEventHook())
|
||||||
assert end.running_called
|
assert end.running_called
|
||||||
|
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ async def test_simple():
|
|||||||
await tctx.master.await_log("AssertionError")
|
await tctx.master.await_log("AssertionError")
|
||||||
|
|
||||||
f = tflow.tflow()
|
f = tflow.tflow()
|
||||||
a.trigger(events.RunningEvent())
|
a.trigger(event_hooks.RunningEventHook())
|
||||||
a.trigger(HttpResponseHook(f))
|
a.trigger(HttpResponseHook(f))
|
||||||
await tctx.master.await_log("not callable")
|
await tctx.master.await_log("not callable")
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ async def test_simple():
|
|||||||
|
|
||||||
ta = TAddon("one")
|
ta = TAddon("one")
|
||||||
a.add(ta)
|
a.add(ta)
|
||||||
a.trigger(events.RunningEvent())
|
a.trigger(event_hooks.RunningEventHook())
|
||||||
assert ta.running_called
|
assert ta.running_called
|
||||||
|
|
||||||
assert ta in a
|
assert ta in a
|
||||||
@ -187,7 +187,7 @@ def test_nesting():
|
|||||||
assert a.get("three")
|
assert a.get("three")
|
||||||
assert a.get("four")
|
assert a.get("four")
|
||||||
|
|
||||||
a.trigger(events.RunningEvent())
|
a.trigger(event_hooks.RunningEventHook())
|
||||||
assert a.get("one").running_called
|
assert a.get("one").running_called
|
||||||
assert a.get("two").running_called
|
assert a.get("two").running_called
|
||||||
assert a.get("three").running_called
|
assert a.get("three").running_called
|
||||||
|
@ -2,35 +2,35 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy import events
|
from mitmproxy import event_hooks
|
||||||
|
|
||||||
|
|
||||||
def test_event():
|
def test_event():
|
||||||
with pytest.raises(TypeError, match="may not be instantiated directly"):
|
with pytest.raises(TypeError, match="may not be instantiated directly"):
|
||||||
events.MitmproxyEvent()
|
event_hooks.EventHook()
|
||||||
|
|
||||||
class NoDataClass(events.MitmproxyEvent):
|
class NoDataClass(event_hooks.EventHook):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
with pytest.raises(TypeError, match="not a dataclass"):
|
with pytest.raises(TypeError, match="not a dataclass"):
|
||||||
NoDataClass()
|
NoDataClass()
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FooEvent(events.MitmproxyEvent):
|
class FooEventHook(event_hooks.EventHook):
|
||||||
data: bytes
|
data: bytes
|
||||||
|
|
||||||
e = FooEvent(b"foo")
|
e = FooEventHook(b"foo")
|
||||||
assert repr(e)
|
assert repr(e)
|
||||||
assert e.args() == [b"foo"]
|
assert e.args() == [b"foo"]
|
||||||
assert FooEvent in events.all_events.values()
|
assert FooEventHook in event_hooks.all_events.values()
|
||||||
|
|
||||||
with pytest.raises(RuntimeError, match="Two conflicting event classes"):
|
with pytest.raises(RuntimeError, match="Two conflicting event classes"):
|
||||||
@dataclass
|
@dataclass
|
||||||
class FooEvent2(events.MitmproxyEvent):
|
class FooEventHook2(event_hooks.EventHook):
|
||||||
name = "foo"
|
name = "foo"
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AnotherABC(events.MitmproxyEvent):
|
class AnotherABC(event_hooks.EventHook):
|
||||||
name = ""
|
name = ""
|
||||||
|
|
||||||
assert AnotherABC not in events.all_events.values()
|
assert AnotherABC not in event_hooks.all_events.values()
|
@ -2,7 +2,7 @@ import urwid
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from mitmproxy import options, events
|
from mitmproxy import options, event_hooks
|
||||||
from mitmproxy.tools import console
|
from mitmproxy.tools import console
|
||||||
|
|
||||||
from ... import tservers
|
from ... import tservers
|
||||||
@ -13,7 +13,7 @@ class TestMaster(tservers.MasterTest):
|
|||||||
def mkmaster(self, **opts):
|
def mkmaster(self, **opts):
|
||||||
o = options.Options(**opts)
|
o = options.Options(**opts)
|
||||||
m = console.master.ConsoleMaster(o)
|
m = console.master.ConsoleMaster(o)
|
||||||
m.addons.trigger(events.ConfigureEvent(o.keys()))
|
m.addons.trigger(event_hooks.ConfigureEventHook(o.keys()))
|
||||||
return m
|
return m
|
||||||
|
|
||||||
async def test_basic(self):
|
async def test_basic(self):
|
||||||
|
@ -18,7 +18,7 @@ class TestDumpMaster:
|
|||||||
m = self.mkmaster()
|
m = self.mkmaster()
|
||||||
ent = log.LogEntry("foo", "error")
|
ent = log.LogEntry("foo", "error")
|
||||||
ent.reply = controller.DummyReply()
|
ent.reply = controller.DummyReply()
|
||||||
m.addons.trigger(log.AddLogEvent(ent))
|
m.addons.trigger(log.AddLogEventHook(ent))
|
||||||
assert m.errorcheck.has_errored
|
assert m.errorcheck.has_errored
|
||||||
|
|
||||||
@pytest.mark.parametrize("termlog", [False, True])
|
@pytest.mark.parametrize("termlog", [False, True])
|
||||||
|
Loading…
Reference in New Issue
Block a user