Repository: streamlink/streamlink

Issue:
Use of CLI parameter --http-ignore-env causes KeyError on all streams
### Checklist

- [X] This is a bug report 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 bug reports](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22bug%22)
- [X] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)

### Streamlink version

Latest build from the master branch

### Description

When using the parameter **--http-ignore-env** to ignore local environment variables for proxy, this always errors on any stream in the current/latest release. This worked on previous releases with no issues.
Any use of this CLI option gives an error `KeyError: 'http-trust-env'`

Test results below are from a common open non-DRM stream for m3u8 testing of
https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8

Test results were performed on Debian Bookworm with Python 3.11.2 and Streamlink 5.3.0+11.g77e67a70

### Debug log

```text
When using the optional CLI parameter of "--http-ignore-env" this errors as per the command output below

streamlink --loglevel=debug --http-ignore-env https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8 350p
[cli][debug] OS:         Linux-6.1.0-3-amd64-x86_64-with-glibc2.36
[cli][debug] Python:     3.11.2
[cli][debug] Streamlink: 5.3.0+11.g77e67a70
[cli][debug] Dependencies:
[cli][debug]  certifi: 2022.12.7
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.2
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.17
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.2
[cli][debug]  urllib3: 1.26.14
[cli][debug]  websocket-client: 1.5.1
[cli][debug] Arguments:
[cli][debug]  url=https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8
[cli][debug]  stream=['350p']
[cli][debug]  --loglevel=debug
[cli][debug]  --http-ignore-env=True
Traceback (most recent call last):
  File "/home/mason/.myenv/streamlink/bin/streamlink", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/mason/.myenv/streamlink/lib/python3.11/site-packages/streamlink_cli/main.py", line 895, in main
    setup_session_options(streamlink, args)
  File "/home/mason/.myenv/streamlink/lib/python3.11/site-packages/streamlink_cli/argparser.py", line 1294, in setup_session_options
    session.set_option(option, value)
  File "/home/mason/.myenv/streamlink/lib/python3.11/site-packages/streamlink/session.py", line 473, in set_option
    self.options.set(key, value)
  File "/home/mason/.myenv/streamlink/lib/python3.11/site-packages/streamlink/options.py", line 54, in set
    method(self, normalized, value)
  File "/home/mason/.myenv/streamlink/lib/python3.11/site-packages/streamlink/session.py", line 108, in _set_http_attr
    setattr(self.session.http, self._OPTIONS_HTTP_ATTRS[key], value)
                               ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^
KeyError: 'http-trust-env'


Exact same command without that CLI option works fine as per below.

streamlink --loglevel=debug https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8 350p
[cli][debug] OS:         Linux-6.1.0-3-amd64-x86_64-with-glibc2.36
[cli][debug] Python:     3.11.2
[cli][debug] Streamlink: 5.3.0+11.g77e67a70
[cli][debug] Dependencies:
[cli][debug]  certifi: 2022.12.7
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.2
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.17
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.2
[cli][debug]  urllib3: 1.26.14
[cli][debug]  websocket-client: 1.5.1
[cli][debug] Arguments:
[cli][debug]  url=https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8
[cli][debug]  stream=['350p']
[cli][debug]  --loglevel=debug
[cli][info] Found matching plugin hls for URL https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8
[plugins.hls][debug] URL=https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8; params={}
[utils.l10n][debug] Language code: en_GB
[cli][info] Available streams: 68k (worst), 140k, 100p, 200p, 350p, 750p_alt, 750p (best)
[cli][info] Opening stream: 350p (hls)
[cli][info] Starting player: /usr/bin/vlc
[stream.hls][debug] Reloading playlist
[cli][debug] Pre-buffering 8192 bytes
[stream.hls][debug] First Sequence: 1; Last Sequence: 184
[stream.hls][debug] Start offset: 0; Duration: None; Start Sequence: 1; End Sequence: 184
[stream.hls][debug] Adding segment 1 to queue
[stream.hls][debug] Adding segment 2 to queue
```



Discussion:
That has nothing to do with any stream or plugin implementations, it's a bug in the session initialization.

> This worked on previous releases with no issues.

Looks like this was introduced in 5.2.0 via #5076
https://github.com/streamlink/streamlink/blame/77e67a7002308dbb41a66c82f6e6fd6a4ff66e2b/src/streamlink/session.py#L40

The options key needs to be `http-trust-env`, not `http-ssl-trust-env`.

Resolving patch:
diff --git a/src/streamlink/session.py b/src/streamlink/session.py
--- a/src/streamlink/session.py
+++ b/src/streamlink/session.py
@@ -32,16 +32,6 @@ class PythonDeprecatedWarning(UserWarning):
 
 
 class StreamlinkOptions(Options):
-    _OPTIONS_HTTP_ATTRS = {
-        "http-cookies": "cookies",
-        "http-headers": "headers",
-        "http-query-params": "params",
-        "http-ssl-cert": "cert",
-        "http-ssl-trust-env": "trust_env",
-        "http-ssl-verify": "verify",
-        "http-timeout": "timeout",
-    }
-
     def __init__(self, session: "Streamlink", *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.session = session
@@ -144,6 +134,16 @@ def inner(self: "StreamlinkOptions", key: str, value: Any) -> None:
 
     # ----
 
+    _OPTIONS_HTTP_ATTRS = {
+        "http-cookies": "cookies",
+        "http-headers": "headers",
+        "http-query-params": "params",
+        "http-ssl-cert": "cert",
+        "http-ssl-verify": "verify",
+        "http-trust-env": "trust_env",
+        "http-timeout": "timeout",
+    }
+
     _MAP_GETTERS: ClassVar[Mapping[str, Callable[["StreamlinkOptions", str], Any]]] = {
         "http-proxy": _get_http_proxy,
         "https-proxy": _get_http_proxy,


Test patch:
diff --git a/tests/test_session.py b/tests/test_session.py
--- a/tests/test_session.py
+++ b/tests/test_session.py
@@ -525,6 +525,24 @@ def test_string(self, session: Streamlink, option: str, value: str):
         session.set_option(option, value)
 
 
+@pytest.mark.parametrize(
+    ("option", "attr", "default", "value"),
+    [
+        ("http-ssl-cert", "cert", None, "foo"),
+        ("http-ssl-verify", "verify", True, False),
+        ("http-trust-env", "trust_env", True, False),
+        ("http-timeout", "timeout", 20.0, 30.0),
+    ],
+)
+def test_options_http_other(session: Streamlink, option: str, attr: str, default, value):
+    httpsessionattr = getattr(session.http, attr)
+    assert httpsessionattr == default
+    assert session.get_option(option) == httpsessionattr
+
+    session.set_option(option, value)
+    assert session.get_option(option) == value
+
+
 class TestOptionsDocumentation:
     @pytest.fixture()
     def docstring(self, session: Streamlink):