From 5bbdf0a3fdde27e757d71fb2197fa29d4ae78baf Mon Sep 17 00:00:00 2001 From: Stephan Yelle Date: Wed, 14 Jan 2026 02:09:17 -0500 Subject: [PATCH] Add src/server.ps1 --- src/server.ps1 | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/server.ps1 diff --git a/src/server.ps1 b/src/server.ps1 new file mode 100644 index 0000000..da6fca9 --- /dev/null +++ b/src/server.ps1 @@ -0,0 +1,62 @@ +function Get-NextFreePort { + param([int]$Start = $Script:Port) + for ($p = [Math]::Max(1024,$Start); $p -lt 65535; $p++) { + $l = [System.Net.Sockets.TcpListener]::new([Net.IPAddress]::Loopback, $p) + try { $l.Start(); $l.Stop(); return $p } catch {} + } + throw "No free TCP port available." +} + +function Start-Server { + $Global:Listener = [System.Net.HttpListener]::new() + $primaryPrefix = "http://localhost:$Script:Port/" + $wildcardPrefix = "http://+:$Script:Port/" + + try { + $Global:Listener.Prefixes.Add($primaryPrefix) + $Global:Listener.Start() + Write-LogHybrid "Listening on $primaryPrefix" Info Server -LogToEvent + } + catch [System.Net.HttpListenerException] { + if ($_.Exception.ErrorCode -eq 5) { + Write-LogHybrid "Access denied on $primaryPrefix. Attempting URL ACL…" Warning Server -LogToEvent + try { + $user = "$env:USERDOMAIN\$env:USERNAME" + if (-not $user.Trim()) { $user = $env:USERNAME } + Start-Process -FilePath "netsh" -ArgumentList "http add urlacl url=$wildcardPrefix user=`"$user`" listen=yes" -Verb RunAs -WindowStyle Hidden -Wait + $Global:Listener = [System.Net.HttpListener]::new() + $Global:Listener.Prefixes.Add($wildcardPrefix) + $Global:Listener.Start() + Write-LogHybrid "Listening on $wildcardPrefix (URL ACL added for $user)" Success Server -LogToEvent + } catch { + Write-LogHybrid "URL ACL registration failed: $($_.Exception.Message)" Error Server -LogToEvent + return + } + } + elseif ($_.Exception.NativeErrorCode -in 32,183) { + $old = $Script:Port + $Script:Port = Get-NextFreePort -Start ($Script:Port + 1) + $Global:Listener = [System.Net.HttpListener]::new() + $primaryPrefix = "http://localhost:$Script:Port/" + $Global:Listener.Prefixes.Add($primaryPrefix) + $Global:Listener.Start() + Write-LogHybrid "Port $old busy. Listening on $primaryPrefix" Warning Server -LogToEvent + } + else { + Write-LogHybrid "HttpListener start failed: $($_.Exception.Message)" Error Server -LogToEvent + return + } + } + + try { + while ($Global:Listener.IsListening) { + $ctx = $Global:Listener.GetContext() + try { Dispatch-Request $ctx } + catch { Write-LogHybrid "Dispatch error: $($_.Exception.Message)" Error Server -LogToEvent } + } + } + finally { + $Global:Listener.Close() + Write-LogHybrid "Listener closed." Info Server -LogToEvent + } +}