Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
WebSniffer.cs
1using System;
3using System.Text;
4using System.Threading;
5using System.Threading.Tasks;
6using Waher.Content;
8using Waher.Events;
14using Waher.Security;
15
17{
21 public class WebSniffer : SnifferBase, IDisposable
22 {
23 private readonly BinaryPresentationMethod binaryPresentationMethod;
24 private readonly DateTime created = DateTime.UtcNow;
25 private readonly DateTime expires;
26 private readonly ICommunicationLayer comLayer;
27 private readonly string[] privileges;
28 private readonly string userVariable;
29 private readonly string resource;
30 private readonly string snifferId;
31 private readonly bool feedbackCheck;
32 private string[] tabIds = null;
33 private DateTime tabIdTimestamp = DateTime.MinValue;
34 private Cache<string, bool> outgoing;
35
47 public WebSniffer(string SnifferId, string PageResource, TimeSpan MaxLife, BinaryPresentationMethod BinaryPresentationMethod, ICommunicationLayer ComLayer,
48 string UserVariable, params string[] Privileges)
49 : base("Web Sniffer: " + PageResource)
50 {
51 this.expires = DateTime.UtcNow.Add(MaxLife);
52 this.comLayer = ComLayer;
53 this.snifferId = SnifferId;
54 this.resource = PageResource;
55 this.binaryPresentationMethod = BinaryPresentationMethod;
56 this.tabIds = null;
57 this.userVariable = UserVariable;
58 this.privileges = Privileges;
59 this.feedbackCheck = ComLayer is HttpServer;
60
61 if (this.feedbackCheck)
62 this.outgoing = new Cache<string, bool>(int.MaxValue, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1), true);
63 else
64 this.outgoing = null;
65 }
66
68 public override Task DisposeAsync()
69 {
70 this.outgoing?.Dispose();
71 this.outgoing = null;
72
73 return base.DisposeAsync();
74 }
75
79 public string SnifferId => this.snifferId;
80
84 public override BinaryPresentationMethod BinaryPresentationMethod => this.binaryPresentationMethod;
85
86 private Task Process(DateTime Timestamp, string Message, string Function)
87 {
88 if (Timestamp >= this.expires)
89 return this.Close();
90 else
91 return this.Push(Timestamp, Message, Function, true);
92 }
93
94 private async Task Push(DateTime Timestamp, string Message, string Function, bool CloseIfNoTabs)
95 {
96 try
97 {
98 DateTime Now = DateTime.UtcNow;
99
100 if ((Now - this.tabIdTimestamp).TotalSeconds > 2 || this.tabIds is null || this.tabIds.Length == 0)
101 {
102 this.tabIds = ClientEvents.GetTabIDsForLocation(this.resource, true, "SnifferId", this.snifferId);
103 this.tabIdTimestamp = Now;
104 }
105
106 if (this.feedbackCheck && Message.StartsWith('{') && Message.EndsWith('}'))
107 {
108 try
109 {
110 object Parsed = JSON.Parse(Message);
111 if (Parsed is IDictionary<string, object> Obj &&
112 Obj.TryGetValue("data", out object Temp) &&
113 Temp is IDictionary<string, object> Obj2 &&
114 Obj2.TryGetValue("timestamp", out object Timestamp2) &&
115 Obj2.TryGetValue("message", out object Message2) &&
116 (this.outgoing?.ContainsKey(this.ToJson(Timestamp2, Message2)) ?? true))
117 {
118 return;
119 }
120 }
121 catch (Exception)
122 {
123 // Ignore
124 }
125 }
126
127 string Data = this.ToJson(XML.Encode(Timestamp), Message);
128
129 this.outgoing?.Add(Data, true);
130
131 int Tabs = await ClientEvents.PushEvent(this.tabIds, Function, Data, true, this.userVariable, this.privileges);
132
133 if (CloseIfNoTabs && Tabs <= 0 && (Now - this.created).TotalSeconds >= 5)
134 await this.Close();
135 }
136 catch (Exception ex)
137 {
138 Log.Exception(ex);
139 }
140 }
141
142 private string ToJson(object Timestamp, object Message)
143 {
144 return JSON.Encode(new KeyValuePair<string, object>[]
145 {
146 new KeyValuePair<string, object>("timestamp", Timestamp),
147 new KeyValuePair<string, object>("message", Message)
148 }, false);
149 }
150
151 private async Task Close()
152 {
153 await this.Push(DateTime.UtcNow, "Sniffer closed.", "Information", false);
154 this.comLayer.Remove(this);
155 await this.DisposeAsync();
156 }
157
158 private Task Process(DateTime Timestamp, byte[] Data, int Offset, int Count, string Function)
159 {
160 if (Timestamp >= this.expires)
161 return this.Close();
162 else
163 return this.Push(Timestamp, this.HexOutput(Data, Offset, Count), Function, true);
164 }
165
166 private string HexOutput(byte[] Data, int Offset, int Count)
167 {
168 if (Data is null)
169 return "<" + Count.ToString() + " bytes>";
170
171 switch (Data is null ? BinaryPresentationMethod.ByteCount : this.binaryPresentationMethod)
172 {
173 case BinaryPresentationMethod.Hexadecimal:
174 StringBuilder sb = new StringBuilder();
175 int i = 0;
176 bool First = true;
177 byte b;
178
179 while (Count-- > 0)
180 {
181 b = Data[Offset++];
182
183 if (i > 0)
184 sb.Append(' ');
185 else if (First)
186 First = false;
187 else
188 sb.AppendLine();
189
190 sb.Append(b.ToString("X2"));
191
192 i = (i + 1) & 31;
193 }
194
195 return sb.ToString();
196
197 case BinaryPresentationMethod.Base64:
198 return Convert.ToBase64String(Data);
199
200 case BinaryPresentationMethod.ByteCount:
201 default:
202 return "<" + Count.ToString() + " bytes>";
203 }
204 }
205
211 public override Task Process(SnifferError Event, CancellationToken Cancel)
212 {
213 return this.Process(Event.Timestamp, Event.Text, "Error");
214 }
215
221 public override Task Process(SnifferException Event, CancellationToken Cancel)
222 {
223 return this.Process(Event.Timestamp, Event.Text, "Exception");
224 }
225
231 public override Task Process(SnifferInformation Event, CancellationToken Cancel)
232 {
233 return this.Process(Event.Timestamp, Event.Text, "Information");
234 }
235
241 public override Task Process(SnifferRxBinary Event, CancellationToken Cancel)
242 {
243 return this.Process(Event.Timestamp, Event.Data, Event.Offset, Event.Count, "Rx");
244 }
245
251 public override Task Process(SnifferRxText Event, CancellationToken Cancel)
252 {
253 return this.Process(Event.Timestamp, Event.Text, "Rx");
254 }
255
261 public override Task Process(SnifferTxBinary Event, CancellationToken Cancel)
262 {
263 return this.Process(Event.Timestamp, Event.Data, Event.Offset, Event.Count, "Tx");
264 }
265
271 public override Task Process(SnifferTxText Event, CancellationToken Cancel)
272 {
273 return this.Process(Event.Timestamp, Event.Text, "Tx");
274 }
275
281 public override Task Process(SnifferWarning Event, CancellationToken Cancel)
282 {
283 return this.Process(Event.Timestamp, Event.Text, "Warning");
284 }
285
286 }
287}
Helps with common JSON-related tasks.
Definition: JSON.cs:16
static object Parse(string Json)
Parses a JSON string.
Definition: JSON.cs:45
static string Encode(string s)
Encodes a string for inclusion in JSON.
Definition: JSON.cs:537
Helps with common XML-related tasks.
Definition: XML.cs:21
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:29
Class representing an event.
Definition: Event.cs:11
DateTime Timestamp
Timestamp of event.
Definition: Event.cs:117
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1657
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
Definition: ClientEvents.cs:51
static string[] GetTabIDsForLocation(string Location)
Gets the Tab IDs of all tabs that display a particular resource.
Sending sniffer events to the corresponding web page(s).
Definition: WebSniffer.cs:22
override Task Process(SnifferRxBinary Event, CancellationToken Cancel)
Processes a binary reception event.
Definition: WebSniffer.cs:241
override Task Process(SnifferInformation Event, CancellationToken Cancel)
Processes an information event.
Definition: WebSniffer.cs:231
override Task Process(SnifferError Event, CancellationToken Cancel)
Processes an error event.
Definition: WebSniffer.cs:211
override Task DisposeAsync()
IDisposableAsync.DisposeAsync
Definition: WebSniffer.cs:68
WebSniffer(string SnifferId, string PageResource, TimeSpan MaxLife, BinaryPresentationMethod BinaryPresentationMethod, ICommunicationLayer ComLayer, string UserVariable, params string[] Privileges)
Sending sniffer events to the corresponding web page(s).
Definition: WebSniffer.cs:47
override Task Process(SnifferRxText Event, CancellationToken Cancel)
Processes a text reception event.
Definition: WebSniffer.cs:251
override Task Process(SnifferWarning Event, CancellationToken Cancel)
Processes a warning event.
Definition: WebSniffer.cs:281
override BinaryPresentationMethod BinaryPresentationMethod
How the sniffer handles binary data.
Definition: WebSniffer.cs:84
override Task Process(SnifferTxText Event, CancellationToken Cancel)
Processes a text transmission event.
Definition: WebSniffer.cs:271
override Task Process(SnifferTxBinary Event, CancellationToken Cancel)
Processes a binary transmission event.
Definition: WebSniffer.cs:261
override Task Process(SnifferException Event, CancellationToken Cancel)
Processes an exception event.
Definition: WebSniffer.cs:221
Implements an HTTP server.
Definition: HttpServer.cs:41
Represents a sniffer error event.
Definition: SnifferError.cs:11
Represents a sniffer exception event.
Represents a sniffer information event.
Represents a sniffer binary reception event.
Represents a sniffer text reception event.
Represents a sniffer binary transmission event.
Represents a sniffer text transmission event.
Represents a sniffer warning event.
Abstract base class for sniffers. Implements default method overloads.
Definition: SnifferBase.cs:15
Implements an in-memory cache.
Definition: Cache.cs:17
void Dispose()
IDisposable.Dispose
Definition: Cache.cs:99
void Add(KeyType Key, ValueType Value)
Adds an item to the cache.
Definition: Cache.cs:446
Interface for observable classes implementing communication protocols.
BinaryPresentationMethod
How binary data is to be presented.