Documentation and screenshots.

This commit is contained in:
Aldo Cortesi 2012-02-22 17:17:13 +13:00
parent a4270efaf2
commit 4f38b3a9c0
17 changed files with 122 additions and 50 deletions

View File

@ -1,28 +1,79 @@
__mitmproxy__ is a console tool that allows interactive examination and __mitmproxy__ is a console tool that allows interactive examination and
modification of HTTP traffic. The _?_ shortcut key shows complete documentation modification of HTTP traffic. Use the _?_ shortcut key to view,
on __mitmproxy__'s functionality. context-sensitive documentation from any __mitmproxy__ screen.
## Flow list
## The interface: connection list The flow list shows an index of captured flows in chronological order.
<img src="@!urlTo("screenshots/mitmproxy.png")!@"/> <img src="@!urlTo("screenshots/mitmproxy.png")!@"/>
- __1__: A GET request, returning a 302 Redirect response.
The connection list shows an index of captured flows in chronological order. - __2__: A GET request, returning 16.75kb of text/html data.
So, in this case, we can we can see that we visited __gmail.com__, which then - __3__: A replayed request.
returned a 301 redirect to mail.google.com. - __4__: Intercepted flows are indicated with orange text. The user may edit
these flows, and then accept them (using the _a_ key) to continue. In this
The statusbar at the bottom tells us that there are 11 flows in the view, that case, the request has been intercepted on the way to the server.
we are using the "pretty" view mode (more on that below), and that the proxy is - __5__: A response intercepted from the server on the way to the client.
bound to port 8080 of all interfaces. - __6__: The event log can be toggled on and off using the _e_ shorcut key. This
pane shows events and errors that may not result in a flow that shows up in the
Also visible is the __Event log__, which can be toggled on and off with the _v_ flow pane.
keyboard shortcut. This displays events like client connection information, - __7__: Flow count.
errors, and script output. - __8__: Various information on mitmproxy's state. In this case, we have an
interception pattern set to ".*".
- __9__: Bind address indicator - mitmproxy is listening on port 8080 of all
interfaces.
## Example: Interception ## Flow view
The __Flow View__ lets you inspect and manipulate a single flow:
<img src="@!urlTo("screenshots/mitmproxy-flowview.png")!@"/>
- __1__: Flow summary.
- __2__: The Request/Response tabs, showing you which part of the flow you are
currently viewing. In the example above, we're viewing the Response. Hit _tab_
to switch between the Response and the Request.
- __3__: Headers.
- __4__: Body.
- __5__: View Mode indicator. In this case, we're viewing the body in __hex__
mode. The other available modes are __pretty__, which uses a number of
heuristics to show you a friendly view of various content types, and __raw__,
which shows you exactly what's there without any changes. You can change modes
using the _m_ key.
## Key/Value Editor
It turns out that ordered key/value data is pervasive in HTTP communications,
so mitmproxy has a built-in editor to help edit and create this kind of data.
There are three ways to reach the __K/V Editor__ from the __Flow View__ screen:
- Editing request or response headers (_e_ for edit, then _h_ for headers)
- Editing a query string (_e_ for edit, then _q_ for query)
- Editing a URL-encoded form (_e_ for edit, then _f_ for form)
If there is is no form or query string, an empty __K/V Editor__ will be started
to let you add one. Here is the __K/V Editor__ showing the headers from a
request:
<img src="@!urlTo("screenshots/mitmproxy-kveditor.png")!@"/>
To edit, navigate to the key or value you want to modify using the arrow or vi
navigation keys, and press enter. The background color will change to show that
you are in edit mode for the specified field:
<img src="@!urlTo("screenshots/mitmproxy-kveditor-editmode.png")!@"/>
Modify the field as desired, and press escape or enter to exit edit mode when
you're done. You can also add a key/value pair (_a_ key), delete a pair (_d_
key), spawn an external editor on a field (_e_ key). Be sure to consult the
context-sensitive help (_?_ key) for more.
# Example: Interception
__mitmproxy__'s interception functionality lets you pause an HTTP request or __mitmproxy__'s interception functionality lets you pause an HTTP request or
response, inspect and modify it, and then accept it to send it on to the server response, inspect and modify it, and then accept it to send it on to the server
@ -31,27 +82,27 @@ or client.
### 1: Set an interception pattern ### 1: Set an interception pattern
<img src="@!urlTo('intercept-filt.png')!@"/> <img src="@!urlTo('mitmproxy-intercept-filt.png')!@"/>
We press _i_ to set an interception pattern. In this case, the __~q__ filter We press _i_ to set an interception pattern. In this case, the __~q__ filter
pattern tells __mitmproxy__ to intercept all requests. For complete filter pattern tells __mitmproxy__ to intercept all requests. For complete filter
syntax, see the [Filter expressions](@!urlTo("filters.html")!@) section of this syntax, see the [Filter expressions](@!urlTo("filters.html")!@) section of this
document, or the built-in help function in __mitmproxy__. document, or the built-in help function in __mitmproxy__.
### 2: Intercepted connections are indicated with a red exclamation mark: ### 2: Intercepted connections are indicated with orange text:
<img src="@!urlTo('intercept-mid.png')!@"/> <img src="@!urlTo('mitmproxy-intercept-mid.png')!@"/>
### 3: You can now view and modify the request: ### 3: You can now view and modify the request:
<img src="@!urlTo('intercept-options.png')!@"/> <img src="@!urlTo('mitmproxy-intercept-options.png')!@"/>
In this case, we viewed the request by selecting it, pressed _e_ for "edit" In this case, we viewed the request by selecting it, pressed _e_ for "edit"
and _m_ for "method" to change the HTTP request method. and _m_ for "method" to change the HTTP request method.
### 4: Accept the intercept to continue ### 4: Accept the intercept to continue:
<img src="@!urlTo('intercept-result.png')!@"/> <img src="@!urlTo('mitmproxy-intercept-result.png')!@"/>
Finally, we press _a_ to accept the modified request, which is then sent on to Finally, we press _a_ to accept the modified request, which is then sent on to
the server. In this case, we changed the request from an HTTP GET to to the server. In this case, we changed the request from an HTTP GET to to

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 161 KiB

