Repository: mitmproxy/mitmproxy

Issue:
[mitmweb] CTRL-C not working
##### Steps to reproduce the problem:

1.Start mitmweb
2.Try to shutdown with CTRL-C
3.Nothing happens


##### Any other comments? What have you tried so far?

With the signal handler not being implemented on Windows, CTRL-C on mitmweb is not doing anything. On top of that the message "Proxy server listening on ..." doesn't appear anymore.

I found this workaround that I tested myself : 
https://stackoverflow.com/questions/27480967/why-does-the-asyncios-event-loop-suppress-the-keyboardinterrupt-on-windows

It's working, it's just that it's not a clean exit of the program


##### System information

<!-- Paste the output of "mitmproxy --version" here. -->
![mitmdump_version](https://user-images.githubusercontent.com/15815157/38858134-336ea1ce-422b-11e8-917a-a329e97591ab.JPG)


<!-- Please use the mitmproxy forums (https://discourse.mitmproxy.org/) for support/how-to questions. Thanks! :) -->



Discussion:

Resolving patch:
diff --git a/mitmproxy/net/tcp.py b/mitmproxy/net/tcp.py
--- a/mitmproxy/net/tcp.py
+++ b/mitmproxy/net/tcp.py
@@ -22,8 +22,6 @@
 # Python 3.6 for Windows is missing a constant
 IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41)
 
-EINTR = 4
-
 
 class _FileLike:
     BLOCKSIZE = 1024 * 32
@@ -595,14 +593,7 @@ def serve_forever(self, poll_interval=0.1):
         self.__is_shut_down.clear()
         try:
             while not self.__shutdown_request:
-                try:
-                    r, w_, e_ = select.select(
-                        [self.socket], [], [], poll_interval)
-                except select.error as ex:  # pragma: no cover
-                    if ex[0] == EINTR:
-                        continue
-                    else:
-                        raise
+                r, w_, e_ = select.select([self.socket], [], [], poll_interval)
                 if self.socket in r:
                     connection, client_address = self.socket.accept()
                     t = basethread.BaseThread(
diff --git a/mitmproxy/tools/web/app.py b/mitmproxy/tools/web/app.py
--- a/mitmproxy/tools/web/app.py
+++ b/mitmproxy/tools/web/app.py
@@ -18,7 +18,6 @@
 from mitmproxy import log
 from mitmproxy import version
 from mitmproxy import optmanager
-from mitmproxy.tools.cmdline import CONFIG_PATH
 import mitmproxy.tools.web.master # noqa
 
 
@@ -457,10 +456,11 @@ def put(self):
 
 class SaveOptions(RequestHandler):
     def post(self):
-        try:
-            optmanager.save(self.master.options, CONFIG_PATH, True)
-        except Exception as err:
-            raise APIError(400, "{}".format(err))
+        # try:
+        #     optmanager.save(self.master.options, CONFIG_PATH, True)
+        # except Exception as err:
+        #     raise APIError(400, "{}".format(err))
+        pass
 
 
 class Application(tornado.web.Application):
diff --git a/mitmproxy/tools/web/master.py b/mitmproxy/tools/web/master.py
--- a/mitmproxy/tools/web/master.py
+++ b/mitmproxy/tools/web/master.py
@@ -105,33 +105,21 @@ def _sig_settings_update(self, options, updated):
 
     def run(self):  # pragma: no cover
         AsyncIOMainLoop().install()
-
         iol = tornado.ioloop.IOLoop.instance()
-
         http_server = tornado.httpserver.HTTPServer(self.app)
         http_server.listen(self.options.web_port, self.options.web_iface)
-
-        iol.add_callback(self.start)
-
         web_url = "http://{}:{}/".format(self.options.web_iface, self.options.web_port)
         self.log.info(
             "Web server listening at {}".format(web_url),
         )
-
+        # FIXME: This should be in an addon hooked to the "running" event, not in master
         if self.options.web_open_browser:
             success = open_browser(web_url)
             if not success:
                 self.log.info(
                     "No web browser found. Please open a browser and point it to {}".format(web_url),
                 )
-        try:
-            iol.start()
-        except KeyboardInterrupt:
-            self.shutdown()
-
-    def shutdown(self):
-        tornado.ioloop.IOLoop.instance().stop()
-        super().shutdown()
+        self.run_loop(iol.start)
 
 
 def open_browser(url: str) -> bool:


Test patch: