-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMathServer.ps1
More file actions
92 lines (86 loc) · 3.48 KB
/
MathServer.ps1
File metadata and controls
92 lines (86 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<#
.SYNOPSIS
Math Server
.DESCRIPTION
A simple math server.
Each first request segment must map to a static method on the `[Math]` class
.EXAMPLE
./MathServer.ps1
#>
param(
# The rootUrl of the server. By default, a random loopback address.
[string]$RootUrl=
"http://127.0.0.1:$(Get-Random -Minimum 4200 -Maximum 42000)/"
)
$httpListener = [Net.HttpListener]::new()
$httpListener.Prefixes.Add($RootUrl)
Write-Warning "Listening on $RootUrl $($httpListener.Start())"
$io = [Ordered]@{ # Pack our job input into an IO dictionary
HttpListener = $httpListener
}
# Our server is a thread job
Start-ThreadJob -ScriptBlock {param([Collections.IDictionary]$io)
$psvariable = $ExecutionContext.SessionState.PSVariable
foreach ($key in $io.Keys) { # First, let's unpack.
if ($io[$key] -is [PSVariable]) { $psvariable.set($io[$key]) }
else { $psvariable.set($key, $io[$key]) }
}
$staticMembers = [Math] | Get-Member -Static
# Listen for the next request
:nextRequest while ($httpListener.IsListening) {
$getContext = $httpListener.GetContextAsync()
while (-not $getContext.Wait(17)) { }
$request, $reply =
$getContext.Result.Request, $getContext.Result.Response
$segments = @($request.Url.Segments)
if ($segments.Length -le 1) {
$reply.ContentType = 'text/html'
$memberList = @(
"<ul>"
foreach ($staticMember in $staticMembers) {
"<li>"
"<a href='/$($staticMember.name)'>$(
$staticMember.name
)</a>"
"</li>"
}
"</ul>"
) -join [Environment]::NewLine
$reply.Close($OutputEncoding.GetBytes($memberList), $false)
continue nextRequest
} else {
$firstSegment = $segments[1] -replace '/'
$mathMember = [Math]::$firstSegment
if ($null -eq $mathMember) {
$reply.StatusCode = 404
$reply.Close()
continue nextRequest
}
}
if ($mathMember.Invoke) {
$mathArgs =
if ($segments.Length -ge 3) {
@(for ($segmentNumber = 2; $segmentNumber -lt $segments.Length; $segmentNumber++) {
$segments[$segmentNumber] -replace '/' -as [double]
})
} else {
$Reply.Close($OutputEncoding.GetBytes("$(
$mathMember.OverloadDefinitions -join [Environment]::NewLine
)"), $false)
}
try {
$result = $mathMember.Invoke($mathArgs)
$Reply.Close($OutputEncoding.GetBytes("$result"), $false)
} catch {
$Reply.Close($OutputEncoding.GetBytes("$($_ | Out-String)"), $false)
}
} else {
$Reply.Close($OutputEncoding.GetBytes("$mathMember"), $false)
}
}
} -ThrottleLimit 100 -ArgumentList $IO -Name "$RootUrl" | # Output our job,
Add-Member -NotePropertyMembers @{ # but attach a few properties first:
HttpListener=$httpListener # * The listener (so we can stop it)
IO=$IO # * The IO (so we can change it)
Url="$RootUrl" # The URL (so we can easily access it).
} -Force -PassThru # Pass all of that thru and return it to you.