fix(clients): use port 443 for HTTPS Transmission URLs that omit a port (#1673)

## Why

Saving a Transmission address as HTTPS and leaving the port blank makes
the connection test fail. The client opens port 9091 and reports an SSL
wrong-version error, so a daemon published through a reverse proxy on
the usual HTTPS port never answers.

parse_transmission_url filled in 9091 whenever the URL omitted a port,
and that default ignored the scheme. An https address therefore started
TLS against 9091, where the peer is not speaking TLS.

## Summary

An omitted port now follows the scheme: 443 for https, and 9091 for
http, which still covers the empty-URL default. A port written in the
URL is left as given. The parser tests cover
https://transmission.myserver.org and expect https, that host, port 443,
and the path /transmission/rpc.

## Testing

The targeted tests for the shelfmark parse_transmission_url change pass
locally. The tests passed with the shelfmark parse_transmission_url
change applied; a run with it reverted gave no clear result, so no test
is shown to catch this bug.

Closes #1667


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
<!-- coderabbit-ai-generated:v1 -->

## Summary by CodeRabbit

* **Bug Fixes**
* HTTPS Transmission URLs without an explicitly specified port now use
port 443. HTTP URLs continue to default to port 9091, and the default
RPC path is unchanged.
* **Documentation**
* Clarified the default ports for each URL scheme and noted that HTTPS
instances on port 9091 require `:9091` in the URL.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
This commit is contained in:
Matt Van HornandMatt Van Horn authored and GitHub committed 2026-11-07 14:29:27 -05:00
1 parent 985a54765d
commit 0bb54ac8f8
4 files changed
+17 -4

No files matched your search

+2 -2
View File
@@ -2311,7 +2311,7 @@ How long to keep cached search results before they expire.
| `QBITTORRENT_DOWNLOAD_DIR_BOOK` | Server-side directory where book torrents are downloaded (optional, uses qBittorrent default if not specified) | string | _none_ |
| `QBITTORRENT_DOWNLOAD_DIR_AUDIOBOOK` | Server-side directory where audiobook torrents are downloaded (optional, uses qBittorrent default if not specified) | string | _none_ |
| `QBITTORRENT_TAG` | Tag(s) to assign to qBittorrent downloads. Leave empty for no tags. | string (comma-separated) | _empty list_ |
| `TRANSMISSION_URL` | URL of your Transmission instance (use https:// for TLS) | string | _none_ |
| `TRANSMISSION_URL` | URL of your Transmission instance (use https:// for TLS). Without a port, https uses 443 and http uses 9091, so add :9091 to an https URL served on 9091 | string | _none_ |
| `TRANSMISSION_USERNAME` | Transmission RPC username (if authentication enabled) | string | _none_ |
| `TRANSMISSION_PASSWORD` | Transmission RPC password | string (secret) | _none_ |
| `TRANSMISSION_CATEGORY` | Label to assign to book downloads in Transmission | string | `books` |
@@ -2516,7 +2516,7 @@ Tag(s) to assign to qBittorrent downloads. Leave empty for no tags.
**Transmission URL**
URL of your Transmission instance (use https:// for TLS)
URL of your Transmission instance (use https:// for TLS). Without a port, https uses 443 and http uses 9091, so add :9091 to an https URL served on 9091
- **Type:** string
- **Default:** _none_
+4 -1
View File
@@ -815,7 +815,10 @@ def prowlarr_clients_settings() -> list[SettingsField]:
TextField(
key="TRANSMISSION_URL",
label="Transmission URL",
description="URL of your Transmission instance (use https:// for TLS)",
description=(
"URL of your Transmission instance (use https:// for TLS). Without a port, "
"https uses 443 and http uses 9091, so add :9091 to an https URL served on 9091"
),
placeholder="http://transmission:9091",
show_when={"field": "PROWLARR_TORRENT_CLIENT", "value": "transmission"},
),
+3 -1
View File
@@ -382,7 +382,9 @@ def parse_transmission_url(url: str) -> tuple[str, str, int, str]:
if protocol not in ("http", "https"):
protocol = "http"
host = parsed.hostname or "localhost"
port = parsed.port or 9091
# An omitted port is scheme-specific: HTTPS behind a reverse proxy is 443,
# while HTTP (including the empty-URL default) stays on Transmission's RPC port.
port = parsed.port if parsed.port is not None else (443 if protocol == "https" else 9091)
path = parsed.path or "/transmission/rpc"
# Ensure path ends with /rpc
+8
View File
@@ -87,6 +87,14 @@ class TestParseTransmissionUrl:
assert port == 9091
assert path == "/transmission/rpc"
def test_parse_https_url_without_port_uses_443(self):
"""Test an HTTPS URL with no port uses the implicit HTTPS port."""
protocol, host, port, path = parse_transmission_url("https://transmission.myserver.org")
assert protocol == "https"
assert host == "transmission.myserver.org"
assert port == 443
assert path == "/transmission/rpc"
def test_parse_url_with_ip_address(self):
"""Test parsing URL with IP address."""
protocol, host, port, path = parse_transmission_url("http://192.168.1.100:9091")