diff options
Diffstat (limited to 'pathod')
-rw-r--r-- | pathod/app.py | 180 | ||||
-rw-r--r-- | pathod/pathod.py | 38 | ||||
-rw-r--r-- | pathod/protocols/http.py | 25 |
3 files changed, 19 insertions, 224 deletions
diff --git a/pathod/app.py b/pathod/app.py deleted file mode 100644 index e3216c58..00000000 --- a/pathod/app.py +++ /dev/null @@ -1,180 +0,0 @@ -import logging -import pprint -import io -import copy -from flask import Flask, jsonify, render_template, request, abort, make_response -from . import version, language -from netlib.http import user_agents -from netlib import strutils - -logging.basicConfig(level="DEBUG") -EXAMPLE_HOST = "example.com" -EXAMPLE_WEBSOCKET_KEY = "examplekey" - -# pylint: disable=unused-variable - - -def make_app(noapi, debug): - app = Flask(__name__) - app.debug = debug - - if not noapi: - @app.route('/api/info') - def api_info(): - return jsonify( - version=version.IVERSION - ) - - @app.route('/api/log') - def api_log(): - return jsonify( - log=app.config["pathod"].get_log() - ) - - @app.route('/api/clear_log') - def api_clear_log(): - app.config["pathod"].clear_log() - return "OK" - - def render(s, cacheable, **kwargs): - kwargs["noapi"] = app.config["pathod"].noapi - kwargs["nocraft"] = app.config["pathod"].nocraft - kwargs["craftanchor"] = app.config["pathod"].craftanchor - resp = make_response(render_template(s, **kwargs), 200) - if cacheable: - resp.headers["Cache-control"] = "public, max-age=4320" - return resp - - @app.route('/') - @app.route('/index.html') - def index(): - return render( - "index.html", - True, - section="main", - version=version.VERSION - ) - - @app.route('/download') - @app.route('/download.html') - def download(): - return render( - "download.html", True, section="download", version=version.VERSION - ) - - @app.route('/about') - @app.route('/about.html') - def about(): - return render("about.html", True, section="about") - - @app.route('/docs/pathod') - def docs_pathod(): - return render( - "docs_pathod.html", True, section="docs", subsection="pathod" - ) - - @app.route('/docs/language') - def docs_language(): - return render( - "docs_lang.html", True, - section="docs", uastrings=user_agents.UASTRINGS, - subsection="lang" - ) - - @app.route('/docs/pathoc') - def docs_pathoc(): - return render( - "docs_pathoc.html", True, section="docs", subsection="pathoc" - ) - - @app.route('/docs/lib_pathod') - def docs_lib_pathod(): - return render( - "docs_lib_pathod.html", True, section="docs", subsection="pathod" - ) - - @app.route('/docs/test') - def docs_test(): - return render( - "docs_test.html", True, section="docs", subsection="test" - ) - - @app.route('/log') - def log(): - if app.config["pathod"].noapi: - abort(404) - return render( - "log.html", - False, - section="log", - log=app.config["pathod"].get_log() - ) - - @app.route('/log/<int:lid>') - def onelog(lid): - item = app.config["pathod"].log_by_id(int(lid)) - if not item: - abort(404) - l = pprint.pformat(item) - return render("onelog.html", False, section="log", alog=l, lid=lid) - - def _preview(is_request): - if is_request: - template = "request_preview.html" - else: - template = "response_preview.html" - - spec = request.args["spec"] - - args = dict( - spec=spec, - section="main", - syntaxerror=None, - error=None, - ) - if not spec.strip(): - args["error"] = "Can't parse an empty spec." - return render(template, False, **args) - - try: - if is_request: - r = language.parse_pathoc(spec).next() - else: - r = language.parse_pathod(spec).next() - except language.ParseException as v: - args["syntaxerror"] = str(v) - args["marked"] = v.marked() - return render(template, False, **args) - - s = io.BytesIO() - - settings = copy.copy(app.config["pathod"].settings) - settings.request_host = EXAMPLE_HOST - settings.websocket_key = EXAMPLE_WEBSOCKET_KEY - - safe = r.preview_safe() - err, safe = app.config["pathod"].check_policy( - safe, - settings - ) - if err: - args["error"] = err - return render(template, False, **args) - if is_request: - settings.request_host = EXAMPLE_HOST - language.serve(safe, s, settings) - else: - settings.websocket_key = EXAMPLE_WEBSOCKET_KEY - language.serve(safe, s, settings) - - args["output"] = strutils.bytes_to_escaped_str(s.getvalue()) - return render(template, False, **args) - - @app.route('/response_preview') - def response_preview(): - return _preview(False) - - @app.route('/request_preview') - def request_preview(): - return _preview(True) - return app diff --git a/pathod/pathod.py b/pathod/pathod.py index 0449c0c1..add33944 100644 --- a/pathod/pathod.py +++ b/pathod/pathod.py @@ -10,7 +10,7 @@ from netlib import tcp, certutils, websockets from netlib.exceptions import HttpException, HttpReadDisconnect, TcpTimeout, TcpDisconnect, \ TlsException -from . import version, app, language, utils, log, protocols +from . import version, language, utils, log, protocols DEFAULT_CERT_DOMAIN = "pathod.net" @@ -136,7 +136,6 @@ class PathodHandler(tcp.BaseHandler): path = req.path http_version = req.http_version headers = req.headers - body = req.content clientcert = None if self.clientcert: @@ -203,24 +202,27 @@ class PathodHandler(tcp.BaseHandler): self.server.craftanchor )]) - if anchor_gen: - spec = anchor_gen.next() + if not anchor_gen: + anchor_gen = iter([self.make_http_error_response( + "Not found", + "No valid craft request found" + )]) - if self.use_http2 and isinstance(spec, language.http2.Response): - spec.stream_id = req.stream_id + spec = anchor_gen.next() - lg("crafting spec: %s" % spec) - nexthandler, retlog["response"] = self.http_serve_crafted( - spec, - lg - ) - if nexthandler and websocket_key: - self.protocol = protocols.websockets.WebsocketsProtocol(self) - return self.protocol.handle_websocket, retlog - else: - return nexthandler, retlog + if self.use_http2 and isinstance(spec, language.http2.Response): + spec.stream_id = req.stream_id + + lg("crafting spec: %s" % spec) + nexthandler, retlog["response"] = self.http_serve_crafted( + spec, + lg + ) + if nexthandler and websocket_key: + self.protocol = protocols.websockets.WebsocketsProtocol(self) + return self.protocol.handle_websocket, retlog else: - return self.protocol.handle_http_app(method, path, headers, body, lg) + return nexthandler, retlog def make_http_error_response(self, reason, body=None): resp = self.protocol.make_error_response(reason, body) @@ -343,8 +345,6 @@ class Pathod(tcp.TCPServer): self.explain = explain self.logfp = logfp - self.app = app.make_app(noapi, webdebug) - self.app.config["pathod"] = self self.log = [] self.logid = 0 self.anchors = anchors diff --git a/pathod/protocols/http.py b/pathod/protocols/http.py index d09b5bf2..6eefb34f 100644 --- a/pathod/protocols/http.py +++ b/pathod/protocols/http.py @@ -1,4 +1,3 @@ -from netlib import wsgi from netlib.exceptions import TlsException from netlib.http import http1 from .. import version, language @@ -11,30 +10,6 @@ class HTTPProtocol(object): def make_error_response(self, reason, body): return language.http.make_error_response(reason, body) - def handle_http_app(self, method, path, headers, body, lg): - """ - Handle a request to the built-in app. - """ - if self.pathod_handler.server.noweb: - crafted = self.pathod_handler.make_http_error_response("Access Denied") - language.serve(crafted, self.pathod_handler.wfile, self.pathod_handler.settings) - return None, dict( - type="error", - msg="Access denied: web interface disabled" - ) - lg("app: %s %s" % (method, path)) - req = wsgi.Request("http", method, path, b"HTTP/1.1", headers, body) - flow = wsgi.Flow(self.pathod_handler.address, req) - sn = self.pathod_handler.connection.getsockname() - a = wsgi.WSGIAdaptor( - self.pathod_handler.server.app, - sn[0], - self.pathod_handler.server.address.port, - version.NAMEVERSION - ) - a.serve(flow, self.pathod_handler.wfile) - return self.pathod_handler.handle_http_request, None - def handle_http_connect(self, connect, lg): """ Handle a CONNECT request. |