Repository: mitmproxy/mitmproxy

Issue:
HTTP2: Cannot change host in-flight
##### Steps to reproduce the problem:
1. Start mitmdump with the following inline script:

``` python
def request(flow):
    if flow.request.host == "google.com":
        flow.request.host = "example.com"
```
1. Use a HTTP2-capable browser to open https://google.com
##### What is the expected behavior?

Requests should be redirected to example.com.
##### What went wrong?

Requests are answered by google.com, even though the UI indicates example.com.
##### Any other comments? What have you tried so far?

This issue can be mitigated by passing `--no-http2`.
Implementing host change for HTTP2 is super tricky, so we may not go for this right now. 
However, the user should get a visible notification when changing hosts and the request should probably be aborted.

---

Mitmproxy Version: master
Operating System: Win10 x64

HTTP2: Cannot change host in-flight
##### Steps to reproduce the problem:
1. Start mitmdump with the following inline script:

``` python
def request(flow):
    if flow.request.host == "google.com":
        flow.request.host = "example.com"
```
1. Use a HTTP2-capable browser to open https://google.com
##### What is the expected behavior?

Requests should be redirected to example.com.
##### What went wrong?

Requests are answered by google.com, even though the UI indicates example.com.
##### Any other comments? What have you tried so far?

This issue can be mitigated by passing `--no-http2`.
Implementing host change for HTTP2 is super tricky, so we may not go for this right now. 
However, the user should get a visible notification when changing hosts and the request should probably be aborted.

---

Mitmproxy Version: master
Operating System: Win10 x64



Discussion:

Resolving patch:
diff --git a/mitmproxy/exceptions.py b/mitmproxy/exceptions.py
--- a/mitmproxy/exceptions.py
+++ b/mitmproxy/exceptions.py
@@ -103,6 +103,10 @@ class ControlException(ProxyException):
     pass
 
 
+class SetServerNotAllowedException(ProxyException):
+    pass
+
+
 class OptionsError(Exception):
     pass
 
diff --git a/mitmproxy/protocol/http2.py b/mitmproxy/protocol/http2.py
--- a/mitmproxy/protocol/http2.py
+++ b/mitmproxy/protocol/http2.py
@@ -109,15 +109,6 @@ def _initiate_server_conn(self):
         self.server_conn.send(self.server_conn.h2.data_to_send())
         self.active_conns.append(self.server_conn.connection)
 
-    def connect(self):  # pragma: no cover
-        raise exceptions.Http2ProtocolException("HTTP2 layer should already have a connection.")
-
-    def set_server(self):  # pragma: no cover
-        raise exceptions.Http2ProtocolException("Cannot change server for HTTP2 connections.")
-
-    def disconnect(self):  # pragma: no cover
-        raise exceptions.Http2ProtocolException("Cannot dis- or reconnect in HTTP2 connections.")
-
     def next_layer(self):  # pragma: no cover
         # WebSockets over HTTP/2?
         # CONNECT for proxying?
@@ -382,15 +373,20 @@ def __init__(self, ctx, stream_id, request_headers):
         self.priority_weight = None
         self.handled_priority_event = None
 
+    def connect(self):  # pragma: no cover
+        raise exceptions.Http2ProtocolException("HTTP2 layer should already have a connection.")
+
+    def disconnect(self):  # pragma: no cover
+        raise exceptions.Http2ProtocolException("Cannot dis- or reconnect in HTTP2 connections.")
+
+    def set_server(self, address):  # pragma: no cover
+        raise exceptions.SetServerNotAllowedException(repr(address))
+
     def check_close_connection(self, flow):
         # This layer only handles a single stream.
         # RFC 7540 8.1: An HTTP request/response exchange fully consumes a single stream.
         return True
 
-    def set_server(self, *args, **kwargs):  # pragma: no cover
-        # do not mess with the server connection - all streams share it.
-        pass
-
     @property
     def data_queue(self):
         if self.response_arrived.is_set():
@@ -584,6 +580,8 @@ def run(self):
         except exceptions.ProtocolException as e:  # pragma: no cover
             self.log(repr(e), "info")
             self.log(traceback.format_exc(), "debug")
+        except exceptions.SetServerNotAllowedException as e:  # pragma: no cover
+            self.log("Changing the Host server for HTTP/2 connections not allowed: {}".format(e), "info")
         except exceptions.Kill:
             self.log("Connection killed", "info")
 


Test patch: