You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
5.4 KiB
179 lines
5.4 KiB
import os |
|
import mimetypes |
|
|
|
from .http import Request, Response |
|
from .util import PappyStringTransport, PappyException |
|
|
|
from twisted.test.proto_helpers import StringTransport |
|
from twisted.web.server import Site, NOT_DONE_YET |
|
from twisted.web import static |
|
from twisted.web.resource import Resource, NoResource |
|
from jinja2 import Environment, FileSystemLoader |
|
from twisted.internet import defer |
|
|
|
## The web server class |
|
|
|
class PappyWebServer(object): |
|
""" |
|
A class that is used to serve pages for requests to http://pappy. It is a |
|
ghetto wrapper around a twisted web Site object. Give it a request object |
|
and it will add a response to it. |
|
|
|
NOINDEX |
|
""" |
|
|
|
from pappyproxy.pappy import session |
|
site_dir = session.config.pappy_dir+'/site' |
|
loader = FileSystemLoader(site_dir) |
|
env = Environment(loader=loader) |
|
|
|
def __init__(self): |
|
root = RootResource(self.site_dir) |
|
self.site = Site(root) |
|
|
|
@staticmethod |
|
def render_template(*args, **kwargs): |
|
return PappyWebServer.env.get_template(args[0]).render(args[1:], **kwargs).encode('utf-8') |
|
|
|
@defer.inlineCallbacks |
|
def handle_request(self, req): |
|
protocol = self.site.buildProtocol(None) |
|
tr = PappyStringTransport() |
|
protocol.makeConnection(tr) |
|
protocol.dataReceived(req.full_request) |
|
tr.waitForProducers() |
|
## WORKING HERE |
|
# use loading functions to load response |
|
yield tr.complete_deferred |
|
rsp_raw = tr.value() |
|
rsp = Response(rsp_raw) |
|
req.response = rsp |
|
|
|
## functions |
|
def blocking_string_request(func): |
|
""" |
|
Wrapper for blocking request handlers in resources. The custom string |
|
transport has a deferred that must be called back when the messege is |
|
complete. If the message blocks though, you can just call it back right away |
|
|
|
NOINDEX |
|
""" |
|
def f(self, request): |
|
request.transport.complete_deferred.callback(None) |
|
return func(self, request) |
|
return f |
|
|
|
## Resources |
|
|
|
class PappyResource(Resource): |
|
""" |
|
Helper class for site resources. |
|
NOINDEX |
|
""" |
|
|
|
def getChild(self, name, request): |
|
if name == '': |
|
return self |
|
return Resource.getChild(self, name, request) |
|
|
|
class RootResource(PappyResource): |
|
|
|
def __init__(self, site_dir): |
|
PappyResource.__init__(self) |
|
self.site_dir = site_dir |
|
self.dirListing = False |
|
|
|
# Static resource |
|
self.static_resource = NoDirFile(self.site_dir + '/static') |
|
self.putChild('static', self.static_resource) |
|
|
|
# Cert download resource |
|
self.putChild('certs', CertResource()) |
|
|
|
# Response viewing resource |
|
self.putChild('rsp', ResponseResource()) |
|
|
|
@blocking_string_request |
|
def render_GET(self, request): |
|
return PappyWebServer.render_template('index.html') |
|
|
|
class NoDirFile(static.File): |
|
|
|
def directoryListing(self): |
|
return NoResource() |
|
|
|
@blocking_string_request |
|
def render_GET(self, request): |
|
return static.File.render_GET(self, request) |
|
|
|
## Cert resources |
|
|
|
class CertResource(PappyResource): |
|
|
|
def __init__(self): |
|
PappyResource.__init__(self) |
|
|
|
self.putChild('download', CertDownload()) |
|
|
|
@blocking_string_request |
|
def render_GET(self, request): |
|
return PappyWebServer.render_template('certs.html') |
|
|
|
class CertDownload(PappyResource): |
|
|
|
@blocking_string_request |
|
def render_GET(self, request): |
|
from .pappy import session |
|
|
|
cert_dir = session.config.cert_dir |
|
ssl_ca_file = session.config.ssl_ca_file |
|
with open(os.path.join(cert_dir, ssl_ca_file), 'r') as f: |
|
ca_raw = f.read() |
|
request.responseHeaders.addRawHeader("Content-Type", "application/x-x509-ca-cert") |
|
return ca_raw |
|
|
|
## View responses |
|
|
|
class ResponseResource(PappyResource): |
|
|
|
def getChild(self, name, request): |
|
if name == '': |
|
return self |
|
return ViewResponseResource(name) |
|
|
|
@blocking_string_request |
|
def render_GET(self, request): |
|
return PappyWebServer.render_template('viewrsp.html') |
|
|
|
class ViewResponseResource(PappyResource): |
|
|
|
def __init__(self, reqid): |
|
PappyResource.__init__(self) |
|
self.reqid = reqid |
|
|
|
def render_GET(self, request): |
|
d = Request.load_request(self.reqid) |
|
d.addCallback(self._render_response, request) |
|
d.addErrback(self._render_response_err, request) |
|
d.addCallback(lambda _: request.transport.complete_deferred.callback(None)) |
|
return NOT_DONE_YET |
|
|
|
def _render_response(self, req, tw_request): |
|
if req.response: |
|
if not req.response.body: |
|
raise PappyException("Response has no body") |
|
if 'content-type' in req.response.headers: |
|
tw_request.responseHeaders.addRawHeader("Content-Type", req.response.headers['content-type']) |
|
else: |
|
guess = mimetypes.guess_type(req.url) |
|
if guess[0]: |
|
tw_request.responseHeaders.addRawHeader("Content-Type", guess[0]) |
|
tw_request.write(req.response.body) |
|
else: |
|
tw_request.write(PappyWebServer.render_template('norsp.html')) |
|
tw_request.finish() |
|
|
|
def _render_response_err(self, err, tw_request): |
|
tw_request.write(PappyWebServer.render_template('norsp.html', errmsg=err.getErrorMessage())) |
|
tw_request.finish() |
|
err.trap(Exception)
|
|
|