mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-21 22:58:24 +00:00
restructure examples
- restructure examples (fix #4031) - remove example dependencies from setup.py, we do not need special dependencies for our supported addons. - unify how we generate docs from code - improve example docs
This commit is contained in:
parent
67372d26ae
commit
08895e9ba6
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
@ -3,4 +3,3 @@ src/public/
|
||||
node_modules/
|
||||
public/
|
||||
src/resources/_gen/
|
||||
src/content/addons-examples.md
|
||||
|
@ -15,9 +15,5 @@ for script in scripts/* ; do
|
||||
"${script}" > "${output}"
|
||||
done
|
||||
|
||||
output="src/content/addons-examples.md"
|
||||
echo "Generating examples content page into ${output} ..."
|
||||
./render_examples.py > "${output}"
|
||||
|
||||
cd src
|
||||
hugo
|
||||
|
@ -1,3 +1,7 @@
|
||||
scripts/*.py {
|
||||
prep: build.sh
|
||||
}
|
||||
|
||||
{
|
||||
daemon: cd src; hugo server -D
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
print("""
|
||||
---
|
||||
title: "Examples"
|
||||
menu:
|
||||
addons:
|
||||
weight: 6
|
||||
---
|
||||
|
||||
# Examples of Addons and Scripts
|
||||
|
||||
The most recent set of examples is also available [on our GitHub project](https://github.com/mitmproxy/mitmproxy/tree/master/examples).
|
||||
|
||||
""")
|
||||
|
||||
base = os.path.dirname(os.path.realpath(__file__))
|
||||
examples_path = os.path.join(base, 'src/examples/')
|
||||
pathlist = Path(examples_path).glob('**/*.py')
|
||||
|
||||
examples = [os.path.relpath(str(p), examples_path) for p in sorted(pathlist)]
|
||||
examples = [p for p in examples if not os.path.basename(p) == '__init__.py']
|
||||
examples = [p for p in examples if not os.path.basename(p).startswith('test_')]
|
||||
|
||||
current_dir = None
|
||||
current_level = 2
|
||||
for ex in examples:
|
||||
if os.path.dirname(ex) != current_dir:
|
||||
current_dir = os.path.dirname(ex)
|
||||
sanitized = current_dir.replace('/', '').replace('.', '')
|
||||
print(" * [Examples: {}]({{{{< relref \"addons-examples#{}\">}}}})".format(current_dir, sanitized))
|
||||
|
||||
sanitized = ex.replace('/', '').replace('.', '')
|
||||
print(" * [{}]({{{{< relref \"addons-examples#example-{}\">}}}})".format(os.path.basename(ex), sanitized))
|
||||
|
||||
current_dir = None
|
||||
current_level = 2
|
||||
for ex in examples:
|
||||
if os.path.dirname(ex) != current_dir:
|
||||
current_dir = os.path.dirname(ex)
|
||||
print("#" * current_level, current_dir)
|
||||
|
||||
print(textwrap.dedent("""
|
||||
{} Example: {}
|
||||
{{{{< example src="{}" lang="py" >}}}}
|
||||
""".format("#" * (current_level + 1), ex, "examples/" + ex)))
|
48
docs/scripts/examples.py
Executable file
48
docs/scripts/examples.py
Executable file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
here = Path(__file__).absolute().parent
|
||||
example_dir = here / ".." / "src" / "examples" / "addons"
|
||||
examples = example_dir.glob('*.py')
|
||||
|
||||
overview = []
|
||||
listings = []
|
||||
|
||||
for example in examples:
|
||||
code = example.read_text()
|
||||
slug = str(example.with_suffix("").relative_to(example_dir))
|
||||
slug = re.sub(r"[^a-zA-Z]", "-", slug)
|
||||
match = re.search(r'''
|
||||
^
|
||||
(?:[#][^\n]*\n)? # there might be a shebang
|
||||
"""
|
||||
\s*
|
||||
(.+?)
|
||||
\s*
|
||||
(?:\n\n|""") # stop on empty line or end of comment
|
||||
''', code, re.VERBOSE)
|
||||
if match:
|
||||
comment = " — " + match.group(1)
|
||||
else:
|
||||
comment = ""
|
||||
overview.append(
|
||||
f" * [{example.name}](#{slug}){comment}"
|
||||
)
|
||||
listings.append(f"""
|
||||
<h2 id="{slug}">Example: {example.name}</h2>
|
||||
|
||||
```python
|
||||
{code}
|
||||
```
|
||||
""")
|
||||
print("\n".join(overview))
|
||||
print("""
|
||||
### Community Examples
|
||||
|
||||
Additional examples contributed by the mitmproxy community can be found
|
||||
[on GitHub](https://github.com/mitmproxy/mitmproxy/tree/master/examples/contrib).
|
||||
|
||||
""")
|
||||
print("\n".join(listings))
|
@ -13,7 +13,7 @@ receive `Flow` objects as arguments - by modifying these objects, addons can
|
||||
change traffic on the fly. For instance, here is an addon that adds a response
|
||||
header with a count of the number of responses seen:
|
||||
|
||||
{{< example src="examples/addons/addheader.py" lang="py" >}}
|
||||
{{< example src="examples/addons/http-add-header.py" lang="py" >}}
|
||||
|
||||
|
||||
## Supported Events
|
||||
|
11
docs/src/content/addons-examples.md
Normal file
11
docs/src/content/addons-examples.md
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
---
|
||||
title: "Example Addons"
|
||||
menu:
|
||||
addons:
|
||||
weight: 6
|
||||
---
|
||||
|
||||
# Example Addons
|
||||
|
||||
{{< readfile file="/generated/examples.html" markdown="true" >}}
|
@ -13,13 +13,13 @@ module as a whole to be treated as an addon object. This lets us place event
|
||||
handler functions in the module scope. For instance, here is a complete script
|
||||
that adds a header to every request.
|
||||
|
||||
{{< example src="examples/addons/scripting-headers.py" lang="py" >}}
|
||||
{{< example src="examples/addons/scripting-minimal-example.py" lang="py" >}}
|
||||
|
||||
|
||||
Here's another example that intercepts requests to a particular URL and sends
|
||||
an arbitrary response instead:
|
||||
|
||||
{{< example src="examples/simple/send_reply_from_proxy.py" lang="py" >}}
|
||||
{{< example src="examples/addons/http-reply-from-proxy.py" lang="py" >}}
|
||||
|
||||
All events around the HTTP protocol [can be found here]({{< relref "addons-events#http-events">}}).
|
||||
|
||||
@ -31,7 +31,7 @@ scripting.
|
||||
|
||||
The WebSocket protocol initially looks like a regular HTTP request, before the client and server agree to upgrade the connection to WebSocket. All scripting events for initial HTTP handshake, and also the dedicated WebSocket events [can be found here]({{< relref "addons-events#websocket-events">}}).
|
||||
|
||||
{{< example src="examples/simple/websocket_messages.py" lang="py" >}}
|
||||
{{< example src="examples/addons/websocket-simple.py" lang="py" >}}
|
||||
|
||||
For WebSocket-related objects please look at the [websocket][] module to find
|
||||
all attributes that you can use when scripting.
|
||||
@ -43,7 +43,7 @@ all attributes that you can use when scripting.
|
||||
|
||||
All events around the TCP protocol [can be found here]({{< relref "addons-events#tcp-events">}}).
|
||||
|
||||
{{< example src="examples/complex/tcp_message.py" lang="py" >}}
|
||||
{{< example src="examples/addons/tcp-simple.py" lang="py" >}}
|
||||
|
||||
For WebSocket-related objects please look at the [tcp][] module to find
|
||||
all attributes that you can use when scripting.
|
||||
|
@ -189,7 +189,7 @@ You can also use a script to customise exactly which requests or responses are
|
||||
streamed. Requests/Responses that should be tagged for streaming by setting
|
||||
their ``.stream`` attribute to ``True``:
|
||||
|
||||
{{< example src="examples/complex/stream.py" lang="py" >}}
|
||||
{{< example src="examples/addons/http-stream-simple.py" lang="py" >}}
|
||||
|
||||
|
||||
### Websockets
|
||||
|
@ -1,15 +1,9 @@
|
||||
# Mitmproxy Scripting API
|
||||
# Mitmproxy Examples
|
||||
|
||||
Mitmproxy has a powerful scripting API that allows you to control almost any aspect of traffic being
|
||||
proxied. In fact, much of mitmproxy’s own core functionality is implemented using the exact same API
|
||||
exposed to scripters (see [mitmproxy/addons](../mitmproxy/addons)).
|
||||
(see [mitmproxy/addons](../mitmproxy/addons)).
|
||||
|
||||
This directory contains some examples of the scripting API. We recommend to start with the
|
||||
ones in [simple/](./simple).
|
||||
|
||||
| :warning: | If you are browsing this on GitHub, make sure to select the git tag matching your mitmproxy version. |
|
||||
|------------|------------------------------------------------------------------------------------------------------|
|
||||
|
||||
|
||||
Some inline scripts may require additional dependencies, which can be installed using
|
||||
`pip install mitmproxy[examples]`.
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
Basic skeleton of a mitmproxy addon.
|
||||
|
||||
Run as follows: mitmproxy -s anatomy.py
|
||||
"""
|
||||
from mitmproxy import ctx
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Handle flows as command arguments."""
|
||||
import typing
|
||||
|
||||
from mitmproxy import command
|
||||
@ -6,9 +7,6 @@ from mitmproxy import flow
|
||||
|
||||
|
||||
class MyAddon:
|
||||
def __init__(self):
|
||||
self.num = 0
|
||||
|
||||
@command.command("myaddon.addheader")
|
||||
def addheader(self, flows: typing.Sequence[flow.Flow]) -> None:
|
||||
for f in flows:
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Handle file paths as command arguments."""
|
||||
import typing
|
||||
|
||||
from mitmproxy import command
|
||||
@ -7,9 +8,6 @@ from mitmproxy import types
|
||||
|
||||
|
||||
class MyAddon:
|
||||
def __init__(self):
|
||||
self.num = 0
|
||||
|
||||
@command.command("myaddon.histogram")
|
||||
def histogram(
|
||||
self,
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Add a custom command to mitmproxy's command prompt."""
|
||||
from mitmproxy import command
|
||||
from mitmproxy import ctx
|
||||
|
||||
@ -9,7 +10,7 @@ class MyAddon:
|
||||
@command.command("myaddon.inc")
|
||||
def inc(self) -> None:
|
||||
self.num += 1
|
||||
ctx.log.info("num = %s" % self.num)
|
||||
ctx.log.info(f"num = {self.num}")
|
||||
|
||||
|
||||
addons = [
|
||||
|
@ -1,5 +1,8 @@
|
||||
"""
|
||||
This example shows how one can add a custom contentview to mitmproxy.
|
||||
Add a custom message body pretty-printer for use inside mitmproxy.
|
||||
|
||||
This example shows how one can add a custom contentview to mitmproxy,
|
||||
which is used to pretty-print HTTP bodies for example.
|
||||
The content view API is explained in the mitmproxy.contentviews module.
|
||||
"""
|
||||
from mitmproxy import contentviews
|
@ -1,3 +1,4 @@
|
||||
"""Take incoming HTTP requests and replay them with modified parameters."""
|
||||
from mitmproxy import ctx
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""HTTP-specific events."""
|
||||
import mitmproxy.http
|
||||
|
||||
|
||||
class Events:
|
||||
# HTTP lifecycle
|
||||
def http_connect(self, flow: mitmproxy.http.HTTPFlow):
|
||||
"""
|
||||
An HTTP CONNECT request was received. Setting a non 2xx response on
|
||||
|
@ -1,8 +1,8 @@
|
||||
"""TCP-specific events."""
|
||||
import mitmproxy.tcp
|
||||
|
||||
|
||||
class Events:
|
||||
# TCP lifecycle
|
||||
def tcp_start(self, flow: mitmproxy.tcp.TCPFlow):
|
||||
"""
|
||||
A TCP connection has started.
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""WebSocket-specific events."""
|
||||
import mitmproxy.http
|
||||
import mitmproxy.websocket
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
"""Generic event hooks."""
|
||||
import typing
|
||||
|
||||
import mitmproxy.addonmanager
|
||||
import mitmproxy.connections
|
||||
import mitmproxy.http
|
||||
import mitmproxy.log
|
||||
import mitmproxy.tcp
|
||||
import mitmproxy.websocket
|
||||
import mitmproxy.proxy.protocol
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
This script demonstrates how to use mitmproxy's filter pattern in scripts.
|
||||
Use mitmproxy's filter pattern in scripts.
|
||||
"""
|
||||
from mitmproxy import flowfilter
|
||||
from mitmproxy import ctx, http
|
@ -1,3 +1,5 @@
|
||||
"""Add an HTTP header to each response."""
|
||||
|
||||
|
||||
class AddHeader:
|
||||
def __init__(self):
|
@ -1,3 +1,4 @@
|
||||
"""Modify an HTTP form submission."""
|
||||
from mitmproxy import http
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
"""Modify HTTP query parameters."""
|
||||
from mitmproxy import http
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
"""
|
||||
This example shows two ways to redirect flows to another server.
|
||||
"""
|
||||
"""Redirect HTTP requests to another server."""
|
||||
from mitmproxy import http
|
||||
|
||||
|
@ -1,14 +1,8 @@
|
||||
"""
|
||||
This example shows how to send a reply from the proxy immediately
|
||||
without sending any data to the remote server.
|
||||
"""
|
||||
"""Send a reply from the proxy without sending any data to the remote server."""
|
||||
from mitmproxy import http
|
||||
|
||||
|
||||
def request(flow: http.HTTPFlow) -> None:
|
||||
# pretty_url takes the "Host" header of the request into account, which
|
||||
# is useful in transparent mode where we usually only have the IP otherwise.
|
||||
|
||||
if flow.request.pretty_url == "http://example.com/path":
|
||||
flow.response = http.HTTPResponse.make(
|
||||
200, # (optional) status code
|
@ -1,7 +1,8 @@
|
||||
"""
|
||||
This inline script modifies a streamed response.
|
||||
If you do not need streaming, see the modify_response_body example.
|
||||
Be aware that content replacement isn't trivial:
|
||||
Modify a streamed response.
|
||||
|
||||
Generally speaking, we recommend *not* to stream messages you need to modify.
|
||||
Modifying streamed responses is tricky and brittle:
|
||||
- If the transfer encoding isn't chunked, you cannot simply change the content length.
|
||||
- If you want to replace all occurrences of "foobar", make sure to catch the cases
|
||||
where one chunk ends with [...]foo" and the next starts with "bar[...].
|
@ -1,3 +1,11 @@
|
||||
"""
|
||||
Select which responses should be streamed.
|
||||
|
||||
Enable response streaming for all HTTP flows.
|
||||
This is equivalent to passing `--set stream_large_bodies=1` to mitmproxy.
|
||||
"""
|
||||
|
||||
|
||||
def responseheaders(flow):
|
||||
"""
|
||||
Enables streaming for all responses.
|
@ -1,5 +1,7 @@
|
||||
"""
|
||||
This script reflects all content passing through the proxy.
|
||||
Mirror all web pages.
|
||||
|
||||
Useful if you are living down under.
|
||||
"""
|
||||
from mitmproxy import http
|
||||
|
@ -1,13 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Simple script showing how to read a mitmproxy dump file
|
||||
#
|
||||
"""
|
||||
Read a mitmproxy dump file.
|
||||
"""
|
||||
from mitmproxy import io
|
||||
from mitmproxy.exceptions import FlowReadException
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
|
||||
with open(sys.argv[1], "rb") as logfile:
|
||||
freader = io.FlowReader(logfile)
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
@ -1,4 +1,6 @@
|
||||
"""
|
||||
Generate a mitmproxy dump file.
|
||||
|
||||
This script demonstrates how to generate a mitmproxy dump file,
|
||||
as it would also be generated by passing `-w` to mitmproxy.
|
||||
In contrast to `-w`, this gives you full control over which
|
@ -1,3 +1,4 @@
|
||||
"""Post messages to mitmproxy's event log."""
|
||||
from mitmproxy import ctx
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
"""
|
||||
Make events hooks non-blocking.
|
||||
|
||||
When event hooks are decorated with @concurrent, they will be run in their own thread, freeing the main event loop.
|
||||
Please note that this generally opens the door to race conditions and decreases performance if not required.
|
||||
"""
|
||||
import time
|
||||
|
||||
from mitmproxy.script import concurrent
|
@ -1,3 +1,4 @@
|
||||
"""React to configuration changes."""
|
||||
import typing
|
||||
|
||||
from mitmproxy import ctx
|
||||
|
@ -1,3 +1,10 @@
|
||||
"""
|
||||
Add a new mitmproxy option.
|
||||
|
||||
Usage:
|
||||
|
||||
mitmproxy -s options-simple.py --set addheader true
|
||||
"""
|
||||
from mitmproxy import ctx
|
||||
|
||||
|
||||
|
24
examples/addons/tcp-simple.py
Normal file
24
examples/addons/tcp-simple.py
Normal file
@ -0,0 +1,24 @@
|
||||
"""
|
||||
Process individual messages from a TCP connection.
|
||||
|
||||
This script replaces full occurences of "foo" with "bar" and prints various details for each message.
|
||||
Please note that TCP is stream-based and *not* message-based. mitmproxy splits stream contents into "messages"
|
||||
as they are received by socket.recv(). This is pretty arbitrary and should not be relied on.
|
||||
However, it is sometimes good enough as a quick hack.
|
||||
|
||||
Example Invocation:
|
||||
|
||||
mitmdump --rawtcp --tcp-hosts ".*" -s examples/tcp-simple.py
|
||||
"""
|
||||
from mitmproxy.utils import strutils
|
||||
from mitmproxy import ctx
|
||||
from mitmproxy import tcp
|
||||
|
||||
|
||||
def tcp_message(flow: tcp.TCPFlow):
|
||||
message = flow.messages[-1]
|
||||
message.content = message.content.replace(b"foo", b"bar")
|
||||
|
||||
ctx.log.info(
|
||||
f"tcp_message[from_client={message.from_client}), content={strutils.bytes_to_escaped_str(message.content)}]"
|
||||
)
|
@ -1,4 +1,6 @@
|
||||
"""
|
||||
Inject a WebSocket message into a running connection.
|
||||
|
||||
This example shows how to inject a WebSocket message to the client.
|
||||
Every new WebSocket connection will trigger a new asyncio task that
|
||||
periodically injects a new message to the client.
|
||||
@ -8,12 +10,11 @@ import mitmproxy.websocket
|
||||
|
||||
|
||||
class InjectWebSocketMessage:
|
||||
|
||||
async def inject(self, flow: mitmproxy.websocket.WebSocketFlow):
|
||||
i = 0
|
||||
while not flow.ended and not flow.error:
|
||||
await asyncio.sleep(5)
|
||||
flow.inject_message(flow.client_conn, 'This is the #{} injected message!'.format(i))
|
||||
flow.inject_message(flow.client_conn, f'This is the #{i} injected message!')
|
||||
i += 1
|
||||
|
||||
def websocket_start(self, flow):
|
@ -1,3 +1,4 @@
|
||||
"""Process individual messages from a WebSocket connection."""
|
||||
import re
|
||||
from mitmproxy import ctx
|
||||
|
@ -1,4 +1,6 @@
|
||||
"""
|
||||
Host a WSGI app in mitmproxy.
|
||||
|
||||
This example shows how to graft a WSGI app onto mitmproxy. In this
|
||||
instance, we're using the Flask framework (http://flask.pocoo.org/) to expose
|
||||
a single simplest-possible page.
|
@ -1,19 +0,0 @@
|
||||
## Complex Examples
|
||||
|
||||
| Filename | Description |
|
||||
|:-------------------------|:----------------------------------------------------------------------------------------------|
|
||||
| block_dns_over_https.py | Use mitmproxy to block DNS over HTTPS (DoH) queries |
|
||||
| change_upstream_proxy.py | Dynamically change the upstream proxy. |
|
||||
| dns_spoofing.py | Use mitmproxy in a DNS spoofing scenario. |
|
||||
| dup_and_replay.py | Duplicates each request, changes it, and then replays the modified request. |
|
||||
| full_transparency_shim.c | Setuid wrapper that can be used to run mitmproxy in full transparency mode, as a normal user. |
|
||||
| har_dump.py | Dump flows as HAR files. |
|
||||
| mitmproxywrapper.py | Bracket mitmproxy run with proxy enable/disable on OS X |
|
||||
| nonblocking.py | Demonstrate parallel processing with a blocking script |
|
||||
| remote_debug.py | This script enables remote debugging of the mitmproxy _UI_ with PyCharm. |
|
||||
| sslstrip.py | sslstrip-like functionality implemented with mitmproxy |
|
||||
| stream.py | Enable streaming for all responses. |
|
||||
| stream_modify.py | Modify a streamed response body. |
|
||||
| tcp_message.py | Modify a raw TCP connection |
|
||||
| tls_passthrough.py | Use conditional TLS interception based on a user-defined strategy. |
|
||||
| xss_scanner.py | Scan all visited webpages. |
|
@ -1,27 +0,0 @@
|
||||
"""
|
||||
tcp_message Inline Script Hook API Demonstration
|
||||
------------------------------------------------
|
||||
|
||||
* modifies packets containing "foo" to "bar"
|
||||
* prints various details for each packet.
|
||||
|
||||
example cmdline invocation:
|
||||
mitmdump --rawtcp --tcp-host ".*" -s examples/complex/tcp_message.py
|
||||
"""
|
||||
from mitmproxy.utils import strutils
|
||||
from mitmproxy import ctx
|
||||
from mitmproxy import tcp
|
||||
|
||||
|
||||
def tcp_message(flow: tcp.TCPFlow):
|
||||
message = flow.messages[-1]
|
||||
old_content = message.content
|
||||
message.content = old_content.replace(b"foo", b"bar")
|
||||
|
||||
ctx.log.info(
|
||||
"[tcp_message{}] from {} to {}:\n{}".format(
|
||||
" (modified)" if message.content != old_content else "",
|
||||
"client" if message.from_client else "server",
|
||||
"server" if message.from_client else "client",
|
||||
strutils.bytes_to_escaped_str(message.content))
|
||||
)
|
4
examples/contrib/README.md
Normal file
4
examples/contrib/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Community-Contributed Examples
|
||||
|
||||
Examples in this directory are contributed by the mitmproxy community.
|
||||
We do _not_ maintain them, but we welcome PRs that add/fix/modernize/clean up examples.
|
@ -1,5 +1,5 @@
|
||||
"""
|
||||
This script enables remote debugging of the mitmproxy *UI* with PyCharm.
|
||||
This script enables remote debugging of the mitmproxy console *UI* with PyCharm.
|
||||
For general debugging purposes, it is easier to just debug mitmdump within PyCharm.
|
||||
|
||||
Usage:
|
0
examples/complex/xss_scanner.py → examples/contrib/xss_scanner.py
Executable file → Normal file
0
examples/complex/xss_scanner.py → examples/contrib/xss_scanner.py
Executable file → Normal file
@ -1,19 +0,0 @@
|
||||
## Simple Examples
|
||||
|
||||
| Filename | Description |
|
||||
| :----------------------------- | :--------------------------------------------------------------------------- |
|
||||
| add_header.py | Simple script that just adds a header to every request. |
|
||||
| custom_contentview.py | Add a custom content view to the mitmproxy UI. |
|
||||
| custom_option.py | Add arguments to a script. |
|
||||
| filter_flows.py | This script demonstrates how to use mitmproxy's filter pattern in scripts. |
|
||||
| io_read_dumpfile.py | Read a dumpfile generated by mitmproxy. |
|
||||
| io_write_dumpfile.py | Only write selected flows into a mitmproxy dumpfile. |
|
||||
| link_expander.py | Discover relative links in HTML traffic and replace them with absolute paths |
|
||||
| log_events.py | Use mitmproxy's logging API. |
|
||||
| modify_body_inject_iframe.py | Inject configurable iframe into pages. |
|
||||
| modify_form.py | Modify HTTP form submissions. |
|
||||
| modify_querystring.py | Modify HTTP query strings. |
|
||||
| redirect_requests.py | Redirect a request to a different server. |
|
||||
| send_reply_from_proxy.py | Send a HTTP response directly from the proxy. |
|
||||
| internet_in_mirror.py | Turn all images upside down. |
|
||||
| wsgi_flask_app.py | Embed a WSGI app into mitmproxy. |
|
@ -1,5 +0,0 @@
|
||||
from mitmproxy import http
|
||||
|
||||
|
||||
def response(flow: http.HTTPFlow) -> None:
|
||||
flow.response.headers["newheader"] = "foo"
|
@ -1,9 +0,0 @@
|
||||
from mitmproxy import http
|
||||
|
||||
|
||||
class AddHeader:
|
||||
def response(self, flow: http.HTTPFlow) -> None:
|
||||
flow.response.headers["newheader"] = "foo"
|
||||
|
||||
|
||||
addons = [AddHeader()]
|
@ -1,21 +0,0 @@
|
||||
"""
|
||||
This example shows how addons can register custom options
|
||||
that can be configured at startup or during execution
|
||||
from the options dialog within mitmproxy.
|
||||
|
||||
Example:
|
||||
|
||||
$ mitmproxy --set custom=true
|
||||
$ mitmproxy --set custom # shorthand for boolean options
|
||||
"""
|
||||
from mitmproxy import ctx
|
||||
|
||||
|
||||
def load(l):
|
||||
ctx.log.info("Registering option 'custom'")
|
||||
l.add_option("custom", bool, False, "A custom option")
|
||||
|
||||
|
||||
def configure(updated):
|
||||
if "custom" in updated:
|
||||
ctx.log.info("custom option value: %s" % ctx.options.custom)
|
@ -1 +1 @@
|
||||
-e .[dev,examples]
|
||||
-e .[dev]
|
||||
|
3
setup.py
3
setup.py
@ -102,9 +102,6 @@ setup(
|
||||
"pytest>=5.1.3,<6",
|
||||
"requests>=2.9.1,<3",
|
||||
"tox>=3.5,<3.15",
|
||||
],
|
||||
'examples': [
|
||||
"beautifulsoup4>=4.4.1,<4.9"
|
||||
]
|
||||
}
|
||||
)
|
||||
|
@ -10,35 +10,21 @@ from ..mitmproxy import tservers
|
||||
class TestScripts(tservers.MasterTest):
|
||||
def test_add_header(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
a = tctx.script(tdata.path("../examples/simple/add_header.py"))
|
||||
f = tflow.tflow(resp=tutils.tresp())
|
||||
a.response(f)
|
||||
assert f.response.headers["newheader"] == "foo"
|
||||
a = tctx.script(tdata.path("../examples/addons/scripting-minimal-example.py"))
|
||||
f = tflow.tflow()
|
||||
a.request(f)
|
||||
assert f.request.headers["myheader"] == "value"
|
||||
|
||||
def test_custom_contentviews(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
tctx.script(tdata.path("../examples/simple/custom_contentview.py"))
|
||||
tctx.script(tdata.path("../examples/addons/contentview.py"))
|
||||
swapcase = contentviews.get("swapcase")
|
||||
_, fmt = swapcase(b"<html>Test!</html>")
|
||||
assert any(b'tEST!' in val[0][1] for val in fmt)
|
||||
|
||||
def test_iframe_injector(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
sc = tctx.script(tdata.path("../examples/simple/modify_body_inject_iframe.py"))
|
||||
tctx.configure(
|
||||
sc,
|
||||
iframe = "http://example.org/evil_iframe"
|
||||
)
|
||||
f = tflow.tflow(
|
||||
resp=tutils.tresp(content=b"<html><body>mitmproxy</body></html>")
|
||||
)
|
||||
tctx.master.addons.invoke_addon(sc, "response", f)
|
||||
content = f.response.content
|
||||
assert b'iframe' in content and b'evil_iframe' in content
|
||||
|
||||
def test_modify_form(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
sc = tctx.script(tdata.path("../examples/simple/modify_form.py"))
|
||||
sc = tctx.script(tdata.path("../examples/addons/http-modify-form.py"))
|
||||
|
||||
form_header = Headers(content_type="application/x-www-form-urlencoded")
|
||||
f = tflow.tflow(req=tutils.treq(headers=form_header))
|
||||
@ -52,7 +38,7 @@ class TestScripts(tservers.MasterTest):
|
||||
|
||||
def test_modify_querystring(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
sc = tctx.script(tdata.path("../examples/simple/modify_querystring.py"))
|
||||
sc = tctx.script(tdata.path("../examples/addons/http-modify-query-string.py"))
|
||||
f = tflow.tflow(req=tutils.treq(path="/search?q=term"))
|
||||
|
||||
sc.request(f)
|
||||
@ -64,36 +50,14 @@ class TestScripts(tservers.MasterTest):
|
||||
|
||||
def test_redirect_requests(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
sc = tctx.script(tdata.path("../examples/simple/redirect_requests.py"))
|
||||
sc = tctx.script(tdata.path("../examples/addons/http-redirect-requests.py"))
|
||||
f = tflow.tflow(req=tutils.treq(host="example.org"))
|
||||
sc.request(f)
|
||||
assert f.request.host == "mitmproxy.org"
|
||||
|
||||
def test_send_reply_from_proxy(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
sc = tctx.script(tdata.path("../examples/simple/send_reply_from_proxy.py"))
|
||||
sc = tctx.script(tdata.path("../examples/addons/http-reply-from-proxy.py"))
|
||||
f = tflow.tflow(req=tutils.treq(host="example.com", port=80))
|
||||
sc.request(f)
|
||||
assert f.response.content == b"Hello World"
|
||||
|
||||
def test_dns_spoofing(self, tdata):
|
||||
with taddons.context() as tctx:
|
||||
sc = tctx.script(tdata.path("../examples/complex/dns_spoofing.py"))
|
||||
|
||||
original_host = "example.com"
|
||||
|
||||
host_header = Headers(host=original_host)
|
||||
f = tflow.tflow(req=tutils.treq(headers=host_header, port=80))
|
||||
|
||||
tctx.master.addons.invoke_addon(sc, "requestheaders", f)
|
||||
|
||||
# Rewrite by reverse proxy mode
|
||||
f.request.scheme = "https"
|
||||
f.request.port = 443
|
||||
|
||||
tctx.master.addons.invoke_addon(sc, "request", f)
|
||||
|
||||
assert f.request.scheme == "http"
|
||||
assert f.request.port == 80
|
||||
|
||||
assert f.request.headers["Host"] == original_host
|
||||
|
Loading…
Reference in New Issue
Block a user