-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(repeater): establish bridges integration
closes #170
- Loading branch information
Showing
17 changed files
with
366 additions
and
39 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
162 changes: 162 additions & 0 deletions
162
src/SecTester.Repeater/Bus/Formatters/MessagePackHttpHeadersFormatter.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Linq; | ||
using MessagePack; | ||
using MessagePack.Formatters; | ||
|
||
namespace SecTester.Repeater.Bus.Formatters; | ||
|
||
// Headers formatter is to be support javascript `undefined` which is treated as null (0xC0) | ||
// https://www.npmjs.com/package/@msgpack/msgpack#messagepack-mapping-table | ||
// https://github.com/msgpack/msgpack/blob/master/spec.md#nil-format | ||
|
||
public class MessagePackHttpHeadersFormatter: IMessagePackFormatter< | ||
IEnumerable<KeyValuePair<string, IEnumerable<string>>> | ||
> | ||
{ | ||
public MessagePackHttpHeadersFormatter() | ||
{ | ||
// noop | ||
} | ||
|
||
public void Serialize(ref MessagePackWriter writer, IEnumerable<KeyValuePair<string, IEnumerable<string>>> value, | ||
MessagePackSerializerOptions options) | ||
{ | ||
|
||
if (value == null) | ||
{ | ||
writer.WriteNil(); | ||
} | ||
else | ||
{ | ||
var count = value.Count(); | ||
|
||
writer.WriteMapHeader(count); | ||
|
||
SerializeMap(ref writer, value); | ||
} | ||
} | ||
|
||
|
||
|
||
public IEnumerable<KeyValuePair<string, IEnumerable<string>>> Deserialize(ref MessagePackReader reader, | ||
MessagePackSerializerOptions options) | ||
{ | ||
switch (reader.NextMessagePackType) | ||
{ | ||
case MessagePackType.Nil: | ||
return null; | ||
case MessagePackType.Map: | ||
break; | ||
default: | ||
throw new MessagePackSerializationException(string.Format(CultureInfo.InvariantCulture, | ||
"Unrecognized code: 0x{0:X2} but expected to be a map or null", reader.NextCode)); | ||
} | ||
|
||
var length = reader.ReadMapHeader(); | ||
|
||
options.Security.DepthStep(ref reader); | ||
|
||
try | ||
{ | ||
return DeserializeMap(ref reader, length, options); | ||
} | ||
finally | ||
{ | ||
reader.Depth--; | ||
} | ||
} | ||
|
||
private static void SerializeMap(ref MessagePackWriter writer, IEnumerable<KeyValuePair<string, IEnumerable<string>>> value) | ||
{ | ||
|
||
foreach (var item in value) | ||
{ | ||
writer.Write(item.Key); | ||
|
||
var headersCount = item.Value.Count(); | ||
|
||
if (headersCount == 1) | ||
{ | ||
writer.Write(item.Value.First()); | ||
} | ||
else | ||
{ | ||
writer.WriteArrayHeader(headersCount); | ||
|
||
foreach (var subItem in item.Value) | ||
{ | ||
writer.Write(subItem); | ||
} | ||
} | ||
}; | ||
} | ||
|
||
|
||
private static List<KeyValuePair<string, IEnumerable<string>>> DeserializeMap(ref MessagePackReader reader, int length, MessagePackSerializerOptions options) | ||
{ | ||
var result = new List<KeyValuePair<string, IEnumerable<string>>>(length); | ||
|
||
for ( int i = 0 ; i < length ; i++ ) | ||
{ | ||
var key = DeserializeString(ref reader); | ||
|
||
switch (reader.NextMessagePackType) | ||
{ | ||
case MessagePackType.String: | ||
result.Add(new KeyValuePair<string, IEnumerable<string>>(key, new List<string>{DeserializeString(ref reader)})); | ||
break; | ||
case MessagePackType.Array: | ||
result.Add(new KeyValuePair<string, IEnumerable<string>>(key, DeserializeArray(ref reader, reader.ReadArrayHeader(), options))); | ||
break; | ||
default: | ||
throw new MessagePackSerializationException(string.Format(CultureInfo.InvariantCulture, "Unrecognized code: 0x{0:X2} but expected to be either a string or an array.", reader.NextCode)); | ||
} | ||
} | ||
|
||
|
||
return result; | ||
} | ||
|
||
private static IEnumerable<string> DeserializeArray(ref MessagePackReader reader, int length, MessagePackSerializerOptions options) | ||
{ | ||
var result = new List<string>(length); | ||
|
||
if (length == 0) | ||
{ | ||
return result; | ||
} | ||
|
||
options.Security.DepthStep(ref reader); | ||
try | ||
{ | ||
for ( int i = 0 ; i < length ; i++ ) | ||
{ | ||
result.Add(DeserializeString(ref reader)); | ||
} | ||
} | ||
finally | ||
{ | ||
reader.Depth--; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private static string DeserializeString(ref MessagePackReader reader) | ||
{ | ||
if (reader.NextMessagePackType != MessagePackType.String) | ||
{ | ||
throw new MessagePackSerializationException(string.Format(CultureInfo.InvariantCulture, "Unrecognized code: 0x{0:X2} but expected to be a string.", reader.NextCode)); | ||
} | ||
|
||
var value = reader.ReadString(); | ||
|
||
if (null == value) | ||
{ | ||
throw new MessagePackSerializationException(string.Format(CultureInfo.InvariantCulture, "Nulls are not allowed.")); | ||
} | ||
|
||
return value; | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/SecTester.Repeater/Bus/Formatters/MessagePackHttpMethodFormatter.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System.Globalization; | ||
using System.Net.Http; | ||
using MessagePack; | ||
using MessagePack.Formatters; | ||
|
||
namespace SecTester.Repeater.Bus.Formatters; | ||
|
||
public class MessagePackHttpMethodFormatter : IMessagePackFormatter<HttpMethod?> | ||
{ | ||
public void Serialize(ref MessagePackWriter writer, HttpMethod? value, MessagePackSerializerOptions options) | ||
{ | ||
if (null == value) | ||
{ | ||
writer.WriteNil(); | ||
} | ||
else | ||
{ | ||
writer.Write(value.Method); | ||
} | ||
} | ||
|
||
public HttpMethod? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) | ||
{ | ||
switch (reader.NextMessagePackType) | ||
{ | ||
case MessagePackType.Nil: | ||
return null; | ||
case MessagePackType.String: | ||
var method = reader.ReadString(); | ||
return string.IsNullOrWhiteSpace(method) ? null : new HttpMethod(method); | ||
default: | ||
throw new MessagePackSerializationException(string.Format(CultureInfo.InvariantCulture, | ||
"Unrecognized code: 0x{0:X2} but expected to be either a string or null.", reader.NextCode)); | ||
} | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
src/SecTester.Repeater/Bus/Formatters/SocketIOIncomingRequestMapper.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Net.Http; | ||
|
||
namespace SecTester.Repeater.Bus.Formatters; | ||
|
||
public class SocketIOIncomingRequestMapper | ||
{ | ||
private const string Protocol = "protocol"; | ||
private const string Url = "url"; | ||
private const string Method = "method"; | ||
private const string Body = "body"; | ||
private const string Headers = "headers"; | ||
|
||
public static IncomingRequest ToRequest(Dictionary<object, object> dictionary) | ||
{ | ||
var protocol = dictionary.TryGetValue(Protocol, out var p) && p is string && Enum.TryParse<Protocol>(p.ToString(), out var e) | ||
? e | ||
: SecTester.Repeater.Protocol.Http; | ||
|
||
var uri = dictionary.TryGetValue(Url, out var u) && u is string | ||
? new Uri(u.ToString()) | ||
: throw new InvalidDataException(FormatPropertyError(Url)); | ||
|
||
var method = dictionary.TryGetValue(Method, out var m) && m is string | ||
? new HttpMethod(m.ToString()) | ||
: HttpMethod.Get; | ||
|
||
var body = dictionary.TryGetValue(Body, out var b) && b is string ? b.ToString() : null; | ||
|
||
dictionary.TryGetValue(Headers, out var headers); | ||
|
||
return new IncomingRequest(uri) | ||
{ | ||
Protocol = protocol, | ||
Body = body, | ||
Method = method, | ||
Headers = MapHeaders(headers as Dictionary<object, object>) | ||
}; | ||
} | ||
|
||
private static IEnumerable<KeyValuePair<string, IEnumerable<string>>> MapHeaders(Dictionary<object, object>? headers) | ||
{ | ||
var result = new List<KeyValuePair<string, IEnumerable<string>>>(headers?.Count ?? 0); | ||
|
||
if (null == headers) | ||
{ | ||
return result; | ||
} | ||
|
||
foreach (var kvp in headers) | ||
{ | ||
var key = kvp.Key.ToString(); | ||
|
||
if (null == kvp.Value) | ||
{ | ||
result.Add(new KeyValuePair<string, IEnumerable<string>>(key, new List<string>())); | ||
continue; | ||
} | ||
|
||
if (kvp.Value is string) | ||
{ | ||
result.Add(new KeyValuePair<string, IEnumerable<string>>(key, new List<string> | ||
{ kvp.Value.ToString() })); | ||
continue; | ||
} | ||
|
||
if (kvp.Value is not object[] objects) | ||
{ | ||
continue; | ||
} | ||
|
||
var values = objects.OfType<string>().Select(value => value.ToString()).ToList(); | ||
|
||
result.Add(new KeyValuePair<string, IEnumerable<string>>(key, values)); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private static string FormatPropertyError(string propName) => $"{propName} is either null or has an invalid data type"; | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,30 @@ | ||
using System.Collections.Generic; | ||
using MessagePack; | ||
using SecTester.Repeater.Bus.Formatters; | ||
using SecTester.Repeater.Runners; | ||
|
||
namespace SecTester.Repeater.Bus; | ||
|
||
[MessagePackObject(true)] | ||
[MessagePackObject] | ||
public record OutgoingResponse : IResponse | ||
{ | ||
[Key("statusCode")] | ||
public int? StatusCode { get; set; } | ||
|
||
[Key("body")] | ||
public string? Body { get; set; } | ||
|
||
[Key("message")] | ||
public string? Message { get; set; } | ||
|
||
[Key("errorCode")] | ||
public string? ErrorCode { get; set; } | ||
|
||
[Key("protocol")] | ||
public Protocol Protocol { get; set; } = Protocol.Http; | ||
|
||
[Key("headers")] | ||
[MessagePackFormatter(typeof(MessagePackHttpHeadersFormatter))] | ||
public IEnumerable<KeyValuePair<string, IEnumerable<string>>> Headers { get; set; } = | ||
new List<KeyValuePair<string, IEnumerable<string>>>(); | ||
} |
This file contains 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
Oops, something went wrong.