-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHTTPServer.cs
122 lines (99 loc) · 4.43 KB
/
HTTPServer.cs
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using System;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MerakiLocationVisualizer
{
public class HTTPServer
{
private const int HandlerThread = 2;
private readonly HttpListener listener;
public HTTPServer(HttpListener listener, string url)
{
this.listener = listener;
listener.Prefixes.Add(url);
}
private void ProcessRequestHandler(Task<HttpListenerContext> result)
{
var context = result.Result;
HttpListenerRequest typeoHTTPRrequest = context.Request;
HttpListenerResponse serverResponse = context.Response;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// INSERT YOUR KEY AND SECRET BELOW
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
string validationResponse = "the.string.you.copied.from.the.meraki.portal";
string MySharedSecret = "the.secret.you.configured.in.the.meraki.portal";
if (!listener.IsListening)
return;
// Start new listener which replace this
listener.GetContextAsync().ContinueWith(ProcessRequestHandler);
// Read request
string request = new StreamReader(context.Request.InputStream).ReadToEnd();
// the only GET we care about is the Meraki backend verifying this server as
// a POST target, so we send the expected response below. Firewall yourself
// appropriately...
if (typeoHTTPRrequest.HttpMethod == "GET")
{
Console.WriteLine("SUCCESSFUL GET");
var responseBytes = System.Text.Encoding.UTF8.GetBytes(validationResponse);
serverResponse.ContentLength64 = responseBytes.Length;
var output = serverResponse.OutputStream;
output.WriteAsync(responseBytes, 0, responseBytes.Length);
output.Close();
}
else if(typeoHTTPRrequest.HttpMethod == "POST")
{
Console.WriteLine("SUCCESSFUL POST");
// the v2 API will return a non-rfc "NaN" string where you've been
// told to expect a float/double. The following prevents that from
// nuking everything. Pre-req is .NET 5.0
var jsonOptions = new JsonSerializerOptions
{
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
// | JsonNumberHandling.WriteAsString
};
DevicesSeen observationReport = new DevicesSeen();
observationReport = JsonSerializer.Deserialize<DevicesSeen>(request, jsonOptions);
// is the shared secret a match
if (observationReport.Secret != MySharedSecret)
{
Console.WriteLine("Shared Secret does not match. Discarding received data.");
return;
}
// for debug
//DumpAsYaml(observationReport);
// Deal with the POSTed data
DataParser.ProcessData(observationReport);
}
}
public void Start()
{
if (listener.IsListening)
return;
listener.Start();
for (int i = 0; i < HandlerThread; i++)
{
listener.GetContextAsync().ContinueWith(ProcessRequestHandler);
}
}
public void Stop()
{
if (listener.IsListening)
listener.Stop();
}
// object dumper for debug/dev
public static void DumpAsYaml(object obj)
{
var stringBuilder = new System.Text.StringBuilder();
var serializer = new YamlDotNet.Serialization.Serializer();
serializer.Serialize(new System.CodeDom.Compiler.IndentedTextWriter(new StringWriter(stringBuilder)), obj);
Console.WriteLine(stringBuilder);
}
}
}