Wiedergabe: jeden Parameter streng kodieren, so wie Plex es selbst tut
Die gebaute Adresse anzusehen hat es in einem Blick beantwortet:
path=/livetv/sessions/0043d829-… ← meine
path=%2Flivetv%2Fsessions%2F0043d829-… ← Plex
Plex' Client schickt alle Parameter durch `qs.stringify`, und das kodiert
alles. `URLComponents` lässt `/`, `:`, `&`, `=`, `+` und Klammern in
Werten stehen. Beim Server kam damit ein Pfad mit echten Schrägstrichen
an — und ein Geräteprofil, das an seinen `&` in zwei Dutzend eigene
Angaben zerfiel. Beides beantwortet er mit einer nackten 400.
Eine Regel für alle Werte, keine Ausnahmen. Damit löst sich nebenbei die
Kodierfrage, die mich mehrere Anläufe gekostet hat: eine Kennung, die
schon `%3A` enthält, wird dabei zu `%253A` — und ist genau einmal
kodiert. Die Sonderbehandlung für `path` und das Profil entfällt, und mit
ihr die Schalter, mit denen ich zwischen falschen Formen hin- und
hergeschaltet habe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ef9fd676c8
commit
44dd794e86
@@ -150,47 +150,24 @@ struct LiveTVGuideTests {
|
||||
#expect(lookup.trace.contains { $0.path == "/livetv/dvrs/2/channels" && $0.result.contains("Channel: 2") })
|
||||
}
|
||||
|
||||
@Test("Die Adresse der Sendung wird genau einmal kodiert")
|
||||
func encodesPathExactlyOnce() async throws {
|
||||
// Beide naheliegenden Wege liegen daneben, und beide habe ich
|
||||
// durchgemacht: unverändert durchgereicht kodiert `URLComponents` ein
|
||||
// zweites Mal (%3A wird %253A); vorher entpackt steht `plex://…` im
|
||||
// Klartext in der Anfrage, und daran verschluckt sich der Server mit
|
||||
// einer nackten „400 Bad Request"-Seite.
|
||||
@Test("Jeder Wert wird streng kodiert, Schrägstriche eingeschlossen")
|
||||
func encodesEveryValueStrictly() async throws {
|
||||
// Plex' eigener Client schickt alle Parameter durch `qs.stringify`,
|
||||
// und das kodiert alles. `URLComponents` allein lässt `/`, `:`, `&`
|
||||
// und `=` in Werten stehen — beim Server kam `path=/livetv/…` an
|
||||
// statt `path=%2Flivetv%2F…`, und die Antwort war eine nackte 400.
|
||||
let server = server(routes: [:])
|
||||
let url = try #require(await server.transcodeURL(for: TranscodeRequest(
|
||||
ratingKey: "5",
|
||||
isLocal: true,
|
||||
pathOverride: "/tv.plex.providers.epg.cloud:2/metadata/plex%3A%2F%2Fmovie%2Fabc"
|
||||
)))
|
||||
let text = url.absoluteString
|
||||
|
||||
#expect(text.contains("path=/tv.plex.providers.epg.cloud:2/metadata/plex%3A%2F%2Fmovie%2Fabc"))
|
||||
#expect(!text.contains("%253A"))
|
||||
#expect(!text.contains("plex://"))
|
||||
}
|
||||
|
||||
@Test("Für eine Sendung wird die Kennung zweimal kodiert")
|
||||
func doubleEncodesForLive() async throws {
|
||||
// Der Server dekodiert den Abfragewert einmal, bevor er ihn als Pfad
|
||||
// liest. Genau einmal kodiert kommt bei ihm `plex://episode/…` an —
|
||||
// kein gültiger Schlüssel, und die Antwort ist eine nackte 400.
|
||||
let server = server(routes: [:])
|
||||
let request = TranscodeRequest(
|
||||
ratingKey: "5",
|
||||
isLocal: true,
|
||||
pathOverride: "/tv.plex.providers.epg.cloud:2/metadata/plex%3A%2F%2Fepisode%2Fabc"
|
||||
)
|
||||
))).absoluteString
|
||||
|
||||
let once = try #require(await server.transcodeURL(for: request)).absoluteString
|
||||
let twice = try #require(
|
||||
await server.transcodeURL(for: request, keepPathEncoding: false)
|
||||
).absoluteString
|
||||
|
||||
#expect(once.contains("plex%3A%2F%2Fepisode%2Fabc"))
|
||||
#expect(twice.contains("plex%253A%252F%252Fepisode%252Fabc"))
|
||||
// Und niemals im Klartext: daran verschluckt sich der Server.
|
||||
#expect(!twice.contains("plex://"))
|
||||
#expect(url.contains("path=%2Ftv.plex.providers.epg.cloud%3A2%2Fmetadata%2F"))
|
||||
// Eine Kennung, die schon `%3A` trägt, wird dabei zu `%253A` — und
|
||||
// ist damit genau einmal kodiert.
|
||||
#expect(url.contains("plex%253A%252F%252Fepisode%252Fabc"))
|
||||
#expect(!url.contains("plex://"))
|
||||
}
|
||||
|
||||
@Test("Nur was tatsächlich mit 200 antwortet, geht an den Player")
|
||||
@@ -367,6 +344,7 @@ struct LiveTVGuideTests {
|
||||
// Das ganze Profil steht in genau einem Parameter.
|
||||
#expect(profile.contains("%26"))
|
||||
#expect(profile.contains("add-transcode-target%28"))
|
||||
#expect(profile.contains("%2B"))
|
||||
// Und `protocol` kommt nur ein einziges Mal vor.
|
||||
#expect(text.split(separator: "&").filter { $0.hasPrefix("protocol=") }.count == 1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user