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:
parent
2b19a33738
commit
e037fe05ff
|
@ -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;
|
||||
}
|
10
docs/conf.py
10
docs/conf.py
|
@ -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
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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'.
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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"><my/path</pre>
|
||||
|
||||
<p>The path value can also be a quoted string, with the same syntax as literals:</p>
|
||||
|
||||
<pre class="example"><"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 %}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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 %}
|
|
@ -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">
|
||||
> pathoc google.com get:/ << 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">
|
||||
> pathoc -s google.com get:/ << 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">
|
||||
> pathoc google.com get:/ get:/ << 301 Moved Permanently: 219 bytes <<
|
||||
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">
|
||||
> pathoc -n 2 google.com get:/ << 301 Moved Permanently: 219 bytes << 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">
|
||||
> pathoc -n 2 google.com get:/ get:/ << 301 Moved Permanently: 219 bytes <<
|
||||
301 Moved Permanently: 219 bytes << 301 Moved Permanently: 219 bytes <<
|
||||
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">
|
||||
> 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">> 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">> 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">> 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">> 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">
|
||||
> > 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 %}
|
|
@ -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>></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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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">"""</span>
|
||||
<span class="sd"> Testing the requests module with</span>
|
||||
<span class="sd"> a pathod context manager.</span>
|
||||
<span class="sd"> """</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">"200:b@100"</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'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">"request"</span><span class="p">]</span>
|
||||
<span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">"method"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"PUT"</span>
|
||||
</pre></div>
|
|
@ -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">"""</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"> """</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">"200:b@100"</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'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">"request"</span><span class="p">]</span>
|
||||
<span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">"method"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"PUT"</span>
|
||||
</pre></div>
|
|
@ -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">"""</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"> """</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">"200:b@100"</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'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">"request"</span><span class="p">]</span>
|
||||
<span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">"method"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"PUT"</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>
|
|
@ -1,7 +0,0 @@
|
|||
{% extends "layout.html" %} {% block content %}
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
{% block body %} {% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -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 %}
|
|
@ -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>© 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>
|
|
@ -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 %}
|
|
@ -1,8 +0,0 @@
|
|||
{% extends "frame.html" %} {% block body %}
|
||||
<h2>Log entry {{ lid }}</h2>
|
||||
<hr>
|
||||
|
||||
<pre>
|
||||
{{ alog }}
|
||||
</pre>
|
||||
{% endblock %}
|
|
@ -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 %}
|
|
@ -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"="';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"';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>
|
|
@ -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 %}
|
|
@ -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"="';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 %}
|
Loading…
Reference in New Issue