aboutsummaryrefslogtreecommitdiffstats
path: root/libpathod/pathod.py
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2014-11-11 12:29:34 +0100
committerMaximilian Hils <git@maximilianhils.com>2014-11-11 12:29:34 +0100
commit8635e00175117d8574b4bea5edc1c43528ddf3e9 (patch)
tree1be23a6349a8fb81a89f8417b0b9d236d1829639 /libpathod/pathod.py
parentb917b61e6aead4f353ef15838315ecc0df721e29 (diff)
parent27c7e9e9345bbc458e7efc4093c2074e19011d12 (diff)
downloadmitmproxy-8635e00175117d8574b4bea5edc1c43528ddf3e9.tar.gz
mitmproxy-8635e00175117d8574b4bea5edc1c43528ddf3e9.tar.bz2
mitmproxy-8635e00175117d8574b4bea5edc1c43528ddf3e9.zip
Merge remote-tracking branch 'origin/master'
Conflicts: setup.py
Diffstat (limited to 'libpathod/pathod.py')
-rw-r--r--libpathod/pathod.py146
1 files changed, 117 insertions, 29 deletions
diff --git a/libpathod/pathod.py b/libpathod/pathod.py
index 79fe7ed1..173773cf 100644
--- a/libpathod/pathod.py
+++ b/libpathod/pathod.py
@@ -1,7 +1,12 @@
-import urllib, threading, re, logging, os
+import urllib
+import threading
+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"
@@ -12,7 +17,8 @@ CA_CERT_NAME = "mitmproxy-ca.pem"
logger = logging.getLogger('pathod')
-class PathodError(Exception): pass
+class PathodError(Exception):
+ pass
class SSLOptions:
@@ -64,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
@@ -162,15 +173,14 @@ 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])
- 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):
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(
@@ -182,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)
@@ -252,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.
@@ -276,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(self.request_settings, 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):
"""
@@ -363,3 +382,72 @@ class Pathod(tcp.TCPServer):
def get_log(self):
return self.log
+
+
+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 = args.ssl_certs
+ )
+
+ 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)
+
+ try:
+ pd = Pathod(
+ (args.address, args.port),
+ craftanchor = args.craftanchor,
+ ssl = args.ssl,
+ ssloptions = ssloptions,
+ staticdir = args.staticdir,
+ anchors = args.anchors,
+ sizelimit = args.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:
+ print >> sys.stderr, "Error: %s"%v
+ sys.exit(1)
+ except language.FileAccessDenied, v:
+ print >> sys.stderr, "Error: %s"%v
+
+ if args.daemonize:
+ utils.daemonize()
+
+ try:
+ print "%s listening on %s:%s"%(
+ version.NAMEVERSION,
+ pd.address.host,
+ pd.address.port
+ )
+ pd.serve_forever()
+ except KeyboardInterrupt:
+ pass