Created
February 11, 2026 16:48
-
-
Save koturn/937948532912e10e4a1dafedbae2b951 to your computer and use it in GitHub Desktop.
Simple HTTP Server implemented in PowerShell.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| $script:DefaultHostIpv4 = '127.0.0.1' | |
| $script:DefaultHostIpv6 = '[::1]' | |
| $script:DefaultPort = '8080' | |
| $script:DefaultLocalRootPath = '.' | |
| $script:DateTimeFormat = 'dd/MMM/yyyy:HH:mm:ss K' | |
| $script:TreatPrefixRootAsLocalRoot = $false | |
| $script:LocalRootPath = $script:DefaultLocalRootPath | |
| $script:PrefixRoot = '' | |
| $script:ShouldLaunchWebBrowser = $false | |
| $script:IsGenerateHtml5IndexPage = $true | |
| function Main { | |
| param ( | |
| [string[]]$cmdArgs | |
| ) | |
| [System.Globalization.CultureInfo]::DefaultThreadCurrentCulture = [System.Globalization.CultureInfo]::InvariantCulture | |
| [System.Globalization.CultureInfo]::DefaultThreadCurrentUICulture = [System.Globalization.CultureInfo]::InvariantCulture | |
| [System.Threading.Thread]::CurrentThread.CurrentCulture = [System.Globalization.CultureInfo]::InvariantCulture | |
| [System.Threading.Thread]::CurrentThread.CurrentUICulture = [System.Globalization.CultureInfo]::InvariantCulture | |
| $prefixList = ParseArguments $cmdArgs | |
| $listener = New-Object System.Net.HttpListener | |
| foreach ($prefix in $prefixList) { | |
| Write-Host "[$(Get-Date -Format $script:DateTimeFormat)]" -NoNewline -ForegroundColor Green | |
| Write-Host " prefix[$($listener.Prefixes.Count)]: $prefix" | |
| $listener.Prefixes.Add($prefix) | |
| } | |
| Write-Host "[$(Get-Date -Format $script:DateTimeFormat)]" -NoNewline -ForegroundColor Green | |
| Write-Host " Path binding: $(if ($script:PrefixRoot.Length -eq 0) { '/' } else { $script:PrefixRoot }) -> $script:LocalRootPath" | |
| Write-Host "[$(Get-Date -Format $script:DateTimeFormat)]" -NoNewline -ForegroundColor Green | |
| Write-Host " Start listening ..." | |
| $rootFaviconPath = $script:PrefixRoot + '/favicon.ico' | |
| try { | |
| $listener.Start() | |
| if ($script:ShouldLaunchWebBrowser -and $prefixList.Count -gt 0) { | |
| rundll32.exe url.dll,FileProtocolHandler "$($prefixList[0].Replace('+', $script:DefaultHostIpv4))" | |
| } | |
| while ($listener.IsListening) { | |
| $task = $listener.GetContextAsync() | |
| # Handle Ctrl+C | |
| while (-not $task.AsyncWaitHandle.WaitOne(0)) { | |
| } | |
| $context = $task.GetAwaiter().GetResult() | |
| $request = $context.Request | |
| $paramPart = '' | |
| $rawPath = RemoveUrlParameter $request.RawUrl ([ref]$paramPart) | |
| $collapsedPath = $rawPath -replace '//+', '/' | |
| $response = $context.Response | |
| try { | |
| if ($collapsedPath -ne $rawPath) { | |
| if ($paramPart.Length -eq 0) { | |
| $response.Headers.Set('Location', $collapsedPath) | |
| } else { | |
| $response.Headers.Set('Location', $collapsedPath + '?' + $paramPart) | |
| } | |
| $response.StatusCode = 307 | |
| } else { | |
| if ($script:TreatPrefixRootAsLocalRoot) { | |
| if ($rawPath -eq $script:PrefixRoot) { | |
| $rawPath = '/.' | |
| } elseif ($rawPath.StartsWith($script:PrefixRoot + '/')) { | |
| $rawPath = $rawPath.Substring($script:PrefixRoot.Length) | |
| } | |
| } | |
| if ($rawPath.Length -eq 0) { | |
| $rawPath = '/.' | |
| } | |
| $entryPath = ($script:LocalRootPath + [System.Net.WebUtility]::UrlDecode($rawPath)).Replace('/', '\') | |
| if ($request.HttpMethod -ne 'GET') { | |
| $response.StatusCode = 501 | |
| } elseif ($entryPath.Contains('\..\') -or $entryPath.EndsWith('\..')) { | |
| $response.StatusCode = 400 | |
| } elseif (Test-Path -Path $entryPath -PathType Container) { | |
| if ($entryPath.EndsWith('\')) { | |
| $response.ContentType = 'text/html' | |
| $indexPath = $entryPath + 'index.html' | |
| if (Test-Path $indexPath -PathType Leaf) { | |
| TransferFile $response $indexPath | |
| } else { | |
| $indexPage = if ($script:IsGenerateHtml5IndexPage) { | |
| CreateHtml5IndexPage $entryPath $rawPath $script:rootFaviconPath | |
| } else { | |
| CreateHtml4IndexPage $entryPath $rawPath $script:rootFaviconPath | |
| } | |
| $content = [System.Text.Encoding]::UTF8.GetBytes($indexPage) | |
| $response.ContentLength64 = $content.Length | |
| $response.OutputStream.Write($content, 0, $content.Length) | |
| } | |
| } else { | |
| $redirectPath = $rawPath + '/' | |
| if ($paramPart.Length -eq 0) { | |
| $response.Headers.Set('Location', $redirectPath) | |
| } else { | |
| $response.Headers.Set('Location', $redirectPath + '?' + $paramPart) | |
| } | |
| $response.StatusCode = 307 | |
| } | |
| } elseif (Test-Path $entryPath -PathType Leaf) { | |
| try { | |
| $response.ContentType = GetMimeType $entryPath 'application/octet-stream' | |
| TransferFile $response $entryPath | |
| } catch { | |
| Write-Error($_.Exception) | |
| $response.StatusCode = 403 | |
| } | |
| } else { | |
| if ($rawPath -eq '/.well-known/appspecific/com.chrome.devtools.json' -and $request.IsLocal) { | |
| $chromeDevToolJson = CreateChromeDevToolJson $script:LocalRootPath | |
| $content = [System.Text.Encoding]::UTF8.GetBytes($chromeDevToolJson) | |
| $response.ContentType = 'application/json' | |
| $response.ContentLength64 = $content.Length | |
| $response.OutputStream.Write($content, 0, $content.Length) | |
| } else { | |
| $response.StatusCode = 404 | |
| } | |
| } | |
| } | |
| # Output log | |
| Write-Host $request.RemoteEndPoint.Address.ToString() -NoNewline -ForegroundColor Blue | |
| Write-Host ' - -' -NoNewline -ForegroundColor DarkGray | |
| Write-Host " [$(Get-Date -Format $script:DateTimeFormat)]" -NoNewline -ForegroundColor Green | |
| Write-Host " `"$($request.HttpMethod) $($request.RawUrl) HTTP/$($request.ProtocolVersion)`"" -NoNewline -ForegroundColor Yellow | |
| $statusType = [int]($response.StatusCode / 100) | |
| if ($statusType -eq 2) { | |
| Write-Host " $($response.StatusCode)" -NoNewline -ForegroundColor DarkGreen | |
| } elseif ($statusType -eq 4 -or $statusType -eq 5) { | |
| Write-Host " $($response.StatusCode)" -NoNewline -ForegroundColor Red | |
| } else { | |
| Write-Host " $($response.StatusCode)" -NoNewline -ForegroundColor DarkMagenta | |
| } | |
| if ($response.StatusCode -eq 200) { | |
| Write-Host " $($response.ContentLength64)" -NoNewline -ForegroundColor Cyan | |
| } else { | |
| Write-Host ' -' -NoNewline -ForegroundColor Cyan | |
| } | |
| if ($request.UrlReferrer -eq $null) { | |
| Write-Host ' -' -NoNewline -ForegroundColor DarkCyan | |
| } else { | |
| Write-Host " `"$($request.UrlReferrer)`"" -NoNewline -ForegroundColor DarkCyan | |
| } | |
| Write-Host " `"$($request.UserAgent)`"" -ForegroundColor DarkYellow | |
| } finally { | |
| $response.Dispose() | |
| } | |
| } | |
| } catch { | |
| Write-Error($_.Exception) | |
| } finally { | |
| $listener.Close() | |
| } | |
| } | |
| function ParseArguments { | |
| param ( | |
| [string[]]$cmdArgs | |
| ) | |
| $hostPartList = New-Object System.Collections.Generic.List[string] | |
| $port = $script:DefaultPort | |
| $prefixRoot = '' | |
| $treatNonOptionArg = $false | |
| for ($i = 0; $i -lt $cmdArgs.Length; $i++) { | |
| $arg = $cmdArgs[$i] | |
| if ($arg[0] -ne '-' -or $treatNonOptionArg) { | |
| $port = [int]$arg | |
| } | |
| else { | |
| switch -CaseSensitive ($arg) { | |
| "-g" { | |
| $hostPartList.Clear() | |
| $hostPartList.Add("+") | |
| } | |
| "-h" { | |
| ShowUsage | |
| exit 0 | |
| } | |
| "-H" { | |
| if ($i + 1 -ge $cmdArgs.Length) { | |
| throw "Argument required for option `"$arg`"" | |
| } | |
| $i++ | |
| if ($hostPartList.Count -eq 0 -or $hostPartList[0] -ne '+') { | |
| $hostPartList.Add($cmdArgs[$i]); | |
| } | |
| } | |
| "-l" { | |
| if ($i + 1 -ge $cmdArgs.Length) { | |
| throw "Argument required for option `"$arg`"" | |
| } | |
| $i++ | |
| $script:LocalRootPath = $cmdArgs[$i] | |
| if (-not (Test-Path -LiteralPath $script:LocalRootPath -PathType Container)) { | |
| throw [System.IO.DirectoryNotFoundException]::new($script:LocalRootPath) | |
| } | |
| } | |
| "-r" { | |
| if ($i + 1 -ge $cmdArgs.Length) { | |
| throw "Argument required for option `"$arg`"" | |
| } | |
| $i++ | |
| $script:PrefixRoot = $cmdArgs[$i] | |
| } | |
| "-R" { | |
| $script:TreatPrefixRootAsLocalRoot = $true | |
| } | |
| "-t" { | |
| $hostPartList.Clear() | |
| $hostPartList.Add("+") | |
| $port = 80 | |
| $script:PrefixRoot = '/Temporary_Listen_Addresses' | |
| } | |
| "-w" { | |
| $script:ShouldLaunchWebBrowser = $true | |
| } | |
| "--legacy-index-page" { | |
| $script:IsGenerateHtml5IndexPage = $false | |
| } | |
| "--" { | |
| $treatNonOptionArg = $true | |
| } | |
| default { | |
| throw "Unknown option `"$arg`"" | |
| } | |
| } | |
| } | |
| } | |
| if ($hostPartList.Count -eq 0) { | |
| $hostPartList.Add($script:DefaultHostIpv4) | |
| $hostPartList.Add($script:DefaultHostIpv6) | |
| } | |
| if ($script:PrefixRoot.Length -gt 0 -and $script:PrefixRoot[0] -ne '/') { | |
| $script:PrefixRoot = '/' + $script:PrefixRoot | |
| } | |
| $prefixList = New-Object System.Collections.Generic.List[string] | |
| foreach ($hostPart in $hostPartList) { | |
| $prefixList.Add("http://$($hostPart):$port$script:PrefixRoot/") | |
| } | |
| return $prefixList | |
| } | |
| function ShowUsage { | |
| Write-Output '[USAGE]' | |
| Write-Output ' THIS_SCRIPT {{OPTIONS...}} {{PORT}}' | |
| Write-Output '[OPTIONS]' | |
| Write-Output ' -g' | |
| Write-Output " Use \'+\' as host part." | |
| Write-Output ' -h' | |
| Write-Output ' Show this message and exit program.' | |
| Write-Output ' -H HOST' | |
| Write-Output ' Use HOST as host part.' | |
| Write-Output ' -l DIR' | |
| Write-Output ' Use specified local directory as the root. (Default: .)' | |
| Write-Output ' -r DIR' | |
| Write-Output ' Use specified directory for the part of directory of prefix.' | |
| Write-Output ' -R' | |
| Write-Output ' Treat the prefix root directory as the local root directory.' | |
| Write-Output ' -t' | |
| Write-Output " Use `"http://+:80/Temporary_Listen_Addresses/`" as prefix." | |
| Write-Output ' -w' | |
| Write-Output ' Launch default web browser after starting listening.' | |
| Write-Output ' --legacy-index-page' | |
| Write-Output ' Generate index page written in HTML4.01.' | |
| } | |
| function RemoveUrlParameter { | |
| param ( | |
| [Parameter(Mandatory)] | |
| [string]$url, | |
| [ref]$paramPart | |
| ) | |
| $index = $url.IndexOf('?') | |
| if ($index -eq -1) { | |
| $paramPart = '' | |
| return $url | |
| } else { | |
| if ($index -eq $url.Length - 1) { | |
| $paramPart = '' | |
| } else { | |
| $paramPart = $url.Substring($index + 1) | |
| } | |
| return $url.Substring(0, $index) | |
| } | |
| } | |
| function TransferFile { | |
| param ( | |
| [Parameter(Mandatory)] | |
| [System.Net.HttpListenerResponse]$response, | |
| [Parameter(Mandatory)] | |
| [string]$filePath | |
| ) | |
| $fileInfo = [System.IO.FileInfo]::new($filePath) | |
| $fileSize = $fileInfo.Length | |
| if ($fileSize -eq 0) { | |
| return | |
| } | |
| $bufferSize = [Math]::Min(81920, $fileSize) | |
| Write-Output $bufferSize | |
| $fs = [System.IO.FileStream]::new( | |
| $filePath, | |
| [System.IO.FileMode]::Open, | |
| [System.IO.FileAccess]::Read, | |
| [System.IO.FileShare]::ReadWrite, | |
| [int]$bufferSize, | |
| [System.IO.FileOptions]::SequentialScan | |
| ) | |
| try { | |
| $response.ContentLength64 = $fileSize | |
| $fs.CopyTo($response.OutputStream) | |
| } finally { | |
| $fs.Dispose() | |
| } | |
| } | |
| function CreateHtml5IndexPage { | |
| param ( | |
| [Parameter(Mandatory)] | |
| [string]$path, | |
| [Parameter(Mandatory)] | |
| [string]$urlPath, | |
| [string]$FaviconPath | |
| ) | |
| $encodedPath = [System.Net.WebUtility]::HtmlEncode($urlPath) | |
| $sb = [System.Text.StringBuilder]::new("<!DOCTYPE html>`n") | |
| $null = $sb.Append("<html lang=""en"">`n") | |
| $null = $sb.Append("<head>`n") | |
| $null = $sb.Append(" <meta charset=""utf-8""/>`n") | |
| $null = $sb.AppendFormat(" <title>{0}</title>`n", $encodedPath) | |
| $null = $sb.Append(" <style>`n") | |
| $null = $sb.Append(" .entry-item { font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Courier New', Courier, 'Liberation Mono', monospace; }`n") | |
| $null = $sb.Append(" @media (prefers-color-scheme: dark) { body { color: #ffffff; background-color: #000000; } a:link { color: #7690ed; } a:visited { color: #7a6c87; } }`n") | |
| $null = $sb.Append(" </style>`n") | |
| if ($null -ne $FaviconPath) { | |
| $null = $sb.AppendFormat( | |
| " <link rel=""shortcut icon"" href=""{0}"">`n", | |
| $FaviconPath | |
| ) | |
| } | |
| $null = $sb.Append("</head>`n") | |
| $null = $sb.Append("<body>`n") | |
| $null = $sb.AppendFormat("<h1>Directory listing for {0}</h1>`n", $encodedPath) | |
| $null = $sb.Append("<hr>`n") | |
| EmitHtmlUlListOfDirectoryEntries $sb $path $urlPath | |
| $null = $sb.Append("</ul>`n") | |
| $null = $sb.Append("<hr>`n") | |
| $null = $sb.Append("</body>`n") | |
| $null = $sb.Append("</html>`n") | |
| return $sb.ToString() | |
| } | |
| function CreateHtml4IndexPage { | |
| param ( | |
| [Parameter(Mandatory)] | |
| [string]$path, | |
| [Parameter(Mandatory)] | |
| [string]$urlPath, | |
| [string]$faviconPath | |
| ) | |
| $encodedPath = [System.Net.WebUtility]::HtmlEncode($urlPath) | |
| $sb = [System.Text.StringBuilder]::new( | |
| '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' + "`n" | |
| ) | |
| $null = $sb.Append("<html lang=""en"">`n") | |
| $null = $sb.Append("<head>`n") | |
| $null = $sb.Append(" <meta http-equiv=""Content-Type"" content=""text/html; charset=utf-8"">`n") | |
| $null = $sb.Append(" <meta http-equiv=""Content-Style-Type"" content=""text/css"">`n") | |
| $null = $sb.AppendFormat(" <title>{0}</title>`n", $encodedPath) | |
| $null = $sb.Append(" <style type=""text/css""><!--`n") | |
| $null = $sb.Append(" .entry-item { font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, 'Courier New', Courier, 'Liberation Mono', monospace; }`n") | |
| $null = $sb.Append(" --></style>`n") | |
| if ($null -ne $faviconPath) { | |
| $null = $sb.AppendFormat(" <link rel=""shortcut icon"" href=""{0}"">`n", $faviconPath) | |
| } | |
| $null = $sb.Append("</head>`n") | |
| $null = $sb.Append("<body>`n") | |
| $null = $sb.AppendFormat("<h1>Directory listing for {0}</h1>`n", $encodedPath) | |
| $null = $sb.Append("<hr>`n") | |
| EmitHtmlUlListOfDirectoryEntries $sb $path $urlPath | |
| $null = $sb.Append("</ul>`n") | |
| $null = $sb.Append("<hr>`n") | |
| $null = $sb.Append("</body>`n") | |
| $null = $sb.Append("</html>`n") | |
| return $sb.ToString() | |
| } | |
| function EmitHtmlUlListOfDirectoryEntries { | |
| param ( | |
| [Parameter(Mandatory)] | |
| [System.Text.StringBuilder]$sb, | |
| [Parameter(Mandatory)] | |
| [string]$path, | |
| [Parameter(Mandatory)] | |
| [string]$urlPath | |
| ) | |
| $null = $sb.Append("<ul>`n") | |
| if ($urlPath -ne '/') { | |
| $null = $sb.Append( | |
| " <li><a class=""entry-item"" href="".."">..</a></li>`n" | |
| ) | |
| } | |
| foreach ($entry in [System.IO.Directory]::EnumerateFileSystemEntries($path)) { | |
| $basename = [System.IO.Path]::GetFileName($entry) | |
| $suffix = if ([System.IO.Directory]::Exists($entry)) { '/' } else { '' } | |
| $null = $sb.AppendFormat( | |
| " <li><a class=""entry-item"" href=""{0}{2}"">{1}{2}</a></li>`n", | |
| [System.Net.WebUtility]::UrlEncode($basename), | |
| [System.Net.WebUtility]::HtmlEncode($basename), | |
| $suffix | |
| ) | |
| } | |
| $null = $sb.Append("</ul>`n") | |
| } | |
| function CreateChromeDevToolJson { | |
| param ( | |
| [Parameter(Mandatory)] | |
| [string]$rootPath | |
| ) | |
| $fullPath = [System.IO.Path]::GetFullPath($rootPath) -replace '\\', '/' | |
| $uuid = [guid]::NewGuid().ToString() | |
| $sb = [System.Text.StringBuilder]::new("{`n") | |
| $null = $sb.Append(" `"workspace`": {`n") | |
| $null = $sb.AppendFormat(" `"root`": `"{0}`",`n", $fullPath) | |
| $null = $sb.AppendFormat(" `"uuid`": `"{0}`"`n", $uuid) | |
| $null = $sb.Append(" }`n") | |
| $null = $sb.Append("}`n") | |
| return $sb.ToString() | |
| } | |
| function GetMimeType { | |
| param ( | |
| [Parameter(Mandatory)] | |
| [string]$fileName, | |
| [Parameter(Mandatory)] | |
| [string]$fallbackMimeType | |
| ) | |
| $ext = [System.IO.Path]::GetExtension($fileName) | |
| if ($MimeTypeDict.ContainsKey($ext)) { | |
| return $MimeTypeDict[$ext] | |
| } else { | |
| return $fallbackMimeType | |
| } | |
| } | |
| $MimeTypeDict = @{ | |
| '.323' = 'text/h323' | |
| '.aaf' = 'application/octet-stream' | |
| '.aca' = 'application/octet-stream' | |
| '.accdb' = 'application/msaccess' | |
| '.accde' = 'application/msaccess' | |
| '.accdt' = 'application/msaccess' | |
| '.acx' = 'application/internet-property-stream' | |
| '.afm' = 'application/octet-stream' | |
| '.ai' = 'application/postscript' | |
| '.aif' = 'audio/x-aiff' | |
| '.aifc' = 'audio/aiff' | |
| '.aiff' = 'audio/aiff' | |
| '.application' = 'application/x-ms-application' | |
| '.art' = 'image/x-jg' | |
| '.asd' = 'application/octet-stream' | |
| '.asf' = 'video/x-ms-asf' | |
| '.asi' = 'application/octet-stream' | |
| '.asm' = 'text/plain' | |
| '.asr' = 'video/x-ms-asf' | |
| '.asx' = 'video/x-ms-asf' | |
| '.atom' = 'application/atom+xml' | |
| '.au' = 'audio/basic' | |
| '.avi' = 'video/x-msvideo' | |
| '.axs' = 'application/olescript' | |
| '.bas' = 'text/plain' | |
| '.bcpio' = 'application/x-bcpio' | |
| '.bin' = 'application/octet-stream' | |
| '.bmp' = 'image/bmp' | |
| '.c' = 'text/plain' | |
| '.cab' = 'application/octet-stream' | |
| '.calx' = 'application/vnd.ms-office.calx' | |
| '.cat' = 'application/vnd.ms-pki.seccat' | |
| '.cdf' = 'application/x-cdf' | |
| '.chm' = 'application/octet-stream' | |
| '.class' = 'application/x-java-applet' | |
| '.clp' = 'application/x-msclip' | |
| '.cmx' = 'image/x-cmx' | |
| '.cnf' = 'text/plain' | |
| '.cod' = 'image/cis-cod' | |
| '.cpio' = 'application/x-cpio' | |
| '.cpp' = 'text/plain' | |
| '.crd' = 'application/x-mscardfile' | |
| '.crl' = 'application/pkix-crl' | |
| '.crt' = 'application/x-x509-ca-cert' | |
| '.csh' = 'application/x-csh' | |
| '.cs' = 'text/plain' | |
| '.css' = 'text/css' | |
| '.csv' = 'application/octet-stream' | |
| '.cur' = 'application/octet-stream' | |
| '.dcr' = 'application/x-director' | |
| '.deploy' = 'application/octet-stream' | |
| '.der' = 'application/x-x509-ca-cert' | |
| '.dib' = 'image/bmp' | |
| '.dir' = 'application/x-director' | |
| '.disco' = 'text/xml' | |
| '.dll' = 'application/x-msdownload' | |
| '.dll.config' = 'text/xml' | |
| '.dlm' = 'text/dlm' | |
| '.doc' = 'application/msword' | |
| '.docm' = 'application/vnd.ms-word.document.macroEnabled.12' | |
| '.docx' = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' | |
| '.dot' = 'application/msword' | |
| '.dotm' = 'application/vnd.ms-word.template.macroEnabled.12' | |
| '.dotx' = 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' | |
| '.dsp' = 'application/octet-stream' | |
| '.dtd' = 'text/xml' | |
| '.dvi' = 'application/x-dvi' | |
| '.dwf' = 'drawing/x-dwf' | |
| '.dwp' = 'application/octet-stream' | |
| '.dxr' = 'application/x-director' | |
| '.eml' = 'message/rfc822' | |
| '.emz' = 'application/octet-stream' | |
| '.eot' = 'application/octet-stream' | |
| '.eps' = 'application/postscript' | |
| '.etx' = 'text/x-setext' | |
| '.evy' = 'application/envoy' | |
| '.exe' = 'application/octet-stream' | |
| '.exe.config' = 'text/xml' | |
| '.fdf' = 'application/vnd.fdf' | |
| '.fif' = 'application/fractals' | |
| '.fla' = 'application/octet-stream' | |
| '.flr' = 'x-world/x-vrml' | |
| '.flv' = 'video/x-flv' | |
| '.gif' = 'image/gif' | |
| '.gtar' = 'application/x-gtar' | |
| '.gz' = 'application/x-gzip' | |
| '.h' = 'text/plain' | |
| '.hdf' = 'application/x-hdf' | |
| '.hdml' = 'text/x-hdml' | |
| '.hhc' = 'application/x-oleobject' | |
| '.hhk' = 'application/octet-stream' | |
| '.hhp' = 'application/octet-stream' | |
| '.hlp' = 'application/winhlp' | |
| '.hqx' = 'application/mac-binhex40' | |
| '.hta' = 'application/hta' | |
| '.htc' = 'text/x-component' | |
| '.htm' = 'text/html' | |
| '.html' = 'text/html' | |
| '.htt' = 'text/webviewhtml' | |
| '.hxt' = 'text/html' | |
| '.ico' = 'image/x-icon' | |
| '.ics' = 'application/octet-stream' | |
| '.ief' = 'image/ief' | |
| '.iii' = 'application/x-iphone' | |
| '.inf' = 'application/octet-stream' | |
| '.ins' = 'application/x-internet-signup' | |
| '.isp' = 'application/x-internet-signup' | |
| '.IVF' = 'video/x-ivf' | |
| '.jar' = 'application/java-archive' | |
| '.java' = 'application/octet-stream' | |
| '.jck' = 'application/liquidmotion' | |
| '.jcz' = 'application/liquidmotion' | |
| '.jfif' = 'image/pjpeg' | |
| '.jpb' = 'application/octet-stream' | |
| '.jpe' = 'image/jpeg' | |
| '.jpeg' = 'image/jpeg' | |
| '.jpg' = 'image/jpeg' | |
| '.js' = 'application/x-javascript' | |
| '.jsx' = 'text/jscript' | |
| '.latex' = 'application/x-latex' | |
| '.lit' = 'application/x-ms-reader' | |
| '.lpk' = 'application/octet-stream' | |
| '.lsf' = 'video/x-la-asf' | |
| '.lsx' = 'video/x-la-asf' | |
| '.lzh' = 'application/octet-stream' | |
| '.m13' = 'application/x-msmediaview' | |
| '.m14' = 'application/x-msmediaview' | |
| '.m1v' = 'video/mpeg' | |
| '.m3u' = 'audio/x-mpegurl' | |
| '.man' = 'application/x-troff-man' | |
| '.manifest' = 'application/x-ms-manifest' | |
| '.map' = 'text/plain' | |
| '.mdb' = 'application/x-msaccess' | |
| '.mdp' = 'application/octet-stream' | |
| '.me' = 'application/x-troff-me' | |
| '.mht' = 'message/rfc822' | |
| '.mhtml' = 'message/rfc822' | |
| '.mid' = 'audio/mid' | |
| '.midi' = 'audio/mid' | |
| '.mix' = 'application/octet-stream' | |
| '.mmf' = 'application/x-smaf' | |
| '.mno' = 'text/xml' | |
| '.mny' = 'application/x-msmoney' | |
| '.mov' = 'video/quicktime' | |
| '.movie' = 'video/x-sgi-movie' | |
| '.mp2' = 'video/mpeg' | |
| '.mp3' = 'audio/mpeg' | |
| '.mpa' = 'video/mpeg' | |
| '.mpe' = 'video/mpeg' | |
| '.mpeg' = 'video/mpeg' | |
| '.mpg' = 'video/mpeg' | |
| '.mpp' = 'application/vnd.ms-project' | |
| '.mpv2' = 'video/mpeg' | |
| '.ms' = 'application/x-troff-ms' | |
| '.msi' = 'application/octet-stream' | |
| '.mso' = 'application/octet-stream' | |
| '.mvb' = 'application/x-msmediaview' | |
| '.mvc' = 'application/x-miva-compiled' | |
| '.nc' = 'application/x-netcdf' | |
| '.nsc' = 'video/x-ms-asf' | |
| '.nws' = 'message/rfc822' | |
| '.ocx' = 'application/octet-stream' | |
| '.oda' = 'application/oda' | |
| '.odc' = 'text/x-ms-odc' | |
| '.ods' = 'application/oleobject' | |
| '.one' = 'application/onenote' | |
| '.onea' = 'application/onenote' | |
| '.onetoc' = 'application/onenote' | |
| '.onetoc2' = 'application/onenote' | |
| '.onetmp' = 'application/onenote' | |
| '.onepkg' = 'application/onenote' | |
| '.osdx' = 'application/opensearchdescription+xml' | |
| '.p10' = 'application/pkcs10' | |
| '.p12' = 'application/x-pkcs12' | |
| '.p7b' = 'application/x-pkcs7-certificates' | |
| '.p7c' = 'application/pkcs7-mime' | |
| '.p7m' = 'application/pkcs7-mime' | |
| '.p7r' = 'application/x-pkcs7-certreqresp' | |
| '.p7s' = 'application/pkcs7-signature' | |
| '.pbm' = 'image/x-portable-bitmap' | |
| '.pcx' = 'application/octet-stream' | |
| '.pcz' = 'application/octet-stream' | |
| '.pdf' = 'application/pdf' | |
| '.pfb' = 'application/octet-stream' | |
| '.pfm' = 'application/octet-stream' | |
| '.pfx' = 'application/x-pkcs12' | |
| '.pgm' = 'image/x-portable-graymap' | |
| '.pko' = 'application/vnd.ms-pki.pko' | |
| '.pma' = 'application/x-perfmon' | |
| '.pmc' = 'application/x-perfmon' | |
| '.pml' = 'application/x-perfmon' | |
| '.pmr' = 'application/x-perfmon' | |
| '.pmw' = 'application/x-perfmon' | |
| '.png' = 'image/png' | |
| '.pnm' = 'image/x-portable-anymap' | |
| '.pnz' = 'image/png' | |
| '.pot' = 'application/vnd.ms-powerpoint' | |
| '.potm' = 'application/vnd.ms-powerpoint.template.macroEnabled.12' | |
| '.potx' = 'application/vnd.openxmlformats-officedocument.presentationml.template' | |
| '.ppam' = 'application/vnd.ms-powerpoint.addin.macroEnabled.12' | |
| '.ppm' = 'image/x-portable-pixmap' | |
| '.pps' = 'application/vnd.ms-powerpoint' | |
| '.ppsm' = 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' | |
| '.ppsx' = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' | |
| '.ppt' = 'application/vnd.ms-powerpoint' | |
| '.pptm' = 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' | |
| '.pptx' = 'application/vnd.openxmlformats-officedocument.presentationml.presentation' | |
| '.prf' = 'application/pics-rules' | |
| '.prm' = 'application/octet-stream' | |
| '.prx' = 'application/octet-stream' | |
| '.ps' = 'application/postscript' | |
| '.psd' = 'application/octet-stream' | |
| '.psm' = 'application/octet-stream' | |
| '.psp' = 'application/octet-stream' | |
| '.pub' = 'application/x-mspublisher' | |
| '.qt' = 'video/quicktime' | |
| '.qtl' = 'application/x-quicktimeplayer' | |
| '.qxd' = 'application/octet-stream' | |
| '.ra' = 'audio/x-pn-realaudio' | |
| '.ram' = 'audio/x-pn-realaudio' | |
| '.rar' = 'application/octet-stream' | |
| '.ras' = 'image/x-cmu-raster' | |
| '.rf' = 'image/vnd.rn-realflash' | |
| '.rgb' = 'image/x-rgb' | |
| '.rm' = 'application/vnd.rn-realmedia' | |
| '.rmi' = 'audio/mid' | |
| '.roff' = 'application/x-troff' | |
| '.rpm' = 'audio/x-pn-realaudio-plugin' | |
| '.rtf' = 'application/rtf' | |
| '.rtx' = 'text/richtext' | |
| '.scd' = 'application/x-msschedule' | |
| '.sct' = 'text/scriptlet' | |
| '.sea' = 'application/octet-stream' | |
| '.setpay' = 'application/set-payment-initiation' | |
| '.setreg' = 'application/set-registration-initiation' | |
| '.sgml' = 'text/sgml' | |
| '.sh' = 'application/x-sh' | |
| '.shar' = 'application/x-shar' | |
| '.sit' = 'application/x-stuffit' | |
| '.sldm' = 'application/vnd.ms-powerpoint.slide.macroEnabled.12' | |
| '.sldx' = 'application/vnd.openxmlformats-officedocument.presentationml.slide' | |
| '.smd' = 'audio/x-smd' | |
| '.smi' = 'application/octet-stream' | |
| '.smx' = 'audio/x-smd' | |
| '.smz' = 'audio/x-smd' | |
| '.snd' = 'audio/basic' | |
| '.snp' = 'application/octet-stream' | |
| '.spc' = 'application/x-pkcs7-certificates' | |
| '.spl' = 'application/futuresplash' | |
| '.src' = 'application/x-wais-source' | |
| '.ssm' = 'application/streamingmedia' | |
| '.sst' = 'application/vnd.ms-pki.certstore' | |
| '.stl' = 'application/vnd.ms-pki.stl' | |
| '.sv4cpio' = 'application/x-sv4cpio' | |
| '.sv4crc' = 'application/x-sv4crc' | |
| '.swf' = 'application/x-shockwave-flash' | |
| '.t' = 'application/x-troff' | |
| '.tar' = 'application/x-tar' | |
| '.tcl' = 'application/x-tcl' | |
| '.tex' = 'application/x-tex' | |
| '.texi' = 'application/x-texinfo' | |
| '.texinfo' = 'application/x-texinfo' | |
| '.tgz' = 'application/x-compressed' | |
| '.thmx' = 'application/vnd.ms-officetheme' | |
| '.thn' = 'application/octet-stream' | |
| '.tif' = 'image/tiff' | |
| '.tiff' = 'image/tiff' | |
| '.toc' = 'application/octet-stream' | |
| '.tr' = 'application/x-troff' | |
| '.trm' = 'application/x-msterminal' | |
| '.tsv' = 'text/tab-separated-values' | |
| '.ttf' = 'application/octet-stream' | |
| '.txt' = 'text/plain' | |
| '.u32' = 'application/octet-stream' | |
| '.uls' = 'text/iuls' | |
| '.ustar' = 'application/x-ustar' | |
| '.vbs' = 'text/vbscript' | |
| '.vcf' = 'text/x-vcard' | |
| '.vcs' = 'text/plain' | |
| '.vdx' = 'application/vnd.ms-visio.viewer' | |
| '.vml' = 'text/xml' | |
| '.vsd' = 'application/vnd.visio' | |
| '.vss' = 'application/vnd.visio' | |
| '.vst' = 'application/vnd.visio' | |
| '.vsto' = 'application/x-ms-vsto' | |
| '.vsw' = 'application/vnd.visio' | |
| '.vsx' = 'application/vnd.visio' | |
| '.vtx' = 'application/vnd.visio' | |
| '.wav' = 'audio/wav' | |
| '.wax' = 'audio/x-ms-wax' | |
| '.wbmp' = 'image/vnd.wap.wbmp' | |
| '.wcm' = 'application/vnd.ms-works' | |
| '.wdb' = 'application/vnd.ms-works' | |
| '.wks' = 'application/vnd.ms-works' | |
| '.wm' = 'video/x-ms-wm' | |
| '.wma' = 'audio/x-ms-wma' | |
| '.wmd' = 'application/x-ms-wmd' | |
| '.wmf' = 'application/x-msmetafile' | |
| '.wml' = 'text/vnd.wap.wml' | |
| '.wmlc' = 'application/vnd.wap.wmlc' | |
| '.wmls' = 'text/vnd.wap.wmlscript' | |
| '.wmlsc' = 'application/vnd.wap.wmlscriptc' | |
| '.wmp' = 'video/x-ms-wmp' | |
| '.wmv' = 'video/x-ms-wmv' | |
| '.wmx' = 'video/x-ms-wmx' | |
| '.wmz' = 'application/x-ms-wmz' | |
| '.wps' = 'application/vnd.ms-works' | |
| '.wri' = 'application/x-mswrite' | |
| '.wrl' = 'x-world/x-vrml' | |
| '.wrz' = 'x-world/x-vrml' | |
| '.wsdl' = 'text/xml' | |
| '.wvx' = 'video/x-ms-wvx' | |
| '.x' = 'application/directx' | |
| '.xaf' = 'x-world/x-vrml' | |
| '.xaml' = 'application/xaml+xml' | |
| '.xap' = 'application/x-silverlight-app' | |
| '.xbap' = 'application/x-ms-xbap' | |
| '.xbm' = 'image/x-xbitmap' | |
| '.xdr' = 'text/plain' | |
| '.xla' = 'application/vnd.ms-excel' | |
| '.xlam' = 'application/vnd.ms-excel.addin.macroEnabled.12' | |
| '.xlc' = 'application/vnd.ms-excel' | |
| '.xlm' = 'application/vnd.ms-excel' | |
| '.xls' = 'application/vnd.ms-excel' | |
| '.xlsb' = 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' | |
| '.xlsm' = 'application/vnd.ms-excel.sheet.macroEnabled.12' | |
| '.xlsx' = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' | |
| '.xlt' = 'application/vnd.ms-excel' | |
| '.xltm' = 'application/vnd.ms-excel.template.macroEnabled.12' | |
| '.xltx' = 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' | |
| '.xlw' = 'application/vnd.ms-excel' | |
| '.xml' = 'text/xml' | |
| '.xof' = 'x-world/x-vrml' | |
| '.xpm' = 'image/x-xpixmap' | |
| '.xps' = 'application/vnd.ms-xpsdocument' | |
| '.xsd' = 'text/xml' | |
| '.xsf' = 'text/xml' | |
| '.xsl' = 'text/xml' | |
| '.xslt' = 'text/xml' | |
| '.xsn' = 'application/octet-stream' | |
| '.xtp' = 'application/octet-stream' | |
| '.xwd' = 'image/x-xwindowdump' | |
| '.z' = 'application/x-compress' | |
| '.zip' = 'application/x-zip-compressed' | |
| } | |
| Main $Args | |
| exit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment