Migrate pathod docs to Sphinx

All the content of the pathod docs are moved into Sphinx. The interactive
format has not translated well to static docs, and there's still a lot of
rewriting, format fixing, structuring, etc to be done.
This commit is contained in:
Aldo Cortesi 2016-06-07 12:55:32 +12:00
parent 2b19a33738
commit e037fe05ff
30 changed files with 643 additions and 1564 deletions

11
docs/_static/theme_overrides.css vendored Normal file
View File

@ -0,0 +1,11 @@
/* override table width restrictions */
.wy-table-responsive table td, .wy-table-responsive table th {
white-space: normal;
}
.wy-table-responsive {
margin-bottom: 24px;
max-width: 100%;
overflow: visible;
}

View File

@ -153,7 +153,7 @@ html_favicon = "favicon.ico"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
@ -216,4 +216,10 @@ html_favicon = "favicon.ico"
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'mitmproxydoc'
htmlhelp_basename = 'mitmproxydoc'
html_context = {
'css_files': [
'_static/theme_overrides.css', # overrides for wide tables in RTD theme
],
}

View File

@ -64,6 +64,17 @@
tutorials/gamecenter
tutorials/transparent-dhcp
.. toctree::
:hidden:
:caption: Pathod & Pathoc
pathod/intro
pathod/language
pathod/library
pathod/test
.. toctree::
:hidden:
:caption: Hacking
@ -80,4 +91,3 @@
* :ref:`genindex`
* :ref:`modindex`

307
docs/pathod/intro.rst Normal file
View File

