Skip to content

Commit

Permalink
improve scripting docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Kriechi committed Apr 4, 2020
1 parent 6acabbb commit 678be7a
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 115 deletions.
16 changes: 15 additions & 1 deletion docs/src/content/addons-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,18 @@ header with a count of the number of responses seen:
Below is an addon class that implements stubs for all events. We've added
annotations to illustrate the argument types for the various events.

{{< example src="examples/addons/events.py" lang="py" >}}
### Generic Events

{{< example src="examples/addons/events.py" lang="py" >}}

### HTTP Events

{{< example src="examples/addons/events-http-specific.py" lang="py" >}}

### WebSocket Events

{{< example src="examples/addons/events-websocket-specific.py" lang="py" >}}

### TCP Events

{{< example src="examples/addons/events-tcp-specific.py" lang="py" >}}
33 changes: 26 additions & 7 deletions docs/src/content/addons-scripting.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ menu:
weight: 5
---

# Scripting
# Scripting HTTP/1.1 and HTTP/2.0

Sometimes, we would like to write a quick script without going through the
trouble of creating a class. The addons mechanism has a shorthand that allows a
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" >}}


Expand All @@ -22,11 +21,31 @@ an arbitrary response instead:

{{< example src="examples/simple/send_reply_from_proxy.py" lang="py" >}}

All events around the HTTP protocol [can be found here]({{< relref "addons-events#http-events">}}).

You can look at the [http][] module, or the [Request][], and
[Response][] classes for other attributes that you can use when
For HTTP-related objects, please look at the [http][] module, or the
[Request][], and [Response][] classes for other attributes that you can use when
scripting.

[http]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/http.py
[Request]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/net/http/request.py
[Response]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/net/http/response.py
# Scripting WebSocket

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" >}}

For WebSocket-related objects please look at the [websocket][] module to find
all attributes that you can use when scripting.

[websocket]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/websocket.py


# Scripting TCP

All events around the TCP protocol [can be found here]({{< relref "addons-events#tcp-events">}}).

{{< example src="examples/complex/tcp_message.py" lang="py" >}}

For WebSocket-related objects please look at the [tcp][] module to find
all attributes that you can use when scripting.

[tcp]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/tcp.py
10 changes: 0 additions & 10 deletions docs/src/content/concepts-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,3 @@ just replay flows for a specific domain:
{{< highlight none >}}
:replay.client "~d google.com"
{{< /highlight >}}










2 changes: 1 addition & 1 deletion docs/src/themes/mitmproxydocs/layouts/partials/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
{{ if .RSSLink -}}
<link href="{{ .RSSLink }}" rel="feed" type="application/rss+xml" title="{{ .Site.Title }}">
{{- end }}
{{ .Hugo.Generator }}
{{ hugo.Generator }}
</head>
<body>
42 changes: 42 additions & 0 deletions examples/addons/events-http-specific.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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
the flow will return the response to the client abort the
connection. CONNECT requests and responses do not generate the usual
HTTP handler events. CONNECT requests are only valid in regular and
upstream proxy modes.
"""

def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
"""
HTTP request headers were successfully read. At this point, the body
is empty.
"""

def request(self, flow: mitmproxy.http.HTTPFlow):
"""
The full HTTP request has been read.
"""

def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
"""
HTTP response headers were successfully read. At this point, the body
is empty.
"""

def response(self, flow: mitmproxy.http.HTTPFlow):
"""
The full HTTP response has been read.
"""

def error(self, flow: mitmproxy.http.HTTPFlow):
"""
An HTTP error has occurred, e.g. invalid server responses, or
interrupted connections. This is distinct from a valid server HTTP
error response, which is simply a response with an HTTP error code.
"""
25 changes: 25 additions & 0 deletions examples/addons/events-tcp-specific.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import mitmproxy.tcp


class Events:
# TCP lifecycle
def tcp_start(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has started.
"""

