aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2015-08-27 15:48:41 +0200
committerMaximilian Hils <git@maximilianhils.com>2015-08-27 15:48:41 +0200
commitecfde4247fcfd8279948b4a22bc4f04c2fb2ba15 (patch)
tree8e6524c523fe60e4d37dd093e15920c390359aa7 /libmproxy
parent0f97899fbd6cc68e974b1670e9c5188a28b52168 (diff)
downloadmitmproxy-ecfde4247fcfd8279948b4a22bc4f04c2fb2ba15.tar.gz
mitmproxy-ecfde4247fcfd8279948b4a22bc4f04c2fb2ba15.tar.bz2
mitmproxy-ecfde4247fcfd8279948b4a22bc4f04c2fb2ba15.zip
re-add http1 replay
Diffstat (limited to 'libmproxy')
-rw-r--r--libmproxy/protocol2/http.py90
1 files changed, 89 insertions, 1 deletions
diff --git a/libmproxy/protocol2/http.py b/libmproxy/protocol2/http.py
index e3878fa6..32c0116b 100644
--- a/libmproxy/protocol2/http.py
+++ b/libmproxy/protocol2/http.py
@@ -1,14 +1,18 @@
from __future__ import (absolute_import, print_function, division)
from .. import version
+import threading
from ..exceptions import InvalidCredentials, HttpException, ProtocolException
from .layer import Layer
from libmproxy import utils
+from libmproxy.controller import Channel
from libmproxy.protocol2.layer import Kill
-from libmproxy.protocol import KILL
+from libmproxy.protocol import KILL, Error
from libmproxy.protocol.http import HTTPFlow
from libmproxy.protocol.http_wrappers import HTTPResponse, HTTPRequest
+from libmproxy.proxy import Log
+from libmproxy.proxy.connection import ServerConnection
from netlib import tcp
from netlib.http import status_codes, http1, http2, HttpErrorConnClosed, HttpError
from netlib.http.semantics import CONTENT_MISSING
@@ -509,3 +513,87 @@ class HttpLayer(Layer):
odict.ODictCaseless([[k,v] for k, v in self.config.authenticator.auth_challenge_headers().items()])
))
raise InvalidCredentials("Proxy Authentication Required")
+
+
+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 is None or 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":
+ # FIXME
+ server_address = self.config.mode.get_upstream_server(
+ self.flow.client_conn
+ )[2:]
+ 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))
+ 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 is None or response_reply == KILL:
+ raise Kill()
+ except (HttpError, tcp.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