@ -0,0 +1,307 @@
.. _intro:
Pathology 101
=============
pathod
------
Pathod is a pathological HTTP daemon designed to let you craft almost any
conceivable HTTP response, including ones that creatively violate the
standards. HTTP responses are specified using a :ref:`small, terse language
<language>` which pathod shares with its evil twin :ref:`pathoc`. To start
playing with pathod, fire up the daemon:
>>> pathod
By default, the service listens on port 9999 of localhost, and the default
crafting anchor point is the path **/p/**. Anything after this URL prefix is
treated as a response specifier. So, hitting the following URL will generate an
HTTP 200 response with 100 bytes of random data:
http://localhost:9999/p/200:b@100
See the :ref:`language documentation <language>` to get (much) fancier. The
pathod daemon also takes a range of configuration options. To view those, use
the command-line help:
>>> pathod --help
Mimicing a proxy
^^^^^^^^^^^^^^^^
Pathod automatically responds to both straight HTTP and proxy requests. For
proxy requests, the upstream host is ignored, and the path portion of the URL
is used to match anchors. This lets you test software that supports a proxy
configuration by spoofing responses from upstream servers.
By default, we treat all proxy CONNECT requests as HTTPS traffic, serving the
response using either pathod's built-in certificates, or the cert/key pair
specified by the user. You can over-ride this behaviour if you're testing a
client that makes a non-SSL CONNECT request using the **-C** command-line
option.
Anchors
^^^^^^^
Anchors provide an alternative to specifying the response in the URL. Instead,
you attach a response to a pre-configured anchor point, specified with a regex.
When a URL matching the regex is requested, the specified response is served.
>>> pathod -a "/foo=200"
Here, "/foo" is the regex specifying the anchor path, and the part after the "="
is a response specifier.
File Access
^^^^^^^^^^^
There are two operators in the :ref:`language <language>`` that load contents
from file - the **+** operator to load an entire request specification from
file, and the **>** value specifier. In pathod, both of these operators are
restricted to a directory specified at startup, or disabled if no directory is
specified:
>>> pathod -d ~/staticdir"
Internal Error Responses
^^^^^^^^^^^^^^^^^^^^^^^^
Pathod uses the non-standard 800 response code to indicate internal errors, to
distinguish them from crafted responses. For example, a request to:
http://localhost:9999/p/foo
... will return an 800 response because "foo" is not a valid page specifier.
.. _pathoc:
pathoc
------
Pathoc is a perverse HTTP daemon designed to let you craft almost any
conceivable HTTP request, including ones that creatively violate the standards.
HTTP requests are specified using a :ref:`small, terse language <language>`,
which pathod shares with its server-side twin pathod. To view pathoc's complete
range of options, use the command-line help:
>>> pathoc --help
Getting Started
^^^^^^^^^^^^^^^
The basic pattern for pathoc commands is as follows:
pathoc hostname request [request ...]
That is, we specify the hostname to connect to, followed by one or more
requests. Lets start with a simple example::
> pathoc google.com get:/
07-06-16 12:13:43: >> 'GET':/
<< 302 Found: 261 bytes
Here, we make a GET request to the path / on port 80 of google.com. Pathoc's
output tells us that the server responded with a 302 redirection. We can tell
pathoc to connect using SSL, in which case the default port is changed to 443
(you can over-ride the default port with the **-p** command-line option)::
> pathoc -s www.google.com get:/
07-06-16 12:14:56: >> 'GET':/
<< 302 Found: 262 bytes
Multiple Requests
^^^^^^^^^^^^^^^^^
There are two ways to tell pathoc to issue multiple requests. The first is to specify
them on the command-line, like so::
> pathoc google.com get:/ get:/
07-06-16 12:21:04: >> 'GET':/
<< 302 Found: 261 bytes
07-06-16 12:21:04: >> 'GET':/
<< 302 Found: 261 bytes
In this case, pathoc issues the specified requests over the same TCP connection -
so in the above example only one connection is made to google.com
The other way to issue multiple requests is to use the **-n** flag::
> pathoc -n 2 google.com get:/
07-06-16 12:21:04: >> 'GET':/
<< 302 Found: 261 bytes
07-06-16 12:21:04: >> 'GET':/
<< 302 Found: 261 bytes
The output is identical, but two separate TCP connections are made to the
upstream server. These two specification styles can be combined::
pathoc -n 2 google.com get:/ get:/
Here, two distinct TCP connections are made, with two requests issued over
each.
Basic Fuzzing
^^^^^^^^^^^^^
The combination of pathoc's powerful request specification language and a few
of its command-line options makes for quite a powerful basic fuzzer. Here's an
example::
pathoc -e -I 200 -t 2 -n 1000 localhost get:/:b@10:ir,@1
The request specified here is a valid GET with a body consisting of 10 random bytes,
but with 1 random byte inserted in a random place. This could be in the headers,
in the initial request line, or in the body itself. There are a few things
to note here:
- Corrupting the request in this way will often make the server enter a state where
it's awaiting more input from the client. This is where the
**-t** option comes in, which sets a timeout that causes pathoc to
disconnect after two seconds.
- The **-n** option tells pathoc to repeat the request 1000 times.
- The **-I** option tells pathoc to ignore HTTP 200 response codes.
You can use this to fine-tune what pathoc considers to be an exceptional
condition, and therefore log-worthy.
- The **-e** option tells pathoc to print an explanation of each logged
request, in the form of an expanded pathoc specification with all random
portions and automatic header additions resolved. This lets you precisely
replay a request that triggered an error.
Interacting with Proxies
^^^^^^^^^^^^^^^^^^^^^^^^
Pathoc has a reasonably sophisticated suite of features for interacting with
proxies. The proxy request syntax very closely mirrors that of straight HTTP,
which means that it is possible to make proxy-style requests using pathoc
without any additional syntax, by simply specifying a full URL instead of a
simple path:
>>> pathoc -p 8080 localhost "get:'http://google.com'"
Another common use case is to use an HTTP CONNECT request to probe remote
servers via a proxy. This is done with the **-c** command-line option, which
allows you to specify a remote host and port pair:
>>> pathoc -c google.com:80 -p 8080 localhost get:/
Note that pathoc does **not** negotiate SSL without being explictly instructed
to do so. If you're making a CONNECT request to an SSL-protected resource, you
must also pass the **-s** flag:
>>> pathoc -sc google.com:443 -p 8080 localhost get:/
Embedded response specification
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
One interesting feature of the Request specification language is that you can
embed a response specification in it, which is then added to the request path.
Here's an example:
>>> pathoc localhost:9999 "get:/p/:s'401:ir,@1'"
This crafts a request that connects to the pathod server, and which then crafts
a response that generates a 401, with one random byte embedded at a random
point. The response specification is parsed and expanded by pathoc, so you see
syntax errors immediately. This really becomes handy when combined with the
**-e** flag to show the expanded request::
07-06-16 12:32:01: >> 'GET':/p/:s'401:i35,\x27\\x1b\x27:h\x27Content-Length\x27=\x270\x27:h\x27Content-Length\x27=\x270\x27':h'Host'='localhost'
<< 401 Unauthorized: 0 bytes
Note that the embedded response has been resolved *before* being sent to
the server, so that "ir,@1" (embed a random byte at a random location) has
become "i15,\'o\'" (embed the character "o" at offset 15). You now have a
pathoc request specification that is precisely reproducible, even with random
components. This feature comes in terribly handy when testing a proxy, since
you can now drive the server response completely from the client, and have a
complete log of reproducible requests to analyze afterwards.
Request Examples
----------------
.. list-table::
:widths: 50 50
:header-rows: 0
* - get:/
- Get path /
* - get:/:b@100
- 100 random bytes as the body
* - get:/:h"Etag"="&;drop table browsers;"
- Add a header
* - get:/:u"&;drop table browsers;"
- Add a User-Agent header
* - get:/:b@100:dr
- Drop the connection randomly
* - get:/:b@100,ascii:ir,@1
- 100 ASCII bytes as the body, and randomly inject a random byte
* - ws:/
- Initiate a websocket handshake.
Response Examples
-----------------
.. list-table::
:widths: 50 50
:header-rows: 0
* - 200
- A basic HTTP 200 response.
* - 200:r
- A basic HTTP 200 response with no Content-Length header. This will hang.
* - 200:da
- Server-side disconnect after all content has been sent.
* - 200:b\@100
- 100 random bytes as the body. A Content-Length header is added, so the disconnect
is no longer needed.
* - 200:b\@100:h"Etag"="';drop table servers;"
- Add a Server header
* - 200:b\@100:dr
- Drop the connection randomly
* - 200:b\@100,ascii:ir,@1
- 100 ASCII bytes as the body, and randomly inject a random byte
* - 200:b\@1k:c"text/json"
- 1k of random bytes, with a text/json content type
* - 200:b\@1k:p50,120
- 1k of random bytes, pause for 120 seconds after 50 bytes
* - 200:b\@1k:pr,f
- 1k of random bytes, but hang forever at a random location
* - 200:b\@100:h\@1k,ascii_letters='foo'
- 100 ASCII bytes as the body, randomly generated 100k header name, with the value
'foo'.

257
docs/pathod/language.rst Normal file
View File

@ -0,0 +1,257 @@
.. _language:
language spec
=============
************
HTTP Request
************
**method:path:[colon-separated list of features]**
.. list-table::
:widths: 20 80
:header-rows: 0
* - method
- A :ref:`VALUE` specifying the HTTP method to
use. Standard methods do not need to be enclosed in quotes, while
non-standard methods can be specified as quoted strings.
The special method **ws** creates a valid websocket upgrade
GET request, and signals to pathoc to switch to websocket recieve
mode if the server responds correctly. Apart from that, websocket
requests are just like any other, and all aspects of the request
can be over-ridden.
* - h\:\ :ref:`VALUE`\ =\ :ref:`VALUE`\
- Set a header.
* - r
- Set the **raw** flag on this response. Pathod will not calculate a
*Content-Length* header if a body is set.
* - c\ :ref:`VALUE`
- A shortcut for setting the Content-Type header. Equivalent to
``h"Content-Type"=VALUE``
* - u\ :ref:`VALUE`
uSHORTCUT
- Set a User-Agent header on this request. You can specify either a
complete :ref:`VALUE`, or a User-Agent shortcut: **android**,
**blackberry**, **bingbot**, **chrome**, **firefox**, **googlebot**,
**ie9**, **ipad**, **iphone**, **safari**.
* - b\ :ref:`VALUE`
- Set the body. The appropriate Content-Length header is added
automatically unless the **r** flag is set.
* - s\ :ref:`VALUE`
- An embedded Response specification, appended to the path of the request.
* - x\ :ref:`INTEGER`
- Repeat this message N times.
* - d\ :ref:`OFFSET`
- Disconnect after OFFSET bytes (HTTP/1 only).
* - i\ :ref:`OFFSET`,\ :ref:`VALUE`
- Inject the specified value at the offset (HTTP/1 only)
* - p\ :ref:`OFFSET`,SECONDS
- Pause for SECONDS seconds after OFFSET bytes. SECONDS can be an integer
or "f" to pause forever (HTTP/1 only)
*************
HTTP Response
*************
**code:[colon-separated list of features]**
.. list-table::
:widths: 20 80
:header-rows: 0
* - code
- An integer specifying the HTTP response code.
The special method **ws** creates a valid websocket upgrade
response (code 101), and moves pathod to websocket mode. Apart
from that, websocket responses are just like any other, and all
aspects of the response can be over-ridden.
* - m\ :ref:`VALUE`
- HTTP Reason message. Automatically chosen according to the response
code if not specified. (HTTP/1 only)
* - h\:\ :ref:`VALUE`\ =\ :ref:`VALUE`\
- Set a header.
* - r
- Set the **raw** flag on this response. Pathod will not calculate a
*Content-Length* header if a body is set.
* - l\ :ref:`VALUE`
- A shortcut for setting the Location header. Equivalent to
``h"Location"=VALUE``
* - c\ :ref:`VALUE`
- A shortcut for setting the Content-Type header. Equivalent to
``h"Content-Type"=VALUE``
* - b\ :ref:`VALUE`
- Set the body. The appropriate Content-Length header is added
automatically unless the **r** flag is set.
* - d\ :ref:`OFFSET`
- Disconnect after OFFSET bytes (HTTP/1 only).
* - i\ :ref:`OFFSET`,\ :ref:`VALUE`
- Inject the specified value at the offset (HTTP/1 only)
* - p\ :ref:`OFFSET`,SECONDS
- Pause for SECONDS seconds after OFFSET bytes. SECONDS can be an integer
or "f" to pause forever (HTTP/1 only)
***************
Websocket Frame
***************
**wf:[colon-separated list of features]**
.. list-table::
:widths: 20 80
:header-rows: 0
* - b\ :ref:`VALUE`
- Set the frame payload. If a masking key is present, the value is
encoded automatically.
* - c\ :ref:`INTEGER`
- Set the op code. This can either be an integer from 0-15, or be one of
the following opcode names: **text** (the default), **continue**,
**binary**, **close**, **ping**, **pong**.
* - d\ :ref:`OFFSET`
- Disconnect after OFFSET bytes
* - i\ :ref:`OFFSET`,\ :ref:`VALUE`
- Inject the specified value at the offset
* - p\ :ref:`OFFSET`,SECONDS
- Pause for SECONDS seconds after OFFSET bytes. SECONDS can be an integer
or "f" to pause forever
* - x\ :ref:`INTEGER`
- Repeat this message N times.
* - [-]fin
- Set or un-set the **fin** bit.
* - k\ :ref:`VALUE`
- Set the masking key. The resulting value must be exactly 4 bytes long.
The special form **knone** specifies that no key should be set, even if
the mask bit is on.
* - l\ :ref:`INTEGER`
- Set the payload length in the frame header, regardless of the actual
body length.
* - [-]mask
- Set or un-set the <b>mask</b> bit.
* - r\ :ref:`VALUE`
- Set the raw frame payload. This disables masking, even if the key is present.
* - [-]rsv1
- Set or un-set the **rsv1** bit.
* - [-]rsv2
- Set or un-set the **rsv2** bit.
* - [-]rsv2
- Set or un-set the **rsv2** bit.
**********
Data types
**********
.. _INTEGER:
INTEGER
^^^^^^^
.. _OFFSET:
OFFSET
^^^^^^
Offsets are calculated relative to the base message, before any injections or
other transforms are applied. They have 3 flavors:
======= ==========================
integer An integer byte offset
**r** A random location
**a** The end of the message
======= ==========================
.. _VALUE:
VALUE
^^^^^
Literals
""""""""
Literal values are specified as a quoted strings::
"foo"
Either single or double quotes are accepted, and quotes can be escaped with
backslashes within the string::
'fo\'o'
Literal values can contain Python-style backslash escape sequences::
'foo\r\nbar'
Generated
"""""""""
An @-symbol lead-in specifies that generated data should be used. There are two
components to a generator specification - a size, and a data type. By default
pathod assumes a data type of "bytes".
Here's a value specifier for generating 100 bytes::
@100
You can use standard suffixes to indicate larger values. Here, for instance, is
a specifier for generating 100 megabytes:
@100m
Data is generated and served efficiently - if you really want to send a
terabyte of data to a client, pathod can do it. The supported suffixes are:
========== ====================
b 1024**0 (bytes)
k 1024**1 (kilobytes)
m 1024**2 (megabytes)
g 1024**3 (gigabytes)
t 1024**4 (terabytes)
========== ====================
Data types are separated from the size specification by a comma. This specification
generates 100mb of ASCII::
@100m,ascii
Supported data types are:
================= ==============================================
ascii All ASCII characters
ascii_letters A-Za-z
ascii_lowercase a-z
ascii_uppercase A-Z
bytes All 256 byte values
digits 0-9
hexdigits 0-f
octdigits 0-7
punctuation !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ and space
whitespace \\t \\n \\x0b \\x0c \\r and space
================= ==============================================
Files
"""""
You can load a value from a specified file path. To do so, you have to specify a
_staticdir_ option to pathod on the command-line, like so:
>>> pathod -d ~/myassets
All paths are relative paths under this directory. File loads are indicated by
starting the value specifier with the left angle bracket::
<my/path
The path value can also be a quoted string, with the same syntax as literals::
<"my/path"

14
docs/pathod/library.rst Normal file
View File

@ -0,0 +1,14 @@
.. _library:
pathod library
==============
Behind the pathod and pathoc command-line tools lurks the **pathod** library, a
powerful way to manipulate and serve HTTP requests and responses from code. The
canonical documentation for the library is in the code, and can be accessed
using pydoc.
.. literalinclude:: ../../examples/pathod/libpathod_pathoc.py
:caption: examples/pathod/libpathod_pathoc.py
:language: python

35
docs/pathod/test.rst Normal file
View File

@ -0,0 +1,35 @@
.. _test:
pathod.test
===========
The **pathod.test** module is a light, flexible testing layer for HTTP clients.
It works by firing up a Pathod instance in a separate thread, letting you use
Pathod's full abilities to generate responses, and then query Pathod's internal
logs to establish what happened. All the mechanics of startup, shutdown, finding
free ports and so forth are taken care of for you.
The canonical docs can be accessed using pydoc:
>>> pydoc pathod.test
The remainder of this page demonstrates some common interaction patterns using
<a href="http://nose.readthedocs.org/en/latest/">nose</a>. These examples are
also applicable with only minor modification to most commonly used Python testing
engines.
Context Manager
---------------
.. literalinclude:: ../../examples/pathod/test_context.py
:caption: examples/pathod/test_context.py
:language: python
One instance per test
---------------------
.. literalinclude:: ../../examples/pathod/test_setup.py
:caption: examples/pathod/test_setup.py
:language: python

View File

@ -1,22 +0,0 @@
{% extends "frame.html" %} {% block body %}
<section>
<div class="page-header">
<h1>About</h1>
</div>
<div class="row">
<div class="span6">
<div>
<p>pathod is developed by <a href="http://corte.si">Aldo Cortesi</a>.</p>
</div>
<div>
<ul>
<li>email: <a href="mailto:aldo@corte.si">aldo@corte.si</a></li>
<li>twitter: <a href="http://twitter.com/cortesi">@cortesi</a></li>
<li>github: <a href="https://github.com/cortesi">github.com/cortesi</a></li>
</ul>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -1,26 +0,0 @@
{% extends "layout.html" %}
{% macro subs(s) %}
{% if subsection == s %}
class="active"
{% endif %}
{% endmacro %}
{% block content %}
<div class="row">
<div class="span3">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li {{subs( "pathod")}}><a href="/docs/pathod">pathod</a></li>
<li {{subs( "pathoc")}}><a href="/docs/pathoc">pathoc</a></li>
<li {{subs( "lang")}}><a href="/docs/language">language</a></li>
<li {{subs( "pathod")}}><a href="/docs/pathod">pathod</a></li>
<li {{subs( "test")}}><a href="/docs/test">pathod.test</a></li>
</ul>
</div>
</div>
<div class="span9">
{% block body %} {% endblock %}
</div>
</div>
{% endblock %}

View File

@ -1,196 +0,0 @@
{% extends "docframe.html" %} {% block body %}
<div class="page-header">
<h1>
Language Spec
<small>The mini-language at the heart of pathoc and pathod.</small>
</h1>
</div>
<ul class="nav nav-tabs">
<li class="active"><a href="#specifying_requests" data-toggle="tab">HTTP Requests</a></li>
<li><a href="#specifying_responses" data-toggle="tab">HTTP Responses</a></li>
<li><a href="#websockets" data-toggle="tab">Websocket Frames</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane" id="specifying_responses">
{% include "docs_lang_responses.html" %}
</div>
<div class="tab-pane active" id="specifying_requests">
{% include "docs_lang_requests.html" %}
</div>
<div class="tab-pane" id="websockets">
{% include "docs_lang_websockets.html" %}
</div>
</div>
<section id="features">
<div class="page-header">
<h1>Features</h1>
</div>
<a id="offsetspec"></a>
<h2>OFFSET</h2>
<p>
Offsets are calculated relative to the base message, before any injections or other
transforms are applied. They have 3 flavors:
</p>
<ul>
<li>An integer byte offset </li>
<li><b>r</b> for a random location</li>
<li><b>a</b> for the end of the message</li>
</ul>
<a id="valuespec"></a>
<h2>VALUE</h2>
<h3>Literals</h3>
<p>Literal values are specified as a quoted strings: </p>
<pre class="example">"foo"</pre>
<p>
Either single or double quotes are accepted, and quotes can be escaped with backslashes
within the string:
</p>
<pre class="example">'fo\'o'</pre>
<p>Literal values can contain Python-style backslash escape sequences:</p>
<pre class="example">'foo\r\nbar'</pre>
<h3>Files</h3>
<p>
You can load a value from a specified file path. To do so, you have to specify a
_staticdir_ option to pathod on the command-line, like so:
</p>
<pre class="example">pathod -d ~/myassets</pre>
<p>
All paths are relative paths under this directory. File loads are indicated by starting
the value specifier with the left angle bracket:
</p>
<pre class="example">&lt;my/path</pre>
<p>The path value can also be a quoted string, with the same syntax as literals:</p>
<pre class="example">&lt;"my/path"</pre>
<h3>Generated values</h3>
<p>
An @-symbol lead-in specifies that generated data should be used. There are two components
to a generator specification - a size, and a data type. By default pathod
assumes a data type of "bytes".
</p>
<p>Here's a value specifier for generating 100 bytes:
<pre class="example">@100</pre>
</p>
<p>
You can use standard suffixes to indicate larger values. Here, for instance, is a
specifier for generating 100 megabytes:
</p>
<pre class="example">@100m</pre>
<p>
Data is generated and served efficiently - if you really want to send a terabyte
of data to a client, pathod can do it. The supported suffixes are:
</p>
<table class="table table-bordered">
<tbody>
<tr>
<td>b</td>
<td>1024**0 (bytes)</td>
</tr>
<tr>
<td>k</td>
<td>1024**1 (kilobytes)</td>
</tr>
<tr>
<td>m</td>
<td>1024**2 (megabytes)</td>
</tr>
<tr>
<td>g</td>
<td>1024**3 (gigabytes)</td>
</tr>
<tr>
<td>t</td>
<td>1024**4 (terabytes)</td>
</tr>
</tbody>
</table>
<p>
Data types are separated from the size specification by a comma. This specification
generates 100mb of ASCII:
</p>
<pre class="example">@100m,ascii</pre>
<p>Supported data types are:</p>
<table class="table table-bordered">
<tbody>
<tr>
<td>ascii</td>
<td>All ASCII characters</td>
</tr>
<tr>
<td>ascii_letters</td>
<td>A-Za-z</td>
</tr>
<tr>
<td>ascii_lowercase</td>
<td>a-z</td>
</tr>
<tr>
<td>ascii_uppercase</td>
<td>A-Z</td>
</tr>
<tr>
<td>bytes</td>
<td>All 256 byte values</td>
</tr>
<tr>
<td>digits</td>
<td>0-9</td>
</tr>
<tr>
<td>hexdigits</td>
<td>0-f</td>
</tr>
<tr>
<td>octdigits</td>
<td>0-7</td>
</tr>
<tr>
<td>punctuation</td>
<td>
<pre>!"#$%&\'()*+,-./:;
<=>?@[\\]^_`{|}~</pre>
</td>
</tr>
<tr>
<td>whitespace</td>
<td>
<pre>\t\n\x0b\x0c\r and space</pre>
</td>
</tr>
</tbody>
</table>
</section>
{% endblock %}

View File

@ -1,114 +0,0 @@
<pre class="example">method:path:[colon-separated list of features]</pre>
</p>
<table class="table table-bordered">
<tbody>
<tr>
<td>method</td>
<td>
<p>
A <a href="#valuespec">VALUE</a> specifying the HTTP method to
use. Standard methods do not need to be enclosed in quotes, while
non-standard methods can be specified as quoted strings.
</p>
<p>
The special method <b>ws</b> creates a valid websocket upgrade
GET request, and signals to pathoc to switch to websocket recieve
mode if the server responds correctly. Apart from that, websocket
requests are just like any other, and all aspects of the request
can be over-ridden.
</p>
</td>
</tr>
<tr>
<td>h<a href="#valuespec">VALUE</a>=<a href="#valuespec">VALUE</a></td>
<td>
Set a header.
</td>
</tr>
<tr>
<td>r</td>
<td>
Set the "raw" flag on this response. Pathod will not calculate a Content-Length header
if a body is set.
</td>
</tr>
<tr>
<td>c<a href="#valuespec">VALUE</a></td>
<td>
A shortcut for setting the Content-Type header. Equivalent to h"Content-Type"=VALUE
</td>
</tr>
<tr>
<td>u<a href="#valuespec">VALUE</a>
<br> uSHORTCUT
</td>
<td>
Set a User-Agent header on this request. You can specify either a complete
<a href="#valuespec">VALUE</a>, or a User-Agent shortcut:
<table class="table table-condensed">
{% for i in uastrings %}
<tr>
<td><b>{{ i[1] }}</b></td>
<td>{{ i[0] }}</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
<tr>
<td>b<a href="#valuespec">VALUE</a></td>
<td>
Set the body. The appropriate Content-Length header is added automatically unless
the "r" flag is set.
</td>
</tr>
<tr>
<td>s<a href="#valuespec">VALUE</a></td>
<td>
An embedded Response specification, appended to the path of the request.
</td>
</tr>
<tr>
<td>x<a href="#valuespec">INTEGER</a></td>
<td>
Repeat this message N times.
</td>
</tr>
<tr>
<td>d<a href="#offsetspec">OFFSET</a></td>
<td>
<span class="badge badge-info">HTTP/1 only</span> Disconnect after
OFFSET bytes.
</td>
</tr>
<tr>
<td>i<a href="#offsetspec">OFFSET</a>,<a href="#valuespec">VALUE</a></td>
<td>
<span class="badge badge-info">HTTP/1 only</span> Inject the specified
value at the offset.
</td>
</tr>
<tr>
<td>p<a href="#offsetspec">OFFSET</a>,SECONDS</td>
<td>
<span class="badge badge-info">HTTP/1 only</span> Pause for SECONDS
seconds after OFFSET bytes. SECONDS can be an integer or "f" to pause
forever.
</td>
</tr>
</tbody>
</table>

View File

@ -1,88 +0,0 @@
<pre class="example">code:[colon-separated list of features]</pre>
<table class="table table-bordered">
<tbody>
<tr>
<td>code</td>
<td>
<p>An integer specifying the HTTP response code.</p>
<p>
The special method <b>ws</b> creates a valid websocket upgrade
response (code 101), and moves pathod to websocket mode. Apart
from that, websocket responses are just like any other, and all
aspects of the response can be over-ridden.
</p>
</td>
</tr>
<tr>
<td>m<a href="#valuespec">VALUE</a></td>
<td>
<span class="badge badge-info">HTTP/1 only</span> HTTP Reason message.
Automatically chosen according to the response code if not specified.
</td>
</tr>
<tr>
<td>h<a href="#valuespec">VALUE</a>=<a href="#valuespec">VALUE</a></td>
<td>
Set a header.
</td>
</tr>
<tr>
<td>r</td>
<td>
Set the "raw" flag on this response. Pathod will not calculate a Content-Length header
if a body is set, or add a Date header to the response.
</td>
</tr>
<tr>
<td>l<a href="#valuespec">VALUE</a></td>
<td>
A shortcut for setting the Location header. Equivalent to h"Location"=VALUE
</td>
</tr>
<tr>
<td>c<a href="#valuespec">VALUE</a></td>
<td>
A shortcut for setting the Content-Type header. Equivalent to h"Content-Type"=VALUE
</td>
</tr>
<tr>
<td>b<a href="#valuespec">VALUE</a></td>
<td>
Set the body. The appropriate Content-Length header is added automatically unless
the "r" flag is set.
</td>
</tr>
<tr>
<td>d<a href="#offsetspec">OFFSET</a></td>
<td>
<span class="badge badge-info">HTTP/1 only</span> Disconnect after
OFFSET bytes.
</td>
</tr>
<tr>
<td>i<a href="#offsetspec">OFFSET</a>,<a href="#valuespec">VALUE</a></td>
<td>
<span class="badge badge-info">HTTP/1 only</span> Inject the specified
value at the offset.
</td>
</tr>
<tr>
<td>p<a href="#offsetspec">OFFSET</a>,SECONDS</td>
<td>
<span class="badge badge-info">HTTP/1 only</span> Pause for SECONDS
seconds after OFFSET bytes. SECONDS can be an integer or "f" to pause
forever.
</td>
</tr>
</tbody>
</table>

View File

@ -1,115 +0,0 @@
<pre class="example">wf:[colon-separated list of features]</pre>
</p>
<table class="table table-bordered">
<tbody>
<tr>
<td> b<a href="#valuespec">VALUE</a> </td>
<td>
Set the frame payload. If a masking key is present, the value is encoded automatically.
</td>
</tr>
<tr>
<td> c<a href="#valuespec">INTEGER</a> </td>
<td>
Set the op code. This can either be an integer from 0-15, or be one of the following
opcode names: <b>text</b> (the default),
<b>continue</b>, <b>binary</b>, <b>close</b>, <b>ping</b>,
<b>pong</b>.
</td>
</tr>
<tr>
<td> d<a href="#offsetspec">OFFSET</a> </td>
<td>
Disconnect after OFFSET bytes.
</td>
</tr>
<tr>
<td> [-]fin </td>
<td>
Set or un-set the <b>fin</b> bit.
</td>
</tr>
<tr>
<td> i<a href="#offsetspec">OFFSET</a>,<a href="#valuespec">VALUE</a> </td>
<td>
Inject the specified value at the offset.
</td>
</tr>
<tr>
<td> k<a href="#valuespec">VALUE</a> </td>
<td>
Set the masking key. The resulting value must be exactly 4 bytes long. The special
form
<b>knone</b> specifies that no key should be set, even if the mask
bit is on.
</td>
</tr>
<tr>
<td> l<a href="#valuespec">INTEGER</a> </td>
<td>
Set the payload length in the frame header, regardless of the actual body length.
</td>
</tr>
<tr>
<td> [-]mask </td>
<td>
Set or un-set the <b>mask</b> bit.
</td>
</tr>
<tr>
<td> p<a href="#offsetspec">OFFSET</a>,SECONDS </td>
<td>
Pause for SECONDS seconds after OFFSET bytes. SECONDS can be an integer or "f" to
pause forever.
</td>
</tr>
<tr>
<td> r<a href="#valuespec">VALUE</a> </td>
<td>
Set the raw frame payload. This disables masking, even if the key is present.
</td>
</tr>
<tr>
<td> [-]rsv1 </td>
<td>
Set or un-set the <b>rsv1</b> bit.
</td>
</tr>
<tr>
<td> [-]rsv2 </td>
<td>
Set or un-set the <b>rsv2</b> bit.
</td>
</tr>
<tr>
<td> [-]rsv3 </td>
<td>
Set or un-set the <b>rsv3</b> bit.
</td>
</tr>
<tr>
<td> x<a href="#valuespec">INTEGER</a> </td>
<td>
Repeat this message N times.
</td>
</tr>
</tbody>
</table>

View File

@ -1,23 +0,0 @@
{% extends "docframe.html" %} {% block body %}
<div class="page-header">
<h1>
pathod
<small>Using pathod and pathoc in code.</small>
</h1>
</div>
<div class="row">
<div class="span6">
<p>
Behind the pathod and pathoc command-line tools lurks <b>pathod</b>,
a powerful library for manipulating and serving HTTP requests and responses.
The canonical documentation for the library is in the code, and can be
accessed using pydoc.
</p>
</div>
<div class="span6">
<h1>pathoc</h1>
{% include "pathod_pathoc.html" %}
</div>
</div>
{% endblock %}

View File

@ -1,211 +0,0 @@
{% extends "docframe.html" %} {% block body %}
<div class="page-header">
<h1>
pathoc
<small>A perverse HTTP client.</small>
</h1>
</div>
<p>
Pathoc is a perverse HTTP daemon designed to let you craft almost any conceivable
HTTP request, including ones that creatively violate the standards. HTTP requests
are specified using a
<a href="/docs/language">small, terse language</a>, which pathod shares with
its server-side twin <a href="/docs/pathod">pathod</a>. To view pathoc's complete
range of options, use the command-line help:
</p>
<pre class="terminal">pathoc --help</pre>
<section>
<div class="page-header">
<h1>Getting Started</h1>
</div>
<p>The basic pattern for pathoc commands is as follows: </p>
<pre class="terminal">pathoc hostname request [request ...]</pre>
<p>
That is, we specify the hostname to connect to, followed by one or more requests.
Lets start with a simple example:
</p>
<pre class="terminal">
&gt; pathoc google.com get:/ &lt;&lt; 301 Moved Permanently: 219 bytes
</pre>
<p>
Here, we make a GET request to the path / on port 80 of google.com. Pathoc's output
tells us that the server responded with a 301. We can tell pathoc to connect
using SSL, in which case the default port is changed to 443 (you can over-ride
the default port with the <b>-p</b> command-line option):
</p>
<pre class="terminal">
&gt; pathoc -s google.com get:/ &lt;&lt; 301 Moved Permanently: 219 bytes
</pre>
</section>
<section>
<div class="page-header">
<h1>Multiple Requests</h1>
</div>
<p>
There are two ways to tell pathoc to issue multiple requests. The first is to specify
them on the command-line, like so:
</p>
<pre class="terminal">
&gt; pathoc google.com get:/ get:/ &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt;
301 Moved Permanently: 219 bytes
</pre>
<p>
In this case, pathoc issues the specified requests over the same TCP connection -
so in the above example only one connection is made to google.com
</p>
<p>The other way to issue multiple requets is to use the <b>-n</b> flag:</p>
<pre class="terminal">
&gt; pathoc -n 2 google.com get:/ &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt; 301
Moved Permanently: 219 bytes
</pre>
<p>
The output is identical, but two separate TCP connections are made to the upstream
server. These two specification styles can be combined:
</p>
<pre class="terminal">
&gt; pathoc -n 2 google.com get:/ get:/ &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt;
301 Moved Permanently: 219 bytes &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt;
301 Moved Permanently: 219 bytes
</pre>
<p>Here, two distinct TCP connections are made, with two requests issued over each.</p>
</section>
<section>
<div class="page-header">
<h1>Basic Fuzzing</h1>
</div>
<p>
The combination of pathoc's powerful request specification language and a few of
its command-line options makes for quite a powerful basic fuzzer. Here's
an example:
</p>
<pre class="terminal">
&gt; pathoc -e -I 200 -t 2 -n 1000 localhost get:/:b@10:ir,@1
</pre>
<p>
The request specified here is a valid GET with a body consisting of 10 random bytes,
but with 1 random byte inserted in a random place. This could be in the headers,
in the initial request line, or in the body itself. There are a few things
to note here:
</p>
<ul>
<li>
Corrupting the request in this way will often make the server enter a state where
it's awaiting more input from the client. This is where the
<b>-t</b> option comes in, which sets a timeout that causes pathoc to
disconnect after two seconds.
</li>
<li>
The <b>-n</b> option tells pathoc to repeat the request 1000 times.
</li>
<li>
The <b>-I</b> option tells pathoc to ignore HTTP 200 response codes.
You can use this to fine-tune what pathoc considers to be an exceptional
condition, and therefore log-worthy.
</li>
<li>
The <b>-e</b> option tells pathoc to print an explanation of each logged
request, in the form of an expanded pathoc specification with all random
portions and automatic header additions resolved. This lets you precisely
replay a request that triggered an error.
</li>
</ul>
</section>
<section>
<div class="page-header">
<h1>Interacting with Proxies</h1>
</div>
<p>
Pathoc has a reasonably sophisticated suite of features for interacting with proxies.
The proxy request syntax very closely mirrors that of straight HTTP, which
means that it is possible to make proxy-style requests using pathoc without
any additional syntax, by simply specifying a full URL instead of a simple
path:
</p>
<pre class="terminal">&gt; pathoc -p 8080 localhost "get:'http://google.com'"</pre>
<p>
Another common use case is to use an HTTP CONNECT request to probe remote servers
via a proxy. This is done with the <b>-c</b> command-line option,
which allows you to specify a remote host and port pair:
</p>
<pre class="terminal">&gt; pathoc -c google.com:80 -p 8080 localhost get:/</pre>
<p>
Note that pathoc does <b>not</b> negotiate SSL without being explictly instructed
to do so. If you're making a CONNECT request to an SSL-protected resource,
you must also pass the <b>-s</b> flag:
</p>
<pre class="terminal">&gt; pathoc -sc google.com:443 -p 8080 localhost get:/</pre>
</section>
<section>
<div class="page-header">
<h1>Embedded response specification</h1>
</div>
<p>
One interesting feature of the Request sppecification language is that you can embed
a response specifcation in it, which is then added to the request path. Here's
an example:
</p>
<pre class="terminal">&gt; pathoc localhost:9999 "get:/p/:s'401:ir,@1'"</pre>
<p>
This crafts a request that connects to the pathod server, and which then crafts a
response that generates a 401, with one random byte embedded at a random
point. The response specification is parsed and expanded by pathoc, so you
see syntax errors immediately. This really becomes handy when combined with
the <b>-e</b> flag to show the expanded request:
</p>
<pre class="terminal">
&gt; > pathoc -e localhost:9999 "get:/p/:s'401:ir,@1'" >> Spec: get:/p/:s'401:i15,\'o\':h\'Content-Length\'=\'0\'':h'Content-Length'='0'
<< 401 Unoauthorized: 0 bytes </pre>
<p>
Note that the embedded response has been resolved <i>before</i> being sent
to the server, so that "ir,@1" (embed a random byte at a random location)
has become "i15,\'o\'" (embed the character "o" at offset 15). You now have
a pathoc request specification that is precisely reproducable, even with
random components. This feature comes in terribly handy when testing a proxy,
since you can now drive the server repsonse completely from the client, and
have a complete log of reproducible requests to analyse afterwards.
</p>
</section>
{% endblock %}

View File

@ -1,172 +0,0 @@
{% extends "docframe.html" %} {% block body %}
<div class="page-header">
<h1>
pathod
<small>A pathological web daemon.</small>
</h1>
</div>
<p>
Pathod is a pathological HTTP daemon designed to let you craft almost any conceivable
HTTP response, including ones that creatively violate the standards. HTTP responses
are specified using a
<a href="/docs/language">small, terse language</a>, which pathod shares with
its evil twin <a href="/docs/pathoc">pathoc</a>.
</p>
<section>
<div class="page-header">
<h1>Getting started</h1>
</div>
<p>To start playing with pathod, simply fire up the daemon:</p>
<pre class="terminal">./pathod</pre>
<p>
By default, the service listens on port 9999 of localhost. Pathod's documentation
is self-hosting, and the pathod daemon exposes an interface that lets you
play with the specifciation language, preview what responses and requests
would look like on the wire, and view internal logs. To access all of this,
just fire up your browser, and point it to the following URL:
</p>
<pre class="example">http://localhost:9999</pre>
<p>
The default crafting anchor point is the path <b>/p/</b>. Anything after
this URL prefix is treated as a response specifier. So, hitting the following
URL will generate an HTTP 200 response with 100 bytes of random data:
</p>
<pre class="example">http://localhost:9999/p/200:b@100</pre>
<p>
See the <a href="/docs/language">language documentation</a> to get (much)
fancier. The pathod daemon also takes a range of configuration options. To
view those, use the command-line help:
</p>
<pre class="terminal">./pathod --help</pre>
</section>
<section>
<div class="page-header">
<h1>Acting as a proxy</h1>
</div>
<p>
Pathod automatically responds to both straight HTTP and proxy requests. For proxy
requests, the upstream host is ignored, and the path portion of the URL is
used to match anchors. This lets you test software that supports a proxy
configuration by spoofing responses from upstream servers.
</p>
<p>
By default, we treat all proxy CONNECT requests as HTTPS traffic, serving the response
using either pathod's built-in certificates, or the cert/key pair specified
by the user. You can over-ride this behaviour if you're testing a client
that makes a non-SSL CONNECT request using the -C command-line option.
</p>
</section>
<section>
<div class="page-header">
<h1>Anchors</h1>
</div>
<p>
Anchors provide an alternative to specifying the response in the URL. Instead, you
attach a response to a pre-configured anchor point, specified with a regex.
When a URL matching the regex is requested, the specified response is served.
</p>
<pre class="terminal">./pathod -a "/foo=200"</pre>
<p>
Here, "/foo" is the regex specifying the anchor path, and the part after the "="
is a response specifier.
</p>
</section>
<section>
<div class="page-header">
<h1>File Access</h1>
</div>
<p>
There are two operators in the <a href="/docs/language">language</a> that
load contents from file - the <b>+</b> operator to load an entire request
specification from file, and the <b>&gt;</b> value specifier. In pathod,
both of these operators are restricted to a directory specified at startup,
or disabled if no directory is specified:</p>
<pre class="terminal">./pathod -d ~/staticdir"</pre>
</section>
<section>
<div class="page-header">
<h1>Internal Error Responses</h1>
</div>
<p>
Pathod uses the non-standard 800 response code to indicate internal errors, to distinguish
them from crafted responses. For example, a request to:
</p>
<pre class="example">http://localhost:9999/p/foo</pre>
<p>
... will return an 800 response because "foo" is not a valid page specifier.
</p>
</section>
<section>
<div class="page-header">
<h1>API</h1>
</div>
<p>
pathod exposes a simple API, intended to make it possible to drive and inspect the
daemon remotely for use in unit testing and the like.
</p>
<table class="table table-bordered">
<tbody>
<tr>
<td>
/api/clear_log
</td>
<td>
A POST to this URL clears the log buffer.
</td>
</tr>
<tr>
<td>
/api/info
</td>
<td>
Basic version and configuration info.
</td>
</tr>
<tr>
<td>
/api/log
</td>
<td>
Returns the current log buffer. At the moment the buffer size is 500 entries - when
the log grows larger than this, older entries are discarded.
The returned data is a JSON dictionary, with the form:
<pre>{ 'log': [ ENTRIES ] } </pre> You can preview the JSON data
returned for a log entry through the built-in web interface.
</td>
</tr>
</tbody>
</table>
</section>
{% endblock %}

View File

@ -1,50 +0,0 @@
{% extends "docframe.html" %} {% block body %}
<div class="page-header">
<h1>
pathod.test
<small>Using pathod in unit tests.</small>
</h1>
</div>
<p>The <b>pathod.test</b> module is a light, flexible testing layer for HTTP clients.
It works by firing up a Pathod instance in a separate thread, letting you use
Pathod's full abilities to generate responses, and then query Pathod's internal
logs to establish what happened. All the mechanics of startup, shutdown, finding
free ports and so forth are taken care of for you.
</p>
<p>The canonical docs can be accessed using pydoc: </p>
<pre class="terminal">pydoc pathod.test</pre>
<p>
The remainder of this page demonstrates some common interaction patterns using
<a href="http://nose.readthedocs.org/en/latest/">nose</a>. These examples are
also applicable with only minor modification to most commonly used Python testing
engines.
</p>
<section>
<div class="page-header">
<h1>Context Manager</h1>
</div>
{% include "examples_context.html" %}
</section>
<section>
<div class="page-header">
<h1>One instance per test</h1>
</div>
{% include "examples_setup.html" %}
</section>
<section>
<div class="page-header">
<h1>One instance per suite</h1>
</div>
{% include "examples_setupall.html" %}
</section>
{% endblock %}

View File

@ -1,39 +0,0 @@
{% extends "frame.html" %} {% block body %}
<section>
<div class="page-header">
<h1>pip</h1>
</div>
<p>The easiest way to install pathod is to use pip:</p>
<pre>pip install pathod</pre>
<p>
This will automatically pull in all the dependencies, and you should be good to go.
</p>
</section>
<section>
<div class="page-header">
<h1>github</h1>
</div>
<p>You can find the project source on GitHub:</p>
<div style="margin-top: 20px; margin-bottom: 20px">
<a class="btn btn-primary btn-large" href="https://github.com/mitmproxy/pathod">github.com/mitmproxy/pathod</a>
</div>
<p>Please also use the <a href="https://github.com/mitmproxy/pathod/issues">github issue tracker</a> to report bugs.</p>
</section>
<section>
<div class="page-header">
<h1>tarball</h1>
</div>
<div style="margin-top: 20px; margin-bottom: 20px">
<a class="btn btn-primary btn-large" href="https://github.com/downloads/mitmproxy/pathod/pathod-{{version}}.tar.gz">pathod-{{version}}.tar.gz</a>
</div>
</section>
{% endblock %}

View File

@ -1,24 +0,0 @@
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">pathod</span> <span class="kn">import</span> <span class="n">test</span>
<span class="k">def</span> <span class="nf">test_simple</span><span class="p">():</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Testing the requests module with</span>
<span class="sd"> a pathod context manager.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c"># Start pathod in a separate thread</span>
<span class="k">with</span> <span class="n">test</span><span class="o">.</span><span class="n">Daemon</span><span class="p">()</span> <span class="k">as</span> <span class="n">d</span><span class="p">:</span>
<span class="c"># Get a URL for a pathod spec</span>
<span class="n">url</span> <span class="o">=</span> <span class="n">d</span><span class="o">.</span><span class="n">p</span><span class="p">(</span><span class="s">&quot;200:b@100&quot;</span><span class="p">)</span>
<span class="c"># ... and request it</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="c"># Check the returned data</span>
<span class="k">assert</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span>
<span class="c"># Check pathod&#39;s internal log</span>
<span class="n">log</span> <span class="o">=</span> <span class="n">d</span><span class="o">.</span><span class="n">last_log</span><span class="p">()[</span><span class="s">&quot;request&quot;</span><span class="p">]</span>
<span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;PUT&quot;</span>
</pre></div>

View File

@ -1,32 +0,0 @@
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">pathod</span> <span class="kn">import</span> <span class="n">test</span>
<span class="k">class</span> <span class="nc">Test</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Testing the requests module with</span>
<span class="sd"> a pathod instance started for</span>
<span class="sd"> each test.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">d</span> <span class="o">=</span> <span class="n">test</span><span class="o">.</span><span class="n">Daemon</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">shutdown</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">test_simple</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c"># Get a URL for a pathod spec</span>
<span class="n">url</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">p</span><span class="p">(</span><span class="s">&quot;200:b@100&quot;</span><span class="p">)</span>
<span class="c"># ... and request it</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="c"># Check the returned data</span>
<span class="k">assert</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span>
<span class="c"># Check pathod&#39;s internal log</span>
<span class="n">log</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">last_log</span><span class="p">()[</span><span class="s">&quot;request&quot;</span><span class="p">]</span>
<span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;PUT&quot;</span>
</pre></div>

View File

@ -1,40 +0,0 @@
<div class="highlight"><pre><span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">from</span> <span class="nn">pathod</span> <span class="kn">import</span> <span class="n">test</span>
<span class="k">class</span> <span class="nc">Test</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Testing the requests module with</span>
<span class="sd"> a single pathod instance started</span>
<span class="sd"> for the test suite.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">setUpAll</span><span class="p">(</span><span class="n">cls</span><span class="p">):</span>
<span class="n">cls</span><span class="o">.</span><span class="n">d</span> <span class="o">=</span> <span class="n">test</span><span class="o">.</span><span class="n">Daemon</span><span class="p">()</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">tearDownAll</span><span class="p">(</span><span class="n">cls</span><span class="p">):</span>
<span class="n">cls</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">shutdown</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c"># Clear the pathod logs between tests</span>
<span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">clear_log</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">test_simple</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c"># Get a URL for a pathod spec</span>
<span class="n">url</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">p</span><span class="p">(</span><span class="s">&quot;200:b@100&quot;</span><span class="p">)</span>
<span class="c"># ... and request it</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="c"># Check the returned data</span>
<span class="k">assert</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span>
<span class="c"># Check pathod&#39;s internal log</span>
<span class="n">log</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">last_log</span><span class="p">()[</span><span class="s">&quot;request&quot;</span><span class="p">]</span>
<span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;PUT&quot;</span>
<span class="k">def</span> <span class="nf">test_two</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">assert</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">log</span><span class="p">()</span>
</pre></div>

View File

@ -1,7 +0,0 @@
{% extends "layout.html" %} {% block content %}
<div class="row">
<div class="span12">
{% block body %} {% endblock %}
</div>
</div>
{% endblock %}

View File

@ -1,60 +0,0 @@
{% extends "frame.html" %} {% block body %}
<div class="masthead">
<div class="container">
<h1>pathod: pathological HTTP</h1>
<p>Crafted malice for tormenting HTTP clients and servers</p>
<img src="/static/torture.png">
</div>
</div>
<div class="row">
<div class="span6">
<div>
<h2><a href="/docs/pathod">pathod</a></h2>
<p>A pathological web daemon.</p>
{% include "response_previewform.html" %}
<br>
</div>
</div>
<div class="span6">
<div>
<h2><a href="/docs/pathoc">pathoc</a></h2>
<p>A perverse HTTP client.</p>
{% include "request_previewform.html" %}
</div>
</div>
</div>
<section>
<div class="page-header">
<h1>Install</h1>
</div>
<div class="row">
<div class="span6">
<div>
<h2>pip</h2>
<pre>pip install pathod</pre>
</div>
</div>
<div class="span6">
<div>
<h2>source</h2>
<ul>
<li>Current release: <a href="http://mitmproxy.org/download/pathod-{{version}}.tar.gz">pathod {{version}}</a></li>
<li>GitHub: <a href="https://github.com/mitmproxy/pathod">github.com/mitmproxy/pathod</a></li>
</ul>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@ -1,75 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>pathod</title>
<link href="/static/bootstrap.min.css" rel="stylesheet">
<link href="/static/pathod.css" rel="stylesheet">
<link href="/static/syntax.css" rel="stylesheet">
<script src="/static/jquery-1.7.2.min.js"></script>
<script src="/static/jquery.scrollTo-min.js"></script>
<script src="/static/jquery.localscroll-min.js"></script>
<script src="/static/bootstrap.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
</style>
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="/index.html">pathod</a>
<div class="nav-collapse">
<ul class="nav">
<li {% if section=="main" %} class="active" {% endif %}><a href="/">home</a></li>
{% if not noapi %}
<li {% if section=="log" %} class="active" {% endif %}><a href="/log">log</a></li>
{% endif %}
<li {% if section=="docs" %} class="active" {% endif %}><a href="/docs/pathod">docs</a></li>
<li {% if section=="about" %} class="active" {% endif %}><a href="/about">about</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
{% block content %} {% endblock %}
<hr>
<footer>
<span>&copy; Aldo Cortesi 2015</span>
<span class="pull-right">[served with pathod]</span>
</footer>
</div>
</body>
<script>
$(function() {
$.localScroll({
duration: 300,
offset: {
top: -45
}
});
});
</script>
</html>

View File

@ -1,31 +0,0 @@
{% extends "frame.html" %} {% block body %}
<form style="float: right" method="POST" action="/log/clear">
<button type="submit" class="btn">clear</button>
</form>
<h1>Logs</h1>
<hr>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>id</th>
<th>method</th>
<th>path</th>
</tr>
</thead>
<tbody>
{% for i in log %}
<tr>
{% if i["type"] == 'error' %}
<td colspan="3">ERROR: {{ i["msg"] }}</td>
{% else %}
<td>{{ i["id"] }}</td>
<td>{{ i["request"]["method"] }}</td>
<td><a href="/log/{{ i[" id "] }}">{{ i["request"]["path"] }}</a></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -1,8 +0,0 @@
{% extends "frame.html" %} {% block body %}
<h2>Log entry {{ lid }}</h2>
<hr>
<pre>
{{ alog }}
</pre>
{% endblock %}

View File

@ -1,44 +0,0 @@
{% extends "frame.html" %} {% block body %}
<div class="page-header">
<h1>pathoc preview</h1>
</div>
<div style="margin-bottom: 20px" class="row">
<div class="span2 header">
Specification:
</div>
<div class="span10">
{% include "request_previewform.html" %}
</div>
</div>
{% if syntaxerror %}
<div class="row">
<div class="span2 header">
Error:
</div>
<div class="span10">
<p style="color: #ff0000">{{ syntaxerror }}</p>
<pre>{{ marked }}</pre>
</div>
</div>
{% elif error %}
<div class="row">
<div class="span2 header">
Error:
</div>
<div class="span10">
<p style="color: #ff0000">{{ error }}</p>
</div>
</div>
{% else %}
<div class="row">
<div class="span2 header">
Request:
</div>
<div class="span10">
<pre>{{ output }}</pre>
<p>Note: pauses are skipped when generating previews!</p>
</div>
</div>
{% endif %} {% endblock %}

View File

@ -1,53 +0,0 @@
<form style="margin-bottom: 0" class="form-inline" method="GET" action="/request_preview">
<input style="width: 18em" id="spec" name="spec" class="input-medium" value="{{spec}}"
placeholder="method:path:[features]">
<input type="submit" class="btn" value="preview">
</form>
<a class="innerlink" data-toggle="collapse" data-target="#requestexamples">examples</a>
<div id="requestexamples" class="collapse">
<p>
Check out the <a href="/docs/language">complete language docs</a>. Here are
some examples to get you started:
</p>
<table class="table table-bordered">
<tbody>
<tr>
<td><a href="/request_preview?spec=get:/">get:/</a></td>
<td>Get path /</td>
</tr>
<tr>
<td><a href="/request_preview?spec=get:/:b@100">get:/:b@100</a></td>
<td>100 random bytes as the body</td>
</tr>
<tr>
<td><a href='/request_preview?spec=get:/:h"Etag"="&apos;;drop table browsers;"'>get:/:h"Etag"="';drop table browsers;"</a></td>
<td>Add a header</td>
</tr>
<tr>
<td><a href='/request_preview?spec=get:/:u"&apos;;drop table browsers;"'>get:/:u"';drop table browsers;"</a></td>
<td>Add a User-Agent header</td>
</tr>
<tr>
<td><a href="/request_preview?spec=get:/:b@100:dr">get:/:b@100:dr</a></td>
<td>Drop the connection randomly</td>
</tr>
<tr>
<td>
<a href="/request_preview?spec="></a>
</td>
<td></td>
</tr>
<tr>
<td><a href="/request_preview?spec=get:/:b@100,ascii:ir,@1">get:/:b@100,ascii:ir,@1</a></td>
<td>100 ASCII bytes as the body, and randomly inject a random byte</td>
</tr>
<tr>
<td><a href="/request_preview?spec=ws:/">ws:/</a></td>
<td>Initiate a websocket handshake.</td>
</tr>
</tbody>
</table>
</div>

View File

@ -1,44 +0,0 @@
{% extends "frame.html" %} {% block body %}
<div class="page-header">
<h1>pathod preview</h1>
</div>
<div style="margin-bottom: 20px" class="row">
<div class="span2 header">
Specification:
</div>
<div class="span10">
{% include "response_previewform.html" %}
</div>
</div>
{% if syntaxerror %}
<div class="row">
<div class="span2 header">
Error:
</div>
<div class="span10">
<p style="color: #ff0000">{{ syntaxerror }}</p>
<pre>{{ marked }}</pre>
</div>
</div>
{% elif error %}
<div class="row">
<div class="span2 header">
Error:
</div>
<div class="span10">
<p style="color: #ff0000">{{ error }}</p>
</div>
</div>
{% else %}
<div class="row">
<div class="span2 header">
Response:
</div>
<div class="span10">
<pre>{{ output }}</pre>
<p>Note: pauses are skipped when generating previews!</p>
</div>
</div>
{% endif %} {% endblock %}

View File

@ -1,87 +0,0 @@
<form style="margin-bottom: 0" class="form-inline" method="GET" action="/response_preview">
<input style="width: 18em" id="spec" name="spec" class="input-medium" value="{{spec}}"
placeholder="code:[features]">
<input type="submit" class="btn" value="preview">
{% if not nocraft %}
<a href="#" id="submitspec" class="btn">go</a>
{% endif %}
</form>
<a class="innerlink" data-toggle="collapse" data-target="#responseexamples">examples</a>
<div id="responseexamples" class="collapse">
<p>
Check out the <a href="/docs/language">complete language docs</a>. Here are
some examples to get you started:
</p>
<table class="table table-bordered">
<tbody>
<tr>
<td><a href="/response_preview?spec=200">200</a></td>
<td>A basic HTTP 200 response.</td>
</tr>
<tr>
<td><a href="/response_preview?spec=200:r">200:r</a></td>
<td>A basic HTTP 200 response with no Content-Length header. This will
hang.
</td>
</tr>
<tr>
<td><a href="/response_preview?spec=200:da">200:da</a></td>
<td>Server-side disconnect after all content has been sent.</td>
</tr>
<tr>
<td><a href="/response_preview?spec=200:b@100">200:b@100</a></td>
<td>
100 random bytes as the body. A Content-Lenght header is added, so the disconnect
is no longer needed.
</td>
</tr>
<tr>
<td><a href='/response_preview?spec=200:b@100:h"Server"="&apos;;drop table servers;"'>200:b@100:h"Etag"="';drop table servers;"</a></td>
<td>Add a Server header</td>
</tr>
<tr>
<td><a href="/response_preview?spec=200:b@100:dr">200:b@100:dr</a></td>
<td>Drop the connection randomly</td>
</tr>
<tr>
<td><a href="/response_preview?spec=200:b@100,ascii:ir,@1">200:b@100,ascii:ir,@1</a></td>
<td>100 ASCII bytes as the body, and randomly inject a random byte</td>
</tr>
<tr>
<td><a href='/response_preview?spec=200:b@1k:c"text/json"'>200:b@1k:c"text/json"</a></td>
<td>1k of random bytes, with a text/json content type</td>
</tr>
<tr>
<td><a href='/response_preview?spec=200:b@1k:p50,120'>200:b@1k:p50,120</a></td>
<td>1k of random bytes, pause for 120 seconds after 50 bytes</td>
</tr>
<tr>
<td><a href='/response_preview?spec=200:b@1k:pr,f'>200:b@1k:pr,f</a></td>
<td>1k of random bytes, but hang forever at a random location</td>
</tr>
<tr>
<td>
<a href="/response_preview?spec=200:b@100:h@1k,ascii_letters='foo'">200:b@100:h@1k,ascii_letters='foo'</a>
</td>
<td>
100 ASCII bytes as the body, randomly generated 100k header name, with the value
'foo'.
</td>
</tr>
</tbody>
</table>
</div>
{% if not nocraft %}
<script>
$(function() {
$("#submitspec").click(function() {
document.location = "{{craftanchor}}" + $("#spec").val()
});
});
</script>
{% endif %}