web app mit hinzugefügt
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# HTTP-Router: leitet Requests an statische Dateien oder API-Endpoints weiter.
|
||||
|
||||
function Invoke-Router {
|
||||
param([Parameter(Mandatory=$true)]$Context)
|
||||
|
||||
$request = $Context.Request
|
||||
$path = $request.Url.AbsolutePath.TrimEnd('/')
|
||||
if ([string]::IsNullOrEmpty($path)) { $path = "/" }
|
||||
$method = $request.HttpMethod
|
||||
|
||||
$isApi = $path.StartsWith("/api/")
|
||||
if ($isApi) {
|
||||
Write-Host (">>> [{0}] {1} {2}" -f (Get-Date -Format "HH:mm:ss.fff"), $method, $path) -ForegroundColor DarkCyan
|
||||
}
|
||||
$reqStart = Get-Date
|
||||
|
||||
# API-Endpoints
|
||||
if ($isApi) {
|
||||
$body = $null
|
||||
if ($method -in @("POST","PUT","PATCH")) {
|
||||
$body = Read-RequestBody -Context $Context
|
||||
}
|
||||
$query = @{}
|
||||
foreach ($key in $request.QueryString.AllKeys) {
|
||||
if ($null -ne $key) { $query[$key] = $request.QueryString[$key] }
|
||||
}
|
||||
|
||||
try {
|
||||
$result = Invoke-ApiHandler -Path $path -Method $method -Body $body -Query $query
|
||||
$handlerMs = [int]((Get-Date) - $reqStart).TotalMilliseconds
|
||||
if ($null -eq $result) {
|
||||
Send-JsonResponse -Context $Context -StatusCode 404 -Body @{ error = "Unknown endpoint: $method $path" }
|
||||
Write-Host ("<<< [{0}] {1} {2} -> 404 ({3}ms)" -f (Get-Date -Format "HH:mm:ss.fff"), $method, $path, $handlerMs) -ForegroundColor DarkYellow
|
||||
} else {
|
||||
$statusCode = 200
|
||||
if ($result -is [hashtable] -and $result.ContainsKey('__status')) {
|
||||
$statusCode = $result['__status']
|
||||
$result.Remove('__status')
|
||||
}
|
||||
Send-JsonResponse -Context $Context -StatusCode $statusCode -Body $result
|
||||
$totalMs = [int]((Get-Date) - $reqStart).TotalMilliseconds
|
||||
Write-Host ("<<< [{0}] {1} {2} -> {3} (handler={4}ms total={5}ms)" -f (Get-Date -Format "HH:mm:ss.fff"), $method, $path, $statusCode, $handlerMs, $totalMs) -ForegroundColor DarkCyan
|
||||
}
|
||||
} catch {
|
||||
$msg = $_.Exception.Message
|
||||
# Client-Disconnects (AbortController) sind harmlos und werden nicht geloggt
|
||||
if ($msg -match "Netzwerkname.*nicht.*verfügbar|connection was forcibly closed|aborted by the software|response has been submitted") {
|
||||
Write-Host " [client disconnect] $path" -ForegroundColor DarkGray
|
||||
} else {
|
||||
Write-Host "<<< [API ERROR] $path -> $msg" -ForegroundColor Red
|
||||
Write-Host " Stack: $($_.ScriptStackTrace)" -ForegroundColor DarkRed
|
||||
try {
|
||||
Send-JsonResponse -Context $Context -StatusCode 500 -Body @{
|
||||
error = $msg
|
||||
stack = $_.ScriptStackTrace
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Assets aus dem Projekt-Root (Logos etc.)
|
||||
if ($path.StartsWith("/assets/")) {
|
||||
$name = $path.Substring("/assets/".Length)
|
||||
$name = $name -replace "[^a-zA-Z0-9._-]", ""
|
||||
$rootDir = Split-Path -Parent $script:Config.WebRoot
|
||||
$file = Join-Path $rootDir $name
|
||||
# Branding-Logos NIE cachen — sonst sieht der User nach dem Upload
|
||||
# weiter die alte Version, auch wenn die URL gleich bleibt.
|
||||
$extraHeaders = $null
|
||||
if ($name -like 'branding-logo.*') {
|
||||
$extraHeaders = @{ 'Cache-Control' = 'no-store, max-age=0' }
|
||||
}
|
||||
Send-FileResponse -Context $Context -FilePath $file -ExtraHeaders $extraHeaders
|
||||
return
|
||||
}
|
||||
|
||||
# Reports (HTML-Reports werden in Temp gespeichert)
|
||||
if ($path.StartsWith("/reports/")) {
|
||||
$name = $path.Substring("/reports/".Length)
|
||||
$name = $name -replace "[^a-zA-Z0-9._-]", ""
|
||||
$file = Join-Path $script:Config.ReportDir $name
|
||||
Send-FileResponse -Context $Context -FilePath $file
|
||||
return
|
||||
}
|
||||
|
||||
# Statische Dateien aus www/
|
||||
$relativePath = if ($path -eq "/") { "index.html" } else { $path.TrimStart('/') }
|
||||
$relativePath = $relativePath -replace '\.\.', '' # path traversal blocken
|
||||
$file = Join-Path $script:Config.WebRoot $relativePath
|
||||
|
||||
if (Test-Path $file -PathType Leaf) {
|
||||
Send-FileResponse -Context $Context -FilePath $file
|
||||
} else {
|
||||
# SPA fallback - alle nicht erkannten Pfade auf index.html
|
||||
Send-FileResponse -Context $Context -FilePath (Join-Path $script:Config.WebRoot "index.html")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user