def tcp_message(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has received a message. The most recent message
will be flow.messages[-1]. The message is user-modifiable.
"""

def tcp_error(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP error has occurred.
"""

def tcp_end(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has ended.
"""
36 changes: 36 additions & 0 deletions examples/addons/events-websocket-specific.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import mitmproxy.http
import mitmproxy.websocket


class Events:
# Websocket lifecycle
def websocket_handshake(self, flow: mitmproxy.http.HTTPFlow):
"""
Called when a client wants to establish a WebSocket connection. The
WebSocket-specific headers can be manipulated to alter the
handshake. The flow object is guaranteed to have a non-None request
attribute.
"""

def websocket_start(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has commenced.
"""

def websocket_message(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
Called when a WebSocket message is received from the client or
server. The most recent message will be flow.messages[-1]. The
message is user-modifiable. Currently there are two types of
messages, corresponding to the BINARY and TEXT frame types.
"""

def websocket_error(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has had an error.
"""

def websocket_end(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has ended.
"""
93 changes: 0 additions & 93 deletions examples/addons/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,99 +10,6 @@


class Events:
# HTTP lifecycle
def http_connect(self, flow: mitmproxy.http.HTTPFlow):
"""
An HTTP CONNECT request was received. Setting a non 2xx response on
the flow will return the response to the client abort the
connection. CONNECT requests and responses do not generate the usual
HTTP handler events. CONNECT requests are only valid in regular and
upstream proxy modes.
"""

def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
"""
HTTP request headers were successfully read. At this point, the body
is empty.
"""

def request(self, flow: mitmproxy.http.HTTPFlow):
"""
The full HTTP request has been read.
"""

def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
"""
HTTP response headers were successfully read. At this point, the body
is empty.
"""

def response(self, flow: mitmproxy.http.HTTPFlow):
"""
The full HTTP response has been read.
"""

def error(self, flow: mitmproxy.http.HTTPFlow):
"""
An HTTP error has occurred, e.g. invalid server responses, or
interrupted connections. This is distinct from a valid server HTTP
error response, which is simply a response with an HTTP error code.
"""

# TCP lifecycle
def tcp_start(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has started.
"""

def tcp_message(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has received a message. The most recent message
will be flow.messages[-1]. The message is user-modifiable.
"""

def tcp_error(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP error has occurred.
"""

def tcp_end(self, flow: mitmproxy.tcp.TCPFlow):
"""
A TCP connection has ended.
"""

# Websocket lifecycle
def websocket_handshake(self, flow: mitmproxy.http.HTTPFlow):
"""
Called when a client wants to establish a WebSocket connection. The
WebSocket-specific headers can be manipulated to alter the
handshake. The flow object is guaranteed to have a non-None request
attribute.
"""

def websocket_start(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has commenced.
"""

def websocket_message(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
Called when a WebSocket message is received from the client or
server. The most recent message will be flow.messages[-1]. The
message is user-modifiable. Currently there are two types of
messages, corresponding to the BINARY and TEXT frame types.
"""

def websocket_error(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has had an error.
"""

def websocket_end(self, flow: mitmproxy.websocket.WebSocketFlow):
"""
A websocket connection has ended.
"""

# Network lifecycle
def clientconnect(self, layer: mitmproxy.proxy.protocol.Layer):
"""
Expand Down
2 changes: 1 addition & 1 deletion examples/complex/websocket_inject_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ 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 #{} an injected message!'.format(i))
flow.inject_message(flow.client_conn, 'This is the #{} injected message!'.format(i))
i += 1

def websocket_start(self, flow):
Expand Down
11 changes: 9 additions & 2 deletions examples/simple/websocket_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ def websocket_message(flow):
# get the latest message
message = flow.messages[-1]

# simply print the content of the message
ctx.log.info(message.content)
# was the message sent from the client or server?
if message.from_client:
ctx.log.info("Client sent a message: {}".format(message.content))
else:
ctx.log.info("Server sent a message: {}".format(message.content))

# manipulate the message content
message.content = re.sub(r'^Hello', 'HAPPY', message.content)

if 'FOOBAR' in message.content:
# kill the message and not send it to the other endpoint
message.kill()

0 comments on commit 678be7a

Please sign in to comment.