Repository: streamlink/streamlink

Issue:
Drop `https-proxy` option in favor of a single `http-proxy` option
### Checklist

- [X] This is a feature request and not a different kind of issue
- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)
- [X] [I have checked the list of open and recently closed plugin requests](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22feature+request%22)

### Description

How much sense would it make dropping `https-proxy` in favor of only having the `http-proxy` option?

The reason [why these two options were added](f9ebaa8b33eac95f88d796ae779500f4b00f3c95) is `requests`, which requires proxy configs for each protocol/scheme separately. It also can take scheme+netloc strings as proxy configs, but Streamlink doesn't support setting configs like this via CLI arguments.

- https://github.com/streamlink/streamlink/blame/1a1a3a06a2655f299fd718f5343799ec13ec7ce4/src/streamlink/session.py#L233-L239
- https://docs.python-requests.org/en/latest/user/advanced/#proxies
- https://github.com/psf/requests/blob/v2.26.0/requests/sessions.py#L373-L376

This protocol-specific configuration in `requests` is based on [`urllib.request.getproxies()`](https://docs.python.org/3/library/urllib.request.html#urllib.request.getproxies), which [similar to cURL](https://man.archlinux.org/man/curl.1#ENVIRONMENT) supports the `NO_PROXY`, `HTTP_PROXY`, `HTTPS_PROXY` and `ALL_PROXY` env vars (all-uppercase or all-lowercase), [unless `trust_env` is set to `False`](https://github.com/psf/requests/blob/v2.26.0/requests/sessions.py#L701-L713) (which can be done in Streamlink via the `http-trust-env` option).

Added in 2f76a1b98b7a862fd7a850a5971b7c7a0abb0f36 was the logic for setting the value for `https-proxy` via `http-proxy` when `https-proxy` was not set yet, to make defining proxy configs less redundant and confusing.

But how much sense does it make having a separate option for HTTPS connections? Even though we have just switched to default HTTPS schemes for scheme-less input URLs in #4068, this doesn't mean that every request will be done via HTTPS if a plugin needs to make requests via HTTP for example or if the user has explicitly set the HTTP scheme in the input URL. **This allows for accidental connections via HTTP over the direct connection when only `https-proxy` is set, which is a problem.**

I also don't see any use case for having a configuration which sets one proxy for HTTP and another for HTTPS connections. It doesn't make any sense, especially when almost every connection is made via HTTPS/TLS anyway. [Streamlink CLI also doesn't support setting HTTPS proxies first](https://github.com/streamlink/streamlink/blob/1a1a3a06a2655f299fd718f5343799ec13ec7ce4/src/streamlink_cli/main.py#L707-L711), which makes the is-not-set condition in the Session's `http-proxy` option useless for Streamlink CLI, because it will always be true.

Another point is that every other HTTP option/argument does not have an HTTPS counterpart, which can be confusing for some users.

----

That's why I'd suggest:

- turning `https-proxy` into an alias for `http-proxy` and suppressing the CLI argument
- or dropping `https-proxy` entirely (breaking change)

`requests` would still pick up the env vars if set.


Discussion:
I don't see any ambiguity between them.  There are valid reasons for using an http proxy (non tls/ssl).   Example is intercept and injection.  
> There are valid reasons for using an http proxy (non tls/ssl).

I am not talking about dropping support for HTTP proxies. Re-read my post again. I am suggesting to only use one single parameter for both types, because having a parameter for each of them allows for accidental direct connections over HTTP if a plugin makes non-TLS HTTP requests and if the user has accidentally only set a proxy for HTTPS.

**`http-proxy` does NOT mean using a HTTP proxy for any kind of network request.** It means using any kind of supported proxy (HTTP, HTTPS, SOCKS, etc) for all non-TLS HTTP requests. Same thing for the `https-proxy` option, which means any kind of supported proxy for all HTTPS requests.

> Example is intercept and injection.

A HTTP proxy doesn't help you with MITM stuff if the underlying connection is encrypted via TLS.
> I am not talking about dropping support for HTTP proxies. Re-read my post again. 

I'm aware of what you're talking about, reread what I said.  If a plugin is using non-TLS and you expect it not to, that is a bug with the plugin not whether an environment variable or option was set.

> A HTTP proxy doesn't help you with MITM stuff if the underlying connection is encrypted via TLS.

K.  In the mean time I'm going to continue doing exactly that which you claim isn't possible.  Deal?     Regarding the change itself your choice.  If you remove the option it's just another patch I cherrypick out. 



@h1z1 do you often use two different proxies, or a proxy for https but not http? 
@beardypig Depends on the case but in general yes, different proxies, different configs (forward and tunnel).  There are cases where the host proxy isn't necessarily wanted to be the same.  FWIW I ripped out any mention of http/insecure urls a few years ago.  Proxy use in Python is a nightmare..  No sites [that I use/knowof] really broke upstream though.    

Resolving patch:
diff --git a/src/streamlink/session.py b/src/streamlink/session.py
--- a/src/streamlink/session.py
+++ b/src/streamlink/session.py
@@ -230,13 +230,11 @@ def set_option(self, key, value):
             else:
                 urllib3_connection.allowed_gai_family = allowed_gai_family
 
-        elif key == "http-proxy":
+        elif key in ("http-proxy", "https-proxy"):
             self.http.proxies["http"] = update_scheme("https://", value, force=False)
-            if "https" not in self.http.proxies:
-                self.http.proxies["https"] = update_scheme("https://", value, force=False)
-
-        elif key == "https-proxy":
-            self.http.proxies["https"] = update_scheme("https://", value, force=False)
+            self.http.proxies["https"] = self.http.proxies["http"]
+            if key == "https-proxy":
+                log.info("The https-proxy option has been deprecated in favour of a single http-proxy option")
 
         elif key == "http-cookies":
             if isinstance(value, dict):
diff --git a/src/streamlink_cli/argparser.py b/src/streamlink_cli/argparser.py
--- a/src/streamlink_cli/argparser.py
+++ b/src/streamlink_cli/argparser.py
@@ -1162,21 +1162,12 @@ def build_parser():
         "--http-proxy",
         metavar="HTTP_PROXY",
         help="""
-        A HTTP proxy to use for all HTTP requests, including WebSocket connections.
-        By default this proxy will be used for all HTTPS requests too.
+        A HTTP proxy to use for all HTTP and HTTPS requests, including WebSocket connections.
 
         Example: "http://hostname:port/"
         """
     )
-    http.add_argument(
-        "--https-proxy",
-        metavar="HTTPS_PROXY",
-        help="""
-        A HTTPS capable proxy to use for all HTTPS requests.
-
-        Example: "https://hostname:port/"
-        """
-    )
+    http.add_argument("--https-proxy", help=argparse.SUPPRESS)
     http.add_argument(
         "--http-cookie",
         metavar="KEY=VALUE",


Test patch:
diff --git a/tests/test_session.py b/tests/test_session.py
--- a/tests/test_session.py
+++ b/tests/test_session.py
@@ -358,21 +358,21 @@ def test_https_proxy_set_first(self):
         session.set_option("http-proxy", "http://testproxy.com")
 
         self.assertEqual("http://testproxy.com", session.http.proxies['http'])
-        self.assertEqual("https://testhttpsproxy.com", session.http.proxies['https'])
+        self.assertEqual("http://testproxy.com", session.http.proxies['https'])
 
     def test_https_proxy_default_override(self):
         session = self.subject(load_plugins=False)
         session.set_option("http-proxy", "http://testproxy.com")
         session.set_option("https-proxy", "https://testhttpsproxy.com")
 
-        self.assertEqual("http://testproxy.com", session.http.proxies['http'])
+        self.assertEqual("https://testhttpsproxy.com", session.http.proxies['http'])
         self.assertEqual("https://testhttpsproxy.com", session.http.proxies['https'])
 
     def test_https_proxy_set_only(self):
         session = self.subject(load_plugins=False)
         session.set_option("https-proxy", "https://testhttpsproxy.com")
 
-        self.assertFalse("http" in session.http.proxies)
+        self.assertEqual("https://testhttpsproxy.com", session.http.proxies['http'])
         self.assertEqual("https://testhttpsproxy.com", session.http.proxies['https'])
 
     def test_http_proxy_socks(self):
@@ -386,5 +386,5 @@ def test_https_proxy_socks(self):
         session = self.subject(load_plugins=False)
         session.set_option("https-proxy", "socks5://localhost:1234")
 
-        self.assertNotIn("http", session.http.proxies)
+        self.assertEqual("socks5://localhost:1234", session.http.proxies["http"])
         self.assertEqual("socks5://localhost:1234", session.http.proxies["https"])