View File

@ -62,26 +62,6 @@ Called once on script shutdown, after any other events.
The main classes you will deal with in writing mitmproxy scripts are: The main classes you will deal with in writing mitmproxy scripts are:
<table class="kvtable"> <table class="kvtable">
<tr>
<th>libmproxy.flow.ScriptContext</th>
<td>A handle for interacting with mitmproxy's global state.</td>
</tr>
<tr>
<th>libmproxy.flow.Flow</th>
<td>A collection of objects representing a single HTTP transaction.</td>
</tr>
<tr>
<th>libmproxy.flow.Request</th>
<td>An HTTP request.</td>
</tr>
<tr>
<th>libmproxy.flow.Response</th>
<td>An HTTP response.</td>
</tr>
<tr>
<th>libmproxy.flow.Error</th>
<td>A communications error.</td>
</tr>
<tr> <tr>
<th>libmproxy.flow.ClientConnection</th> <th>libmproxy.flow.ClientConnection</th>
<td>Describes a client connection.</td> <td>Describes a client connection.</td>
@ -90,12 +70,38 @@ The main classes you will deal with in writing mitmproxy scripts are:
<th>libmproxy.flow.ClientDisconnection</th> <th>libmproxy.flow.ClientDisconnection</th>
<td>Describes a client disconnection.</td> <td>Describes a client disconnection.</td>
</tr> </tr>
<tr>
<th>libmproxy.flow.Error</th>
<td>A communications error.</td>
</tr>
<tr>
<th>libmproxy.flow.Flow</th>
<td>A collection of objects representing a single HTTP transaction.</td>
</tr>
<tr> <tr>
<th>libmproxy.flow.Headers</th> <th>libmproxy.flow.Headers</th>
<td>HTTP headers for a request or response.</td> <td>HTTP headers for a request or response.</td>
</tr> </tr>
</table> <tr>
<th>libmproxy.flow.ODict</th>
<td>A dictionary-like object for managing sets of key/value data. There
is also a variant called CaselessODict that ignores key case for some
calls.</td>
</tr>
<tr>
<th>libmproxy.flow.Response</th>
<td>An HTTP response.</td>
</tr>
<tr>
<th>libmproxy.flow.Request</th>
<td>An HTTP request.</td>
</tr>
<tr>
<th>libmproxy.flow.ScriptContext</th>
<td>A handle for interacting with mitmproxy's global state.</td>
</tr>
</table>
The canonical API documentation is the code. You can view the API documentation The canonical API documentation is the code. You can view the API documentation
using pydoc (which is installed with Python by default), like this: using pydoc (which is installed with Python by default), like this:

