From f44556081b62de8c60a94e3a67c3755952ea97c0 Mon Sep 17 00:00:00 2001 From: Stephan Yelle Date: Sat, 24 Jan 2026 23:11:47 -0500 Subject: [PATCH] Update src/http.ps1 --- src/http.ps1 | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/src/http.ps1 b/src/http.ps1 index 584050b..d1cd1c0 100644 --- a/src/http.ps1 +++ b/src/http.ps1 @@ -1,8 +1,8 @@ function Send-Text { param($Context, $Text) if (-not $Context -or -not $Context.Response) { return } - $bytes = [Text.Encoding]::UTF8.GetBytes($Text) - $Context.Response.ContentType = 'text/plain' + $bytes = [Text.Encoding]::UTF8.GetBytes([string]$Text) + $Context.Response.ContentType = 'text/plain; charset=utf-8' $Context.Response.ContentLength64 = $bytes.Length $Context.Response.OutputStream.Write($bytes,0,$bytes.Length) $Context.Response.OutputStream.Close() @@ -30,6 +30,73 @@ function Send-HTML { $Context.Response.OutputStream.Close() } +function Send-RemoteAsset { + [CmdletBinding()] + param( + [Parameter(Mandatory)][object] $Context, + [Parameter(Mandatory)][string] $Url, + [Parameter(Mandatory)][string] $ContentType + ) + + if (-not $Context -or -not $Context.Response) { return } + + if ([string]::IsNullOrWhiteSpace($Url)) { + try { + $Context.Response.StatusCode = 500 + } catch { } + Send-Text $Context "Asset URL is empty (ContentType=$ContentType)" + return + } + + try { + $resp = Invoke-WebRequest -UseBasicParsing -Uri $Url -ErrorAction Stop + + try { + $Context.Response.Headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0" + $Context.Response.Headers["Pragma"] = "no-cache" + $Context.Response.Headers["Expires"] = "0" + } catch { } + + $Context.Response.ContentType = $ContentType + + # Prefer binary stream for images/icons. For js/css/html, treat as UTF-8 text. + $bytes = $null + + if ($ContentType -like 'image/*' -or $ContentType -like '*x-icon*' -or $ContentType -like '*octet-stream*') { + try { + $ms = New-Object System.IO.MemoryStream + $resp.RawContentStream.CopyTo($ms) + $bytes = $ms.ToArray() + } + catch { + # Fallback: treat as text if RawContentStream isn't usable + $bytes = [Text.Encoding]::UTF8.GetBytes([string]$resp.Content) + } + } + else { + $bytes = [Text.Encoding]::UTF8.GetBytes([string]$resp.Content) + } + + $Context.Response.ContentLength64 = $bytes.Length + $Context.Response.OutputStream.Write($bytes, 0, $bytes.Length) + } + catch { + Write-LogHybrid "Send-RemoteAsset failed for $Url : $($_.Exception.Message)" Error Server -LogToEvent + + try { + $Context.Response.StatusCode = 502 + $msg = "Failed to fetch asset: $Url" + $bytes = [Text.Encoding]::UTF8.GetBytes($msg) + $Context.Response.ContentType = "text/plain; charset=utf-8" + $Context.Response.ContentLength64 = $bytes.Length + $Context.Response.OutputStream.Write($bytes, 0, $bytes.Length) + } catch { } + } + finally { + try { $Context.Response.OutputStream.Close() } catch { } + } +} + function Send-JSON { [CmdletBinding()] param(