@@ -347,6 +347,69 @@ iptv_http_reconnect ( http_client_t *hc, const char *url )
347347 urlreset (& u );
348348}
349349
350+ /*
351+ * Return the index of the last occurrence of character `x` in string `s`
352+ */
353+ static
354+ int last_index_of (const char * s , char x ) {
355+ int i ;
356+ int len = strlen (s );
357+ assert (s != NULL );
358+ for (i = len - 1 ; i >= 0 ; i -- ) {
359+ if (s [i ] == x ) {
360+ return i ;
361+ }
362+ }
363+ return -1 ; // x not found
364+ }
365+
366+ /*
367+ * Allocates a string with the absolute URL obtained by merging the absolute base and the relative URLs
368+ */
369+ static char * merge_absolute_and_relative_urls (const char * absolute_url , const char * relative_url ) {
370+ size_t absoute_key_url_len , last_slash_pos ;
371+ char * absolute_key_url ;
372+ const unsigned int max_levels = 100 ;
373+ int i ;
374+
375+ // allocate enough memory to contain `s` + `url` + \0
376+ absoute_key_url_len = strlen (absolute_url ) + strlen (relative_url ) + 1 ;
377+ absolute_key_url = (char * )malloc (absoute_key_url_len );
378+ memset (absolute_key_url , 0 , absoute_key_url_len );
379+
380+ // copy the url up to the last /
381+ // http://test/ab/cd becomes http://test/ab/
382+ last_slash_pos = last_index_of (absolute_url , '/' );
383+ assert (last_slash_pos < absoute_key_url_len );
384+ assert (last_slash_pos > 0 );
385+ memcpy (absolute_key_url , absolute_url , last_slash_pos + 1 );
386+
387+ for (i = 0 ; i < max_levels && (strncmp (relative_url , "../" , strlen ("../" )) == 0 ); i ++ ) {
388+ // skip `../` in relative_url
389+ relative_url = relative_url + 3 ;
390+
391+ // replace the last / with \0
392+ // http://test/ab/ becomes http://test/ab
393+ last_slash_pos = last_index_of (absolute_key_url , '/' );
394+ assert (last_slash_pos < absoute_key_url_len );
395+ assert (last_slash_pos > 0 );
396+ absolute_key_url [last_slash_pos ] = 0 ;
397+
398+ // keep until the remaining /
399+ // http://test/ab becomes http://test/
400+ last_slash_pos = last_index_of (absolute_key_url , '/' );
401+ assert (last_slash_pos < absoute_key_url_len );
402+ assert (last_slash_pos > 0 );
403+ absolute_key_url [last_slash_pos + 1 ] = 0 ;
404+ }
405+
406+ // concat `s` to the base URL
407+ assert (strlen (absolute_key_url ) + strlen (relative_url ) < absoute_key_url_len );
408+ memcpy (absolute_key_url + strlen (absolute_key_url ), relative_url , strlen (relative_url )+ 1 );
409+
410+ return absolute_key_url ;
411+ }
412+
350413static int
351414iptv_http_complete
352415 ( http_client_t * hc )
@@ -356,6 +419,7 @@ iptv_http_complete
356419 char * url ;
357420 htsmsg_t * m , * m2 ;
358421 int r ;
422+ char * absolute_key_url = NULL ;
359423
360424 if (hp == NULL || hp -> shutdown || hp -> im == NULL )
361425 return 0 ;
@@ -396,13 +460,20 @@ iptv_http_complete
396460 tvherror (LS_IPTV , "no URI in KEY attribute" );
397461 goto end ;
398462 }
463+ if (memcmp (s , "../" , strlen ("../" )) == 0 ) {
464+ tvhtrace (LS_IPTV , "KEY URI: relative URL detected (%s), rewriting it" , s );
465+ absolute_key_url = merge_absolute_and_relative_urls (url , s );
466+ s = absolute_key_url ;
467+ tvhtrace (LS_IPTV , "new KEY URI: '%s'" , s );
468+ }
399469 hp -> hls_encrypted = 1 ;
400470 if (strcmp (hp -> hls_key_url ?: "" , s )) {
401471 free (hp -> hls_key_url );
402472 hp -> hls_key_url = strdup (s );
403473 free (hp -> hls_url_after_key );
404474 hp -> hls_url_after_key = url ;
405- url = strdup (s );
475+ url = strdup (s );
476+ free (absolute_key_url );
406477 hc -> hc_data_complete = iptv_http_complete_key ;
407478 sbuf_reset (& hp -> key_sbuf , 32 );
408479 }
0 commit comments