From f9bb0cc23e0801fe5b484889943677d0739b45aa Mon Sep 17 00:00:00 2001 From: Arunima George Date: Fri, 25 Oct 2024 15:58:02 +0100 Subject: [PATCH] TD-4945: CORS Policy Issue on iPhone Landing Page --- .../Api/MediaManifestProxyController.cs | 76 ++++++++++++++++++- .../Controllers/MediaController.cs | 13 +++- .../Views/Home/_CmsVideo.cshtml | 2 +- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/MediaManifestProxyController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/MediaManifestProxyController.cs index 69129c075..5c7b9c61d 100644 --- a/LearningHub.Nhs.WebUI/Controllers/Api/MediaManifestProxyController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/Api/MediaManifestProxyController.cs @@ -14,7 +14,6 @@ /// /// Defines the . /// - [Authorize] [Route("api/[controller]")] [ApiController] public class MediaManifestProxyController : ControllerBase @@ -37,6 +36,7 @@ public MediaManifestProxyController(ILogger logger /// The playBackUrl. /// The token. /// The MediaManifestProxy string. + [Authorize] public string Get(string playBackUrl, string token) { this.logger.LogDebug($"playBackUrl={playBackUrl} token={token}"); @@ -103,6 +103,80 @@ public string Get(string playBackUrl, string token) return null; } + /// + /// The LandingPageGet. + /// + /// The playBackUrl. + /// The token. + /// The MediaManifestProxy string. + [HttpGet] + [Route("LandingPageGet")] + public string LandingPageGet(string playBackUrl, string token) + { + this.logger.LogDebug($"playBackUrl={playBackUrl} token={token}"); + var httpRequest = (HttpWebRequest)WebRequest.Create(new Uri(playBackUrl)); + httpRequest.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore); + httpRequest.Timeout = 30000; + + var httpResponse = httpRequest.GetResponse(); + + try + { + this.logger.LogDebug($"Calling httpResponse.GetResponseStream(): playBackUrl={playBackUrl} "); + var stream = httpResponse.GetResponseStream(); + if (stream != null) + { + using (var reader = new StreamReader(stream)) + { + const string qualityLevelRegex = @"(|)([^""\s]+\.m3u8\(encryption=cbc\))"; + const string fragmentsRegex = @"(Fragments\([\w\d=-]+,[\w\d=-]+\))"; + const string urlRegex = @"(https?:\/\/[\da-z\.-]+\.[a-z\.]{2,6}[\/\w \.-]*\?[^,\s""]*)"; + + var baseUrl = playBackUrl.Substring(0, playBackUrl.IndexOf(".ism", System.StringComparison.OrdinalIgnoreCase)) + ".ism"; + this.logger.LogDebug($"baseUrl={baseUrl}"); + + var content = reader.ReadToEnd(); + + content = ReplaceUrisWithProxy(content, baseUrl); + var newContent = Regex.Replace(content, urlRegex, match => + { + string baseUrlWithQuery = match.Groups[1].Value; // URL including the query string + + // Append the token correctly without modifying surrounding characters + string newUrl = baseUrlWithQuery.Contains("?") ? + $"{baseUrlWithQuery}&token={token}" : + $"{baseUrlWithQuery}?token={token}"; + + return newUrl; + }); + + this.logger.LogDebug($"newContent={newContent}"); + + var match = Regex.Match(playBackUrl, qualityLevelRegex); + if (match.Success) + { + this.logger.LogDebug($"match.Success"); + var qualityLevel = match.Groups[0].Value; + newContent = Regex.Replace(newContent, fragmentsRegex, m => string.Format(CultureInfo.InvariantCulture, baseUrl + "/" + qualityLevel + "/" + m.Value)); + this.logger.LogDebug($"Updated newContent={newContent}"); + } + + return newContent; + } + } + } + catch (Exception ex) + { + this.logger.LogError(ex.Message); + } + finally + { + httpResponse.Close(); + } + + return null; + } + private static string ReplaceUrisWithProxy(string playlistContent, string proxyUrl) { // Split the playlist content into lines diff --git a/LearningHub.Nhs.WebUI/Controllers/MediaController.cs b/LearningHub.Nhs.WebUI/Controllers/MediaController.cs index 1012b7a51..4acd69e07 100644 --- a/LearningHub.Nhs.WebUI/Controllers/MediaController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/MediaController.cs @@ -39,16 +39,25 @@ public MediaController(IWebHostEnvironment hostingEnvironment, ILoggerThe playBackUrl. /// The token. /// The orgin node. + /// The isLandingPage. /// The . [Route("Media/MediaManifest")] - public IActionResult MediaManifest(string playBackUrl, string token, string origin = "*") + public IActionResult MediaManifest(string playBackUrl, string token, string origin = "*", bool isLandingPage = false) { try { this.Logger.LogDebug($"playBackUrl={playBackUrl} token={token}"); var hostPortion = this.Request.Host; + var manifestProxyUrl = string.Empty; + if (isLandingPage) + { + manifestProxyUrl = string.Format("https://{0}/api/MediaManifestProxy/LandingPageGet", hostPortion); + } + else + { + manifestProxyUrl = string.Format("https://{0}/api/MediaManifestProxy", hostPortion); + } - var manifestProxyUrl = string.Format("https://{0}/api/MediaManifestProxy", hostPortion); this.Logger.LogDebug($"manifestProxyUrl={manifestProxyUrl}"); var modifiedTopLeveLManifest = this.azureMediaService.GetTopLevelManifestForToken(manifestProxyUrl, playBackUrl, token); diff --git a/LearningHub.Nhs.WebUI/Views/Home/_CmsVideo.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_CmsVideo.cshtml index 23de524bf..1b9433b83 100644 --- a/LearningHub.Nhs.WebUI/Views/Home/_CmsVideo.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Home/_CmsVideo.cshtml @@ -108,7 +108,7 @@ if (checkIfIphone()) { var token = model.videoAsset.azureMediaAsset.authenticationToken; - url = '@requestURL' + "Media/MediaManifest?playBackUrl=" + url + "&token=" + token + "&origin=" + '@requestURL'; + url = '@requestURL' + "Media/MediaManifest?playBackUrl=" + url + "&token=" + token + "&origin=" + '@requestURL' + "&isLandingPage=" + true; } var subtitleTrack = null; if (model.videoAsset.azureMediaAsset && model.videoAsset.closedCaptionsFile) {