From 962a414327d93b604a59a4b8c8582d359745009d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 24 Oct 2014 14:01:34 +1300 Subject: Fix tests, re-add scripts --- libpathod/pathod.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'libpathod/pathod.py') diff --git a/libpathod/pathod.py b/libpathod/pathod.py index 79fe7ed1..ecf1cc7e 100644 --- a/libpathod/pathod.py +++ b/libpathod/pathod.py @@ -1,6 +1,11 @@ -import urllib, threading, re, logging, os +import urllib +import threading +import re +import logging +import os from netlib import tcp, http, wsgi, certutils import netlib.utils + import version, app, language, utils @@ -12,7 +17,8 @@ CA_CERT_NAME = "mitmproxy-ca.pem" logger = logging.getLogger('pathod') -class PathodError(Exception): pass +class PathodError(Exception): + pass class SSLOptions: -- cgit v1.2.3 From cd481fdd14a96afeb61ce5d2b8d899f24af1051f Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 24 Oct 2014 17:12:54 +1300 Subject: Refactor and whitespace --- libpathod/pathod.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'libpathod/pathod.py') diff --git a/libpathod/pathod.py b/libpathod/pathod.py index ecf1cc7e..25f072fa 100644 --- a/libpathod/pathod.py +++ b/libpathod/pathod.py @@ -369,3 +369,92 @@ class Pathod(tcp.TCPServer): def get_log(self): return self.log + + +def main(parser, args): + certs = [] + for i in args.ssl_certs: + parts = i.split("=", 1) + if len(parts) == 1: + parts = ["*", parts[0]] + parts[1] = os.path.expanduser(parts[1]) + if not os.path.exists(parts[1]): + parser.error("Certificate file does not exist: %s"%parts[1]) + certs.append(parts) + + ssloptions = SSLOptions( + cn = args.cn, + confdir = args.confdir, + not_after_connect = args.ssl_not_after_connect, + ciphers = args.ciphers, + sslversion = utils.SSLVERSIONS[args.sslversion], + certs = certs + ) + + alst = [] + for i in args.anchors: + parts = utils.parse_anchor_spec(i) + if not parts: + parser.error("Invalid anchor specification: %s"%i) + alst.append(parts) + + root = logging.getLogger() + if root.handlers: + for handler in root.handlers: + root.removeHandler(handler) + + log = logging.getLogger('pathod') + log.setLevel(logging.DEBUG) + fmt = logging.Formatter( + '%(asctime)s: %(message)s', + datefmt='%d-%m-%y %H:%M:%S', + ) + if args.logfile: + fh = logging.handlers.WatchedFileHandler(args.logfile) + fh.setFormatter(fmt) + log.addHandler(fh) + if not args.daemonize: + sh = logging.StreamHandler() + sh.setFormatter(fmt) + log.addHandler(sh) + + sizelimit = None + if args.sizelimit: + try: + sizelimit = utils.parse_size(args.sizelimit) + except ValueError, v: + parser.error(v) + + try: + pd = Pathod( + (args.address, args.port), + craftanchor = args.craftanchor, + ssl = args.ssl, + ssloptions = ssloptions, + staticdir = args.staticdir, + anchors = alst, + sizelimit = sizelimit, + noweb = args.noweb, + nocraft = args.nocraft, + noapi = args.noapi, + nohang = args.nohang, + timeout = args.timeout, + logreq = args.logreq, + logresp = args.logresp, + hexdump = args.hexdump, + explain = args.explain, + ) + except PathodError, v: + parser.error(str(v)) + except language.FileAccessDenied, v: + parser.error("%s You probably want to a -d argument."%str(v)) + + try: + print "%s listening on %s:%s"%( + version.NAMEVERSION, + pd.address.host, + pd.address.port + ) + pd.serve_forever() + except KeyboardInterrupt: + pass -- cgit v1.2.3 From c6c05098360c32dca82621cc4aaf91064f81e3f3 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 24 Oct 2014 17:19:55 +1300 Subject: Strictly separate argument parsing from main loops --- libpathod/pathod.py | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) (limited to 'libpathod/pathod.py') diff --git a/libpathod/pathod.py b/libpathod/pathod.py index 25f072fa..37b07bb6 100644 --- a/libpathod/pathod.py +++ b/libpathod/pathod.py @@ -3,6 +3,7 @@ import threading import re import logging import os +import sys from netlib import tcp, http, wsgi, certutils import netlib.utils @@ -371,33 +372,16 @@ class Pathod(tcp.TCPServer): return self.log -def main(parser, args): - certs = [] - for i in args.ssl_certs: - parts = i.split("=", 1) - if len(parts) == 1: - parts = ["*", parts[0]] - parts[1] = os.path.expanduser(parts[1]) - if not os.path.exists(parts[1]): - parser.error("Certificate file does not exist: %s"%parts[1]) - certs.append(parts) - +def main(args): ssloptions = SSLOptions( cn = args.cn, confdir = args.confdir, not_after_connect = args.ssl_not_after_connect, ciphers = args.ciphers, sslversion = utils.SSLVERSIONS[args.sslversion], - certs = certs + certs = args.ssl_certs ) - alst = [] - for i in args.anchors: - parts = utils.parse_anchor_spec(i) - if not parts: - parser.error("Invalid anchor specification: %s"%i) - alst.append(parts) - root = logging.getLogger() if root.handlers: for handler in root.handlers: @@ -418,13 +402,6 @@ def main(parser, args): sh.setFormatter(fmt) log.addHandler(sh) - sizelimit = None - if args.sizelimit: - try: - sizelimit = utils.parse_size(args.sizelimit) - except ValueError, v: - parser.error(v) - try: pd = Pathod( (args.address, args.port), @@ -432,8 +409,8 @@ def main(parser, args): ssl = args.ssl, ssloptions = ssloptions, staticdir = args.staticdir, - anchors = alst, - sizelimit = sizelimit, + anchors = args.anchors, + sizelimit = args.sizelimit, noweb = args.noweb, nocraft = args.nocraft, noapi = args.noapi, @@ -445,9 +422,13 @@ def main(parser, args): explain = args.explain, ) except PathodError, v: - parser.error(str(v)) + print >> sys.stderr, "Error: %s"%v + sys.exit(1) except language.FileAccessDenied, v: - parser.error("%s You probably want to a -d argument."%str(v)) + print >> sys.stderr, "Error: %s"%v + + if args.daemonize: + utils.daemonize() try: print "%s listening on %s:%s"%( -- cgit v1.2.3 From 5aadf92767614b7bd8e2ef677085410ac359e5e8 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 25 Oct 2014 08:18:39 +1300 Subject: Nicer way to specify patterns read for file - just use a path --- libpathod/pathod.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libpathod/pathod.py') diff --git a/libpathod/pathod.py b/libpathod/pathod.py index 37b07bb6..92e5b2db 100644 --- a/libpathod/pathod.py +++ b/libpathod/pathod.py @@ -169,7 +169,7 @@ class PathodHandler(tcp.BaseHandler): for i in self.server.anchors: if i[0].match(path): self.info("crafting anchor: %s" % path) - aresp = language.parse_response(self.server.request_settings, i[1]) + aresp = language.parse_response(i[1]) again, retlog["response"] = self.serve_crafted(aresp) return again, retlog @@ -177,7 +177,7 @@ class PathodHandler(tcp.BaseHandler): spec = urllib.unquote(path)[len(self.server.craftanchor):] self.info("crafting spec: %s" % spec) try: - crafted = language.parse_response(self.server.request_settings, spec) + crafted = language.parse_response(spec) except language.ParseException, v: self.info("Parse error: %s" % v.msg) crafted = language.make_error_response( @@ -299,7 +299,7 @@ class Pathod(tcp.TCPServer): except re.error: raise PathodError("Invalid regex in anchor: %s" % i[0]) try: - language.parse_response(self.request_settings, i[1]) + language.parse_response(i[1]) except language.ParseException, v: raise PathodError("Invalid page spec in anchor: '%s', %s" % (i[1], str(v))) self.anchors.append((arex, i[1])) -- cgit v1.2.3 From 00d0ee5ad56d8243b1e9bfffec9a941e11359d2c Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 25 Oct 2014 15:30:54 +1300 Subject: Parse patterns eagerly on instantiation --- libpathod/pathod.py | 66 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 27 deletions(-) (limited to 'libpathod/pathod.py') diff --git a/libpathod/pathod.py b/libpathod/pathod.py index 92e5b2db..173773cf 100644 --- a/libpathod/pathod.py +++ b/libpathod/pathod.py @@ -1,13 +1,12 @@ import urllib import threading -import re import logging import os import sys from netlib import tcp, http, wsgi, certutils import netlib.utils -import version, app, language, utils +from . import version, app, language, utils DEFAULT_CERT_DOMAIN = "pathod.net" @@ -71,7 +70,12 @@ class PathodHandler(tcp.BaseHandler): if self.server.explain and not isinstance(crafted, language.PathodErrorResponse): crafted = crafted.freeze(self.server.request_settings, None) self.info(">> Spec: %s" % crafted.spec()) - response_log = language.serve(crafted, self.wfile, self.server.request_settings, None) + response_log = language.serve( + crafted, + self.wfile, + self.server.request_settings, + None + ) if response_log["disconnect"]: return False, response_log return True, response_log @@ -169,8 +173,7 @@ class PathodHandler(tcp.BaseHandler): for i in self.server.anchors: if i[0].match(path): self.info("crafting anchor: %s" % path) - aresp = language.parse_response(i[1]) - again, retlog["response"] = self.serve_crafted(aresp) + again, retlog["response"] = self.serve_crafted(i[1]) return again, retlog if not self.server.nocraft and path.startswith(self.server.craftanchor): @@ -189,7 +192,10 @@ class PathodHandler(tcp.BaseHandler): elif self.server.noweb: crafted = language.make_error_response("Access Denied") language.serve(crafted, self.wfile, self.server.request_settings) - return False, dict(type="error", msg="Access denied: web interface disabled") + return False, dict( + type="error", + msg="Access denied: web interface disabled" + ) else: self.info("app: %s %s" % (method, path)) req = wsgi.Request("http", method, path, headers, content) @@ -259,19 +265,34 @@ class Pathod(tcp.TCPServer): LOGBUF = 500 def __init__( - self, addr, confdir=CONFDIR, ssl=False, ssloptions=None, - craftanchor="/p/", staticdir=None, anchors=None, - sizelimit=None, noweb=False, nocraft=False, noapi=False, - nohang=False, timeout=None, logreq=False, logresp=False, - explain=False, hexdump=False + self, + addr, + confdir=CONFDIR, + ssl=False, + ssloptions=None, + craftanchor="/p/", + staticdir=None, + anchors=(), + sizelimit=None, + noweb=False, + nocraft=False, + noapi=False, + nohang=False, + timeout=None, + logreq=False, + logresp=False, + explain=False, + hexdump=False ): """ addr: (address, port) tuple. If port is 0, a free port will be automatically chosen. ssloptions: an SSLOptions object. - craftanchor: string specifying the path under which to anchor response generation. + craftanchor: string specifying the path under which to anchor + response generation. staticdir: path to a directory of static resources, or None. - anchors: A list of (regex, spec) tuples, or None. + anchors: List of (regex object, language.Request object) tuples, or + None. sizelimit: Limit size of served data. nocraft: Disable response crafting. noapi: Disable the API. @@ -283,26 +304,17 @@ class Pathod(tcp.TCPServer): self.staticdir = staticdir self.craftanchor = craftanchor self.sizelimit = sizelimit - self.noweb, self.nocraft, self.noapi, self.nohang = noweb, nocraft, noapi, nohang - self.timeout, self.logreq, self.logresp, self.hexdump = timeout, logreq, logresp, hexdump + self.noweb, self.nocraft = noweb, nocraft + self.noapi, self.nohang = noapi, nohang + self.timeout, self.logreq = timeout, logreq + self.logresp, self.hexdump = logresp, hexdump self.explain = explain self.app = app.make_app(noapi) self.app.config["pathod"] = self self.log = [] self.logid = 0 - self.anchors = [] - if anchors: - for i in anchors: - try: - arex = re.compile(i[0]) - except re.error: - raise PathodError("Invalid regex in anchor: %s" % i[0]) - try: - language.parse_response(i[1]) - except language.ParseException, v: - raise PathodError("Invalid page spec in anchor: '%s', %s" % (i[1], str(v))) - self.anchors.append((arex, i[1])) + self.anchors = anchors def check_policy(self, req, settings): """ -- cgit v1.2.3