diff options
-rw-r--r-- | README | 140 | ||||
-rw-r--r-- | libpathod/rparse.py | 10 | ||||
-rw-r--r-- | notes | 42 | ||||
-rwxr-xr-x | pathod | 2 | ||||
-rw-r--r-- | todo | 4 |
5 files changed, 149 insertions, 49 deletions
@@ -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() @@ -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 @@ -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' @@ -1,6 +1,8 @@ 0.1: - - Logs + - Test pause at 0 bytes + - Web help document + - README - API - Logs, log reset, log retrieval - Anchor management |