diff options
author | Maximilian Hils <git@maximilianhils.com> | 2015-09-02 01:16:48 +0200 |
---|---|---|
committer | Maximilian Hils <git@maximilianhils.com> | 2015-09-02 01:16:48 +0200 |
commit | c14fbc7794eee2a60d3c90f818ec481cf9db544b (patch) | |
tree | 529949dc40052291460b485142330932cf51819a /libmproxy/protocol/http_replay.py | |
parent | e8de7595c2e8a98418593e90b886e45a745e234a (diff) | |
parent | f1c8b47b1eb153d448061c0ddce21030c31af2b7 (diff) | |
download | mitmproxy-c14fbc7794eee2a60d3c90f818ec481cf9db544b.tar.gz mitmproxy-c14fbc7794eee2a60d3c90f818ec481cf9db544b.tar.bz2 mitmproxy-c14fbc7794eee2a60d3c90f818ec481cf9db544b.zip |
Merge pull request #741 from mitmproxy/proxy-refactor-cb
Proxy Refactor
Diffstat (limited to 'libmproxy/protocol/http_replay.py')
-rw-r--r-- | libmproxy/protocol/http_replay.py | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/libmproxy/protocol/http_replay.py b/libmproxy/protocol/http_replay.py new file mode 100644 index 00000000..2759a019 --- /dev/null +++ b/libmproxy/protocol/http_replay.py @@ -0,0 +1,96 @@ +from __future__ import (absolute_import, print_function, division) +import threading + +from netlib.http import HttpError +from netlib.http.http1 import HTTP1Protocol +from netlib.tcp import NetLibError +from ..controller import Channel +from ..models import Error, HTTPResponse, ServerConnection, make_connect_request +from .base import Log, Kill + + +# TODO: Doesn't really belong into libmproxy.protocol... + + +class RequestReplayThread(threading.Thread): + name = "RequestReplayThread" + + def __init__(self, config, flow, masterq, should_exit): + """ + masterqueue can be a queue or None, if no scripthooks should be + processed. + """ + self.config, self.flow = config, flow + if masterq: + self.channel = Channel(masterq, should_exit) + else: + self.channel = None + super(RequestReplayThread, self).__init__() + + def run(self): + r = self.flow.request + form_out_backup = r.form_out + try: + self.flow.response = None + + # If we have a channel, run script hooks. + if self.channel: + request_reply = self.channel.ask("request", self.flow) + if request_reply == Kill: + raise Kill() + elif isinstance(request_reply, HTTPResponse): + self.flow.response = request_reply + + if not self.flow.response: + # In all modes, we directly connect to the server displayed + if self.config.mode == "upstream": + server_address = self.config.upstream_server.address + server = ServerConnection(server_address) + server.connect() + protocol = HTTP1Protocol(server) + if r.scheme == "https": + connect_request = make_connect_request((r.host, r.port)) + server.send(protocol.assemble(connect_request)) + resp = protocol.read_response("CONNECT") + if resp.code != 200: + raise HttpError(502, "Upstream server refuses CONNECT request") + server.establish_ssl( + self.config.clientcerts, + sni=self.flow.server_conn.sni + ) + r.form_out = "relative" + else: + r.form_out = "absolute" + else: + server_address = (r.host, r.port) + server = ServerConnection(server_address) + server.connect() + protocol = HTTP1Protocol(server) + if r.scheme == "https": + server.establish_ssl( + self.config.clientcerts, + sni=self.flow.server_conn.sni + ) + r.form_out = "relative" + + server.send(protocol.assemble(r)) + self.flow.server_conn = server + self.flow.response = HTTPResponse.from_protocol( + protocol, + r.method, + body_size_limit=self.config.body_size_limit, + ) + if self.channel: + response_reply = self.channel.ask("response", self.flow) + if response_reply == Kill: + raise Kill() + except (HttpError, NetLibError) as v: + self.flow.error = Error(repr(v)) + if self.channel: + self.channel.ask("error", self.flow) + except Kill: + # KillSignal should only be raised if there's a channel in the + # first place. + self.channel.tell("log", Log("Connection killed", "info")) + finally: + r.form_out = form_out_backup |