View File

@ -318,7 +318,6 @@ class ConsoleMaster(flow.FlowMaster):
('heading_key', "q"), ":back", ('heading_key', "q"), ":back",
] ]
footer_text_flowview = [ footer_text_flowview = [
('heading_key', "tab"), ":toggle view ",
('heading_key', "?"), ":help ", ('heading_key', "?"), ":help ",
('heading_key', "q"), ":back ", ('heading_key', "q"), ":back ",
] ]

View File

@ -84,6 +84,8 @@ def fcol(s, attr):
REPLAY_SYMBOL = u"\u21ba"
def format_flow(f, focus, extended=False, padding=2): def format_flow(f, focus, extended=False, padding=2):
pile = [] pile = []
@ -98,7 +100,7 @@ def format_flow(f, focus, extended=False, padding=2):
else: else:
req.append(fcol(">>" if focus else " ", "focus")) req.append(fcol(">>" if focus else " ", "focus"))
if f.request.is_replay(): if f.request.is_replay():
req.append(fcol(u"\u267B", "replay")) req.append(fcol(REPLAY_SYMBOL, "replay"))
req.append(fcol(f.request.method, "method")) req.append(fcol(f.request.method, "method"))
preamble = sum(i[1] for i in req) + len(req) -1 preamble = sum(i[1] for i in req) + len(req) -1
@ -126,7 +128,7 @@ def format_flow(f, focus, extended=False, padding=2):
if f.response: if f.response:
if f.response.is_replay(): if f.response.is_replay():
resp.append(fcol(u"\u267B", "replay")) resp.append(fcol(REPLAY_SYMBOL, "replay"))
if f.response.code in [200, 304]: if f.response.code in [200, 304]:
resp.append(fcol(f.response.code, "goodcode")) resp.append(fcol(f.response.code, "goodcode"))
else: else:

View File

@ -58,6 +58,10 @@ class ODict:
return self.lst == other.lst return self.lst == other.lst
def __getitem__(self, k): def __getitem__(self, k):
"""
Returns a list of values matching key.
"""
ret = [] ret = []
k = self._kconv(k) k = self._kconv(k)
for i in self.lst: for i in self.lst:
@ -73,18 +77,28 @@ class ODict:
return new return new
def __len__(self): def __len__(self):
"""
Total number of (key, value) pairs.
"""
return len(self.lst) return len(self.lst)
def __setitem__(self, k, values): def __setitem__(self, k, valuelist):
if isinstance(values, basestring): """
raise ValueError("ODict values should be lists.") Sets the values for key k. If there are existing values for this
key, they are cleared.
"""
if isinstance(valuelist, basestring):
raise ValueError("ODict valuelist should be lists.")
k = self._kconv(k) k = self._kconv(k)
new = self._filter_lst(k, self.lst) new = self._filter_lst(k, self.lst)
for i in values: for i in valuelist:
new.append((k, i)) new.append((k, i))
self.lst = new self.lst = new
def __delitem__(self, k): def __delitem__(self, k):
"""
Delete all items matching k.
"""
self.lst = self._filter_lst(k, self.lst) self.lst = self._filter_lst(k, self.lst)
def __contains__(self, k): def __contains__(self, k):