Skip to content

Commit d50effd

Browse files
stackiaclaude
andcommitted
fix: use case-insensitive matching for seek parameter detection
The heuristic detection of playseek/tvdr parameters in query strings used case-sensitive strstr(), causing parameters like "Playseek=" to go unrecognized. This left the parameter in the upstream URL unprocessed and prevented recent seek mode from triggering. Switch to strcasestr() for detection, extraction, and removal of seek parameters, preserving the original case when forwarding to upstream. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b970c27 commit d50effd

2 files changed

Lines changed: 21 additions & 13 deletions

File tree

e2e/test_rtsp_misc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ def _build_seek_query(param_name: str, start_str: str, end_str: str) -> str:
447447
return "custom_seek=%s-%s&r2h-seek-name=custom_seek" % (start_str, end_str)
448448
return "%s=%s-%s" % (param_name, start_str, end_str)
449449

450-
@pytest.mark.parametrize("param_name", ["playseek", "tvdr", "custom_seek"])
450+
@pytest.mark.parametrize("param_name", ["playseek", "Playseek", "tvdr", "custom_seek"])
451451
def test_recent_playseek_uses_clock_range(self, shared_r2h, param_name):
452452
rtsp = MockRTSPServer(num_packets=500)
453453
rtsp.start()
@@ -514,7 +514,7 @@ def test_recent_playseek_ignores_r2h_start(self, shared_r2h):
514514
finally:
515515
rtsp.stop()
516516

517-
@pytest.mark.parametrize("param_name", ["playseek", "tvdr", "custom_seek"])
517+
@pytest.mark.parametrize("param_name", ["playseek", "Playseek", "tvdr", "custom_seek"])
518518
def test_boundary_playseek_is_forwarded(self, shared_r2h, param_name):
519519
rtsp = MockRTSPServer(num_packets=500)
520520
rtsp.start()

src/service.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ int service_extract_seek_params(char *query_start, char **out_seek_param_name,
273273
const char *seek_param_name = NULL;
274274
char *seek_param_value = NULL;
275275
int seek_offset_seconds = 0;
276+
char heuristic_seek_name[16];
276277

277278
if (!query_start || *query_start != '?' || !out_seek_param_name ||
278279
!out_seek_param_value || !out_seek_offset_seconds) {
@@ -354,18 +355,25 @@ int service_extract_seek_params(char *query_start, char **out_seek_param_name,
354355
logger(LOG_DEBUG, "Using explicitly specified seek parameter name: %s",
355356
seek_param_name);
356357
} else if (query_start) {
357-
/* Heuristic detection with fixed priority: playseek > tvdr */
358-
char *playseek_check = strstr(query_start, "playseek=");
358+
/* Heuristic detection with fixed priority: playseek > tvdr
359+
* Use case-insensitive matching and preserve original case */
360+
char *playseek_check = strcasestr(query_start, "playseek=");
359361
if (playseek_check &&
360362
(playseek_check == query_start + 1 || *(playseek_check - 1) == '&')) {
361-
seek_param_name = "playseek";
362-
logger(LOG_DEBUG, "Heuristic: detected playseek parameter");
363+
memcpy(heuristic_seek_name, playseek_check, 8);
364+
heuristic_seek_name[8] = '\0';
365+
seek_param_name = heuristic_seek_name;
366+
logger(LOG_DEBUG, "Heuristic: detected playseek parameter (%s)",
367+
seek_param_name);
363368
} else {
364-
char *tvdr_check = strstr(query_start, "tvdr=");
369+
char *tvdr_check = strcasestr(query_start, "tvdr=");
365370
if (tvdr_check &&
366371
(tvdr_check == query_start + 1 || *(tvdr_check - 1) == '&')) {
367-
seek_param_name = "tvdr";
368-
logger(LOG_DEBUG, "Heuristic: detected tvdr parameter");
372+
memcpy(heuristic_seek_name, tvdr_check, 4);
373+
heuristic_seek_name[4] = '\0';
374+
seek_param_name = heuristic_seek_name;
375+
logger(LOG_DEBUG, "Heuristic: detected tvdr parameter (%s)",
376+
seek_param_name);
369377
}
370378
}
371379
}
@@ -380,8 +388,8 @@ int service_extract_seek_params(char *query_start, char **out_seek_param_name,
380388
char *search_pos = query_start;
381389
char *seek_start, *seek_end;
382390

383-
/* Iterate through all occurrences of the seek parameter */
384-
while ((seek_start = strstr(search_pos, search_pattern)) != NULL) {
391+
/* Iterate through all occurrences of the seek parameter (case-insensitive) */
392+
while ((seek_start = strcasestr(search_pos, search_pattern)) != NULL) {
385393
if (seek_start > query_start && *(seek_start - 1) != '?' &&
386394
*(seek_start - 1) != '&') {
387395
search_pos = seek_start + strlen(search_pattern);
@@ -445,10 +453,10 @@ int service_extract_seek_params(char *query_start, char **out_seek_param_name,
445453
seek_param_name, seek_param_value);
446454
}
447455

448-
/* Remove all seek parameters from URL */
456+
/* Remove all seek parameters from URL (case-insensitive) */
449457
if (seek_param_value) {
450458
char *remove_pos = query_start;
451-
while ((seek_start = strstr(remove_pos, search_pattern)) != NULL) {
459+
while ((seek_start = strcasestr(remove_pos, search_pattern)) != NULL) {
452460
if (seek_start > query_start && *(seek_start - 1) != '?' &&
453461
*(seek_start - 1) != '&') {
454462
remove_pos = seek_start + strlen(search_pattern);

0 commit comments

Comments
 (0)