Repository: abhinavsingh/proxy.py
Pull request #1078 (2022-01-30 20:10:58)

Allow multiport with ephemeral & unix socket support

codecov[bot]: # [Codecov](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh) Report
> Merging [#1078](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh) (b1f08b2) into [develop](https://codecov.io/gh/abhinavsingh/proxy.py/commit/de36c6089ba5eba7d92762e2b47013cbc21f252d?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh) (de36c60) will **decrease** coverage by `6.91%`.
> The diff coverage is `35.00%`.

[![Impacted file tree graph](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/graphs/tree.svg?width=650&height=150&src=pr&token=Zh9J7b4la2&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh)](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh)

```diff
@@             Coverage Diff             @@
##           develop    #1078      +/-   ##
===========================================
- Coverage    87.48%   80.57%   -6.92%     
===========================================
  Files          166      166              
  Lines         6953     6964      +11     
  Branches       700      647      -53     
===========================================
- Hits          6083     5611     -472     
- Misses         756     1221     +465     
- Partials       114      132      +18     
```

| Flag | Coverage Δ | |
|---|---|---|
| pytest | `80.57% <35.00%> (-6.75%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh) | Coverage Δ | |
|---|---|---|
| [proxy/core/listener/base.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvY29yZS9saXN0ZW5lci9iYXNlLnB5) | `93.33% <ø> (-0.61%)` | :arrow_down: |
| [proxy/proxy.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvcHJveHkucHk=) | `84.84% <30.76%> (-14.33%)` | :arrow_down: |
| [proxy/core/listener/unix.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvY29yZS9saXN0ZW5lci91bml4LnB5) | `52.38% <33.33%> (-47.62%)` | :arrow_down: |
| [proxy/core/listener/tcp.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvY29yZS9saXN0ZW5lci90Y3AucHk=) | `100.00% <100.00%> (ø)` | |
| [proxy/http/server/reverse.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvaHR0cC9zZXJ2ZXIvcmV2ZXJzZS5weQ==) | `0.00% <0.00%> (-92.86%)` | :arrow_down: |
| [proxy/core/work/threadless.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvY29yZS93b3JrL3RocmVhZGxlc3MucHk=) | `18.71% <0.00%> (-64.54%)` | :arrow_down: |
| [proxy/core/work/pool.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvY29yZS93b3JrL3Bvb2wucHk=) | `35.00% <0.00%> (-56.67%)` | :arrow_down: |
| [proxy/core/work/fd/local.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvY29yZS93b3JrL2ZkL2xvY2FsLnB5) | `46.66% <0.00%> (-53.34%)` | :arrow_down: |
| [proxy/core/base/tcp\_upstream.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvY29yZS9iYXNlL3RjcF91cHN0cmVhbS5weQ==) | `47.05% <0.00%> (-52.95%)` | :arrow_down: |
| [proxy/plugin/modify\_chunk\_response.py](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh#diff-cHJveHkvcGx1Z2luL21vZGlmeV9jaHVua19yZXNwb25zZS5weQ==) | `50.00% <0.00%> (-50.00%)` | :arrow_down: |
| ... and [25 more](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh). Last update [de36c60...b1f08b2](https://codecov.io/gh/abhinavsingh/proxy.py/pull/1078?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Abhinav+Singh).


Patch:
diff --git a/proxy/core/listener/base.py b/proxy/core/listener/base.py
index 899538b..49357b3 100644
--- a/proxy/core/listener/base.py
+++ b/proxy/core/listener/base.py
@@ -8,7 +8,6 @@
     :copyright: (c) 2013-present by Abhinav Singh and contributors.
     :license: BSD, see LICENSE for more details.
 """
-import os
 import socket
 import logging
 import argparse
@@ -60,5 +59,3 @@ class BaseListener(ABC):
     def shutdown(self) -> None:
         assert self._socket
         self._socket.close()
-        if self.flags.unix_socket_path:
-            os.remove(self.flags.unix_socket_path)
diff --git a/proxy/core/listener/tcp.py b/proxy/core/listener/tcp.py
index 3000ae3..f841183 100644
--- a/proxy/core/listener/tcp.py
+++ b/proxy/core/listener/tcp.py
@@ -65,7 +65,10 @@ class TcpSocketListener(BaseListener):
         super().__init__(*args, **kwargs)
 
     def listen(self) -> socket.socket:
-        sock = socket.socket(self.flags.family, socket.SOCK_STREAM)
+        sock = socket.socket(
+            socket.AF_INET6 if self.flags.hostname.version == 6 else socket.AF_INET,
+            socket.SOCK_STREAM,
+        )
         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
         sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
         # s.setsockopt(socket.SOL_TCP, socket.TCP_FASTOPEN, 5)
diff --git a/proxy/core/listener/unix.py b/proxy/core/listener/unix.py
index fa84f96..4defd9a 100644
--- a/proxy/core/listener/unix.py
+++ b/proxy/core/listener/unix.py
@@ -8,6 +8,7 @@
     :copyright: (c) 2013-present by Abhinav Singh and contributors.
     :license: BSD, see LICENSE for more details.
 """
+import os
 import socket
 import logging
 
@@ -30,9 +31,8 @@ class UnixSocketListener(BaseListener):
     """Unix socket domain listener."""
 
     def listen(self) -> socket.socket:
-        sock = socket.socket(self.flags.family, socket.SOCK_STREAM)
+        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
         sock.bind(self.flags.unix_socket_path)
         sock.listen(self.flags.backlog)
         sock.setblocking(False)
@@ -41,3 +41,8 @@ class UnixSocketListener(BaseListener):
             self.flags.unix_socket_path,
         )
         return sock
+
+    def shutdown(self) -> None:
+        super().shutdown()
+        if self.flags.unix_socket_path:
+            os.remove(self.flags.unix_socket_path)
diff --git a/proxy/proxy.py b/proxy/proxy.py
index a6b6886..3ea2f4a 100644
--- a/proxy/proxy.py
+++ b/proxy/proxy.py
@@ -195,10 +195,24 @@ class Proxy:
         # Override flags.port to match the actual port
         # we are listening upon.  This is necessary to preserve
         # the server port when `--port=0` is used.
-        self.flags.port = cast(
-            'TcpSocketListener',
-            self.listeners.pool[0],
-        )._port
+        if not self.flags.unix_socket_path:
+            self.flags.port = cast(
+                'TcpSocketListener',
+                self.listeners.pool[0],
+            )._port
+        # --ports flag can also use 0 as value for ephemeral port selection.
+        # Here, we override flags.ports to reflect actual listening ports.
+        ports = []
+        offset = 1 if self.flags.unix_socket_path or self.flags.port else 0
+        for index in range(offset, offset + len(self.flags.ports)):
+            ports.append(
+                cast(
+                    'TcpSocketListener',
+                    self.listeners.pool[index],
+                )._port,
+            )
+        self.flags.ports = ports
+        # Write ports to port file
         self._write_port_file()
         # Setup EventManager
         if self.flags.enable_events:
@@ -278,7 +292,12 @@ class Proxy:
     def _write_port_file(self) -> None:
         if self.flags.port_file:
             with open(self.flags.port_file, 'wb') as port_file:
-                port_file.write(bytes_(self.flags.port))
+                if not self.flags.unix_socket_path:
+                    port_file.write(bytes_(self.flags.port))
+                    port_file.write(b'\n')
+                for port in self.flags.ports:
+                    port_file.write(bytes_(port))
+                    port_file.write(b'\n')
 
     def _delete_port_file(self) -> None:
         if self.flags.port_file \


Test patch:
diff --git a/tests/core/test_listener.py b/tests/core/test_listener.py
index 2ccfc82..4f3adf2 100644
--- a/tests/core/test_listener.py
+++ b/tests/core/test_listener.py
@@ -69,15 +69,11 @@ class TestListener(unittest.TestCase):
             socket.AF_UNIX,
             socket.SOCK_STREAM,
         )
-        self.assertEqual(sock.setsockopt.call_count, 2)
+        self.assertEqual(sock.setsockopt.call_count, 1)
         self.assertEqual(
             sock.setsockopt.call_args_list[0][0],
             (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1),
         )
-        self.assertEqual(
-            sock.setsockopt.call_args_list[1][0],
-            (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),
-        )
         sock.bind.assert_called_with(sock_path)
         sock.listen.assert_called_with(flags.backlog)
         sock.setblocking.assert_called_with(False)