aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README140
-rw-r--r--libpathod/rparse.py10
-rw-r--r--notes42
-rwxr-xr-xpathod2
-rw-r--r--todo4
5 files changed, 149 insertions, 49 deletions
diff --git a/README b/README
new file mode 100644
index 00000000..3e25d581
--- /dev/null
+++ b/README
@@ -0,0 +1,140 @@
+
+Pathod
+======
+
+Pathod is a pathological HTTP/S daemon, useful for testing and torturing client
+software. At Pathod's core is a small, terse language for crafting HTTP
+responses. The simplest way to use Pathod is to fire up the daemon, and specify
+the respnse behaviour you want in the request URL, like this:
+
+ http://localhost:9999/p/200
+
+Everything below the magic "/p/" path component is a response specifier - in
+this case we're just specifying a vanilly 200 OK response, see the docs below
+to get fancier. You can also add anchors to the Pathod server that serve a
+fixed response whenever a path matching a specified URL is requested:
+
+ pathod --anchor /foo=200
+
+Here, the part before the "=" is a regex specifying the anchor path, and the
+part after is again a response specifier.
+
+Pathod has a nifty web interface built in, which exposes activity logs, online
+help and various other goodies. Try it by visiting the server root:
+
+ http://localhost:9999
+
+
+
+Specifying Responses
+====================
+
+The general form of a response is as follows:
+
+ code[MESSAGE]:[colon-separated list of features]
+
+Here's the simplest possible response specification, returning just an HTTP 200
+OK message with no headers and no content:
+
+ 200
+
+We can embellish this a bit by specifying an optional custom HTTP response
+message. By default for a 200 response code, this is just "OK", but we can
+change it like this:
+
+ 200"YAY"
+
+The quoted string above is an example of a value specifier, a syntax that is
+used pervasively in the Pathod response specification language. In this case,
+we're specifying a literal string, but there are many other fun things we can
+do. For example, we can tell Pathod to generate 100k of random ASCII letters
+instead:
+
+ 200@100k,ascii_letters
+
+Full documentation on the value specification syntax can be found below.
+
+Following the response code specifier is a colon-separateed list of features.
+For instance, this specifies a response with a body consisting of 1 megabyte of
+random data:
+
+ 200:b@1m
+
+And this is the same response with an ETag header added:
+
+ 200:b@1m:h"Etag"="foo"
+
+Both the header name and the header value are full value specifiers. Here's the
+same response again, but with a 1k randomly generated header name:
+
+ 200:b@1m:h@1k,ascii_letters="foo"
+
+A few specific headers have shortcuts, because they're used so often. The
+shorcut for the content-type header is "c":
+
+ 200:b@1m:c"text/json"
+
+That's it for the basic response definition. Now we can start mucking with the
+responses to break clients. One common hard-to-test circumstance is hangs or
+slow responses. Pathod has a pause operator that you can use to define
+precisely when and how long the server should hang. Here, for instance, we hang
+for 120 seconds after sending 50 bytes (counted from the first byte of the HTTP
+response):
+
+ 200:b@1m:p120,50
+
+If that's not long enough, we can tell Pathod to hang forever:
+
+ 200:b@1m:p120,f
+
+Or to send all data, and then hang without disconnecting:
+
+ 200:b@1m:p120,a
+
+We can also ask Pathod to hang randomly:
+
+ 200:b@1m:pr,a
+
+Pathod has a similar mechanism for simply dropping a connection mid-response.
+So we can tell Pathod to disconnect after sending 50 bytes:
+
+ 200:b@1m:d50
+
+Or randomly:
+
+ 200:b@1m:dr
+
+All of these features can be combined. Here's a response that pauses twice,
+then hangs:
+
+ 200:b@1m:p10,10:p20,10:d5000
+
+
+Features
+========
+
+ hVALUE=VALUE Set header
+ bVALUE Set body
+ cVALUE Set Content-Type header
+ lVALUE Set Location header
+
+ dOFF|r Disconnect after OFF bytes, measured from the beginning of the response.
+ pNUM|f,OFF|r|a Pause for NUM seconds after OFF bytes.
+
+
+Value Specifiers
+----------------
+
+ @500k - 500k of random data
+ @500k,utf8 - 500k of utf8. Other specifiers: utf8,alphanum,alpha,printable
+ "foo" - literal
+ <path - load from path under data directory
+ <"path" - load from path under data directory
+
+
+Anchors
+=======
+
+ Passed on command-line:
+ -a "/foo/bar=200:!/foo"
+
diff --git a/libpathod/rparse.py b/libpathod/rparse.py
index 8a461180..d3b3dbb5 100644
--- a/libpathod/rparse.py
+++ b/libpathod/rparse.py
@@ -344,7 +344,7 @@ class Response:
version = "HTTP/1.1"
code = 200
msg = LiteralGenerator(http.RESPONSES[code])
- body = LiteralGenerator("OK")
+ body = LiteralGenerator("")
def __init__(self):
self.headers = []
self.actions = []
@@ -429,6 +429,7 @@ class Response:
sofar += len(d)
skip = 0
fp.finish()
+ fp.connection.stream.close()
def serve(self, fp):
started = time.time()
@@ -454,10 +455,9 @@ class Response:
"\r\n",
]
vals.extend(hdrs)
- vals.extend([
- "\r\n",
- self.body
- ])
+ vals.append("\r\n")
+ if self.body:
+ vals.append(self.body)
vals.reverse()
actions = self.ready_actions(self.length(), self.actions)
actions.reverse()
diff --git a/notes b/notes
deleted file mode 100644
index 632c5064..00000000
--- a/notes
+++ /dev/null
@@ -1,42 +0,0 @@
-
-Response:
-
- code[msg]:[colon-separated features]
-
-
-Features:
-
- hVALUE=VALUE Set header
- bVALUE Set body
- cVALUE Set Content-Type header
- lVALUE Set Location header
-
- dOFF|r Disconnect after OFF bytes, measured from the beginning of the response.
- pNUM|f,OFF|r|a Pause for NUM seconds after OFF bytes.
-
-Value Specifiers:
-
- @500k - 500k of random data
- @500k,utf8 - 500k of utf8. Other specifiers: utf8,alphanum,alpha,printable
- "foo" - literal
- <path - load from path under data directory
- <"path" - load from path under data directory
-
-
-Examples:
- 200:b500k
- 404:pb5:b1k,printable
- 200:t"text/json":pr5:b1k
- 200:b1k:xr
-
-
-Anchors:
-
- Passed on command-line:
- -a "/foo/bar=200:!/foo"
-
-
-Built-in help
-
- /help
- /explain/expression
diff --git a/pathod b/pathod
index fd321da1..cae06e4a 100755
--- a/pathod
+++ b/pathod
@@ -5,7 +5,7 @@ import tornado.ioloop
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Process some integers.')
- parser.add_argument("-p", dest='port', default=8888, type=int, help='Port.')
+ parser.add_argument("-p", dest='port', default=9999, type=int, help='Port.')
parser.add_argument(
"-a", dest='anchors', default=[], type=str, action="append",
help='Add an anchor. Specified as a string with the form pattern=pagespec'
diff --git a/todo b/todo
index f38847da..b9ac5c4b 100644
--- a/todo
+++ b/todo
@@ -1,6 +1,8 @@
0.1:
- - Logs
+ - Test pause at 0 bytes
+ - Web help document
+ - README
- API
- Logs, log reset, log retrieval
- Anchor management