Merge branch 'rel/1.0.0-alpha2' into dev
This commit is contained in:
commit
05da66ada0
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceRoot}/client-ts/node_modules/jasmine/bin/jasmine.js",
|
||||
"args": ["JASMINE_CONFIG_PATH=${workspaceRoot}/client-ts/Microsoft.AspNetCore.SignalR.Client.TS.Tests/jasmine.json"],
|
||||
"cwd": "${workspaceRoot}/client-ts",
|
||||
"outFiles": []
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Attach to Port",
|
||||
"address": "localhost",
|
||||
"port": 5858,
|
||||
"outFiles": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -14,6 +14,13 @@ describe("Connection", () => {
|
|||
.toThrow(new Error("Cannot resolve '/test'."));
|
||||
});
|
||||
|
||||
it("cannot be created with relative url if window object is not present", () => {
|
||||
(<any>global).window = {};
|
||||
expect(() => new HttpConnection("/test"))
|
||||
.toThrow(new Error("Cannot resolve '/test'."));
|
||||
delete (<any>global).window;
|
||||
});
|
||||
|
||||
it("starting connection fails if getting id fails", async (done) => {
|
||||
let options: IHttpConnectionOptions = {
|
||||
httpClient: <IHttpClient>{
|
||||
|
|
|
|||
|
|
@ -29,10 +29,11 @@ describe("Text Message Formatter", () => {
|
|||
|
||||
describe("Binary Message Formatter", () => {
|
||||
([
|
||||
[[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], <Uint8Array[]>[ new Uint8Array([])]],
|
||||
[[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff], <Uint8Array[]>[ new Uint8Array([0xff])]],
|
||||
[[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f], <Uint8Array[]>[ new Uint8Array([0xff]), new Uint8Array([0x7f])]],
|
||||
[[], <Uint8Array[]>[]],
|
||||
[[0x00], <Uint8Array[]>[ new Uint8Array([])]],
|
||||
[[0x01, 0xff], <Uint8Array[]>[ new Uint8Array([0xff])]],
|
||||
[[0x01, 0xff,
|
||||
0x01, 0x7f], <Uint8Array[]>[ new Uint8Array([0xff]), new Uint8Array([0x7f])]],
|
||||
] as [[number[], Uint8Array[]]]).forEach(([payload, expected_messages]) => {
|
||||
it(`should parse '${payload}' correctly`, () => {
|
||||
let messages = BinaryMessageFormat.parse(new Uint8Array(payload).buffer);
|
||||
|
|
@ -41,14 +42,15 @@ describe("Binary Message Formatter", () => {
|
|||
});
|
||||
|
||||
([
|
||||
[[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Cannot read message size")],
|
||||
[[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x80, 0x00], new Error("Cannot read message size")],
|
||||
[[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")],
|
||||
[[0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")],
|
||||
[[0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")],
|
||||
[[0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")],
|
||||
[[0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00], new Error("Messages bigger than 2147483647 bytes are not supported")],
|
||||
[[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00], new Error("Incomplete message")],
|
||||
[[0x80], new Error("Cannot read message size.")],
|
||||
[[0x02, 0x01, 0x80, 0x80], new Error("Cannot read message size.")],
|
||||
[[0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80], new Error("Cannot read message size.")], // the size of the second message is cut
|
||||
[[0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01], new Error("Incomplete message.")], // second message has only size
|
||||
[[0xff, 0xff, 0xff, 0xff, 0xff], new Error("Messages bigger than 2GB are not supported.")],
|
||||
[[0x80, 0x80, 0x80, 0x80, 0x08], new Error("Messages bigger than 2GB are not supported.")],
|
||||
[[0x80, 0x80, 0x80, 0x80, 0x80], new Error("Messages bigger than 2GB are not supported.")],
|
||||
[[0x02, 0x00], new Error("Incomplete message.")],
|
||||
[[0xff, 0xff, 0xff, 0xff, 0x07], new Error("Incomplete message.")]
|
||||
] as [[number[], Error]]).forEach(([payload, expected_error]) => {
|
||||
it(`should fail to parse '${payload}'`, () => {
|
||||
expect(() => BinaryMessageFormat.parse(new Uint8Array(payload).buffer)).toThrow(expected_error);
|
||||
|
|
@ -56,8 +58,8 @@ describe("Binary Message Formatter", () => {
|
|||
});
|
||||
|
||||
([
|
||||
[[], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]],
|
||||
[[0x20], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20]],
|
||||
[[], [0x00]],
|
||||
[[0x20], [0x01, 0x20]],
|
||||
] as [[number[], number[]]]).forEach(([input, expected_payload]) => {
|
||||
it(`should write '${input}'`, () => {
|
||||
let actual = new Uint8Array(BinaryMessageFormat.write(new Uint8Array(input)));
|
||||
|
|
@ -65,4 +67,18 @@ describe("Binary Message Formatter", () => {
|
|||
expect(actual).toEqual(expected);
|
||||
})
|
||||
});
|
||||
|
||||
([0x0000, 0x0001, 0x007f, 0x0080, 0x3fff, 0x4000, 0xc0de] as number[]).forEach(size => {
|
||||
it(`messages should be roundtrippable (message size: '${size}')`, () => {
|
||||
const message = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
message.push(i & 0xff);
|
||||
}
|
||||
|
||||
var payload = new Uint8Array(message);
|
||||
expect(payload).toEqual(BinaryMessageFormat.parse(BinaryMessageFormat.write(payload))[0]);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,24 +20,21 @@ describe("MessageHubProtocol", () => {
|
|||
});
|
||||
|
||||
([
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b,
|
||||
0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x01, 0xa3, 0x45, 0x72, 0x72],
|
||||
[ [ 0x0b, 0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x01, 0xa3, 0x45, 0x72, 0x72],
|
||||
{
|
||||
type: MessageType.Completion,
|
||||
invocationId: "abc",
|
||||
error: "Err",
|
||||
result: null
|
||||
} as CompletionMessage ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
|
||||
0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ],
|
||||
[ [ 0x0a, 0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ],
|
||||
{
|
||||
type: MessageType.Completion,
|
||||
invocationId: "abc",
|
||||
error: null,
|
||||
result: "OK"
|
||||
} as CompletionMessage ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0x93, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x02 ],
|
||||
[ [ 0x07, 0x93, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x02 ],
|
||||
{
|
||||
type: MessageType.Completion,
|
||||
invocationId: "abc",
|
||||
|
|
@ -51,8 +48,7 @@ describe("MessageHubProtocol", () => {
|
|||
}));
|
||||
|
||||
([
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08 ],
|
||||
[ [ 0x07, 0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08 ],
|
||||
{
|
||||
type: MessageType.Result,
|
||||
invocationId: "abc",
|
||||
|
|
@ -65,17 +61,17 @@ describe("MessageHubProtocol", () => {
|
|||
}));
|
||||
|
||||
([
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ], new Error("Invalid payload.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90 ], new Error("Invalid payload.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc2 ], new Error("Invalid payload.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x05 ], new Error("Invalid message type.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x91, 0xa1, 0x78 ], new Error("Invalid message type.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x01 ], new Error("Invalid payload for Invocation message.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x91, 0x02 ], new Error("Invalid payload for stream Result message.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x92, 0x03, 0xa0 ], new Error("Invalid payload for Completion message.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x94, 0x03, 0xa0, 0x02, 0x00 ], new Error("Invalid payload for Completion message.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x93, 0x03, 0xa0, 0x01 ], new Error("Invalid payload for Completion message.") ],
|
||||
[ [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x93, 0x03, 0xa0, 0x03 ], new Error("Invalid payload for Completion message.") ]
|
||||
[ [ 0x00 ], new Error("Invalid payload.") ],
|
||||
[ [ 0x01, 0x90 ], new Error("Invalid payload.") ],
|
||||
[ [ 0x01, 0xc2 ], new Error("Invalid payload.") ],
|
||||
[ [ 0x02, 0x91, 0x05 ], new Error("Invalid message type.") ],
|
||||
[ [ 0x03, 0x91, 0xa1, 0x78 ], new Error("Invalid message type.") ],
|
||||
[ [ 0x02, 0x91, 0x01 ], new Error("Invalid payload for Invocation message.") ],
|
||||
[ [ 0x02, 0x91, 0x02 ], new Error("Invalid payload for stream Result message.") ],
|
||||
[ [ 0x03, 0x92, 0x03, 0xa0 ], new Error("Invalid payload for Completion message.") ],
|
||||
[ [ 0x05, 0x94, 0x03, 0xa0, 0x02, 0x00 ], new Error("Invalid payload for Completion message.") ],
|
||||
[ [ 0x04, 0x93, 0x03, 0xa0, 0x01 ], new Error("Invalid payload for Completion message.") ],
|
||||
[ [ 0x04, 0x93, 0x03, 0xa0, 0x03 ], new Error("Invalid payload for Completion message.") ]
|
||||
] as [[number[], Error]]).forEach(([payload, expected_error]) =>
|
||||
it("throws for invalid messages", () => {
|
||||
expect(() => new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer))
|
||||
|
|
@ -84,10 +80,8 @@ describe("MessageHubProtocol", () => {
|
|||
|
||||
it("can read multiple messages", () => {
|
||||
let payload = [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
|
||||
0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ];
|
||||
0x07, 0x93, 0x02, 0xa3, 0x61, 0x62, 0x63, 0x08,
|
||||
0x0a, 0x94, 0x03, 0xa3, 0x61, 0x62, 0x63, 0x03, 0xa2, 0x4f, 0x4b ];
|
||||
let messages = new MessagePackHubProtocol().parseMessages(new Uint8Array(payload).buffer);
|
||||
expect(messages).toEqual([
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,55 +21,73 @@ export namespace TextMessageFormat {
|
|||
}
|
||||
|
||||
export namespace BinaryMessageFormat {
|
||||
|
||||
// The length prefix of binary messages is encoded as VarInt. Read the comment in
|
||||
// the BinaryMessageParser.TryParseMessage for details.
|
||||
|
||||
export function write(output: Uint8Array): ArrayBuffer {
|
||||
// .byteLength does is undefined in IE10
|
||||
// msgpack5 uses returns Buffer instead of Uint8Array on IE10 and some other browser
|
||||
// in which case .byteLength does will be undefined
|
||||
let size = output.byteLength || output.length;
|
||||
let buffer = new Uint8Array(size + 8);
|
||||
|
||||
// javascript bitwise operators only support 32-bit integers
|
||||
for (let i = 7; i >= 4; i--) {
|
||||
buffer[i] = size & 0xff;
|
||||
size = size >> 8;
|
||||
let lenBuffer = [];
|
||||
do
|
||||
{
|
||||
let sizePart = size & 0x7f;
|
||||
size = size >> 7;
|
||||
if (size > 0) {
|
||||
sizePart |= 0x80;
|
||||
}
|
||||
lenBuffer.push(sizePart);
|
||||
}
|
||||
while (size > 0);
|
||||
|
||||
buffer.set(output, 8);
|
||||
// msgpack5 uses returns Buffer instead of Uint8Array on IE10 and some other browser
|
||||
// in which case .byteLength does will be undefined
|
||||
size = output.byteLength || output.length;
|
||||
|
||||
let buffer = new Uint8Array(lenBuffer.length + size);
|
||||
buffer.set(lenBuffer, 0);
|
||||
buffer.set(output, lenBuffer.length);
|
||||
return buffer.buffer;
|
||||
}
|
||||
|
||||
export function parse(input: ArrayBuffer): Uint8Array[] {
|
||||
let result: Uint8Array[] = [];
|
||||
let uint8Array = new Uint8Array(input);
|
||||
// 8 - the length prefix size
|
||||
const maxLengthPrefixSize = 5;
|
||||
const numBitsToShift = [0, 7, 14, 21, 28 ];
|
||||
|
||||
for (let offset = 0; offset < input.byteLength;) {
|
||||
|
||||
if (input.byteLength < offset + 8) {
|
||||
throw new Error("Cannot read message size")
|
||||
}
|
||||
|
||||
// Note javascript bitwise operators only support 32-bit integers - for now cutting bigger messages.
|
||||
// Tracking bug https://github.com/aspnet/SignalR/issues/613
|
||||
if (!(uint8Array[offset] == 0 && uint8Array[offset + 1] == 0 && uint8Array[offset + 2] == 0
|
||||
&& uint8Array[offset + 3] == 0 && (uint8Array[offset + 4] & 0x80) == 0)) {
|
||||
throw new Error("Messages bigger than 2147483647 bytes are not supported");
|
||||
}
|
||||
|
||||
let numBytes = 0;
|
||||
let size = 0;
|
||||
for (let i = 4; i < 8; i++) {
|
||||
size = (size << 8) | uint8Array[offset + i];
|
||||
let byteRead;
|
||||
do
|
||||
{
|
||||
byteRead = uint8Array[offset + numBytes];
|
||||
size = size | ((byteRead & 0x7f) << (numBitsToShift[numBytes]));
|
||||
numBytes++;
|
||||
}
|
||||
while (numBytes < Math.min(maxLengthPrefixSize, input.byteLength - offset) && (byteRead & 0x80) != 0);
|
||||
|
||||
if ((byteRead & 0x80) !== 0 && numBytes < maxLengthPrefixSize) {
|
||||
throw new Error("Cannot read message size.");
|
||||
}
|
||||
|
||||
if (uint8Array.byteLength >= (offset + 8 + size)) {
|
||||
if (numBytes === maxLengthPrefixSize && byteRead > 7) {
|
||||
throw new Error("Messages bigger than 2GB are not supported.");
|
||||
}
|
||||
|
||||
if (uint8Array.byteLength >= (offset + numBytes + size)) {
|
||||
// IE does not support .slice() so use subarray
|
||||
result.push(uint8Array.slice
|
||||
? uint8Array.slice(offset + 8, offset + 8 + size)
|
||||
: uint8Array.subarray(offset + 8, offset + 8 + size));
|
||||
? uint8Array.slice(offset + numBytes, offset + numBytes + size)
|
||||
: uint8Array.subarray(offset + numBytes, offset + numBytes + size));
|
||||
}
|
||||
else {
|
||||
throw new Error("Incomplete message");
|
||||
throw new Error("Incomplete message.");
|
||||
}
|
||||
|
||||
offset = offset + 8 + size;
|
||||
offset = offset + numBytes + size;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ export class HttpConnection implements IConnection {
|
|||
return url;
|
||||
}
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
if (typeof window === 'undefined' || !window || !window.document) {
|
||||
throw new Error(`Cannot resolve '${url}'.`);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Binary;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
|
||||
|
|
@ -10,18 +9,34 @@ namespace Microsoft.AspNetCore.SignalR.Internal.Formatters
|
|||
{
|
||||
public static class BinaryMessageFormatter
|
||||
{
|
||||
public static void WriteMessage(ReadOnlySpan<byte> payload, Stream output)
|
||||
public unsafe static void WriteMessage(ReadOnlySpan<byte> payload, Stream output)
|
||||
{
|
||||
// TODO: Optimize for size - (e.g. use Varints)
|
||||
var length = sizeof(long);
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(length + payload.Length);
|
||||
// This code writes length prefix of the message as a VarInt. Read the comment in
|
||||
// the BinaryMessageParser.TryParseMessage for details.
|
||||
|
||||
var lenBuffer = stackalloc byte[5];
|
||||
var lenNumBytes = 0;
|
||||
var length = payload.Length;
|
||||
do
|
||||
{
|
||||
ref var current = ref lenBuffer[lenNumBytes];
|
||||
current = (byte)(length & 0x7f);
|
||||
length >>= 7;
|
||||
if (length > 0)
|
||||
{
|
||||
current |= 0x80;
|
||||
}
|
||||
lenNumBytes++;
|
||||
}
|
||||
while (length > 0);
|
||||
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(lenNumBytes + payload.Length);
|
||||
var bufferSpan = buffer.AsSpan();
|
||||
|
||||
BufferWriter.WriteBigEndian<long>(bufferSpan, payload.Length);
|
||||
bufferSpan = bufferSpan.Slice(length);
|
||||
new Span<byte>(lenBuffer, lenNumBytes).CopyTo(bufferSpan);
|
||||
bufferSpan = bufferSpan.Slice(lenNumBytes);
|
||||
payload.CopyTo(bufferSpan);
|
||||
output.Write(buffer, 0, payload.Length + length);
|
||||
|
||||
output.Write(buffer, 0, lenNumBytes + payload.Length);
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,41 +2,70 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Binary;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Internal.Formatters
|
||||
{
|
||||
public static class BinaryMessageParser
|
||||
{
|
||||
private static int[] _numBitsToShift = new[] { 0, 7, 14, 21, 28 };
|
||||
private const int MaxLengthPrefixSize = 5;
|
||||
|
||||
public static bool TryParseMessage(ref ReadOnlyBuffer<byte> buffer, out ReadOnlyBuffer<byte> payload)
|
||||
{
|
||||
long length = 0;
|
||||
payload = default(ReadOnlyBuffer<byte>);
|
||||
payload = default;
|
||||
|
||||
if (buffer.Length < sizeof(long))
|
||||
if (buffer.IsEmpty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the length
|
||||
length = buffer.Span.Slice(0, sizeof(long)).ReadBigEndian<long>();
|
||||
// The payload starts with a length prefix encoded as a VarInt. VarInts use the most significant bit
|
||||
// as a marker whether the byte is the last byte of the VarInt or if it spans to the next byte. Bytes
|
||||
// appear in the reverse order - i.e. the first byte contains the least significant bits of the value
|
||||
// Examples:
|
||||
// VarInt: 0x35 - %00110101 - the most significant bit is 0 so the value is %x0110101 i.e. 0x35 (53)
|
||||
// VarInt: 0x80 0x25 - %10000000 %00101001 - the most significant bit of the first byte is 1 so the
|
||||
// remaining bits (%x0000000) are the lowest bits of the value. The most significant bit of the second
|
||||
// byte is 0 meaning this is last byte of the VarInt. The actual value bits (%x0101001) need to be
|
||||
// prepended to the bits we already read so the values is %01010010000000 i.e. 0x1480 (5248)
|
||||
// We support paylads up to 2GB so the biggest number we support is 7fffffff which when encoded as
|
||||
// VarInt is 0xFF 0xFF 0xFF 0xFF 0x7F - hence the maximum length prefix is 5 bytes.
|
||||
|
||||
if (length > Int32.MaxValue)
|
||||
var length = 0U;
|
||||
var numBytes = 0;
|
||||
|
||||
var lengthPrefixBuffer = buffer.Span.Slice(0, Math.Min(MaxLengthPrefixSize, buffer.Length));
|
||||
byte byteRead;
|
||||
do
|
||||
{
|
||||
throw new FormatException("Messages over 2GB in size are not supported");
|
||||
byteRead = lengthPrefixBuffer[numBytes];
|
||||
length = length | (((uint)(byteRead & 0x7f)) << _numBitsToShift[numBytes]);
|
||||
numBytes++;
|
||||
}
|
||||
while (numBytes < lengthPrefixBuffer.Length && ((byteRead & 0x80) != 0));
|
||||
|
||||
// size bytes are missing
|
||||
if ((byteRead & 0x80) != 0 && (numBytes < MaxLengthPrefixSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((byteRead & 0x80) != 0 || (numBytes == MaxLengthPrefixSize && byteRead > 7))
|
||||
{
|
||||
throw new FormatException("Messages over 2GB in size are not supported.");
|
||||
}
|
||||
|
||||
// We don't have enough data
|
||||
if (buffer.Length < (int)length + sizeof(long))
|
||||
if (buffer.Length < length + numBytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the payload
|
||||
payload = buffer.Slice(sizeof(long), (int)length);
|
||||
payload = buffer.Slice(numBytes, (int)length);
|
||||
|
||||
// Skip the payload
|
||||
buffer = buffer.Slice((int)length + sizeof(long));
|
||||
buffer = buffer.Slice(numBytes + (int)length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<Description>Common serialiation primitives for SignalR Clients Servers</Description>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Microsoft.AspNetCore.SignalR</RootNamespace>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
|
@ -16,9 +18,9 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
|
|||
{
|
||||
var expectedEncoding = new byte[]
|
||||
{
|
||||
/* length: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* length: */ 0x00,
|
||||
/* body: <empty> */
|
||||
/* length: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
|
||||
/* length: */ 0x0E,
|
||||
/* body: */ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x0D, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21,
|
||||
};
|
||||
|
||||
|
|
@ -38,10 +40,34 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, new byte[0])]
|
||||
[InlineData(0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xAB, 0xCD, 0xEF, 0x12 }, new byte[] { 0xAB, 0xCD, 0xEF, 0x12 })]
|
||||
[InlineData(4, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, new byte[0])]
|
||||
[InlineData(4, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xAB, 0xCD, 0xEF, 0x12 }, new byte[] { 0xAB, 0xCD, 0xEF, 0x12 })]
|
||||
[InlineData(0, new byte[] { 0x00 }, new byte[0])]
|
||||
[InlineData(0, new byte[] { 0x04, 0xAB, 0xCD, 0xEF, 0x12 }, new byte[] { 0xAB, 0xCD, 0xEF, 0x12 })]
|
||||
[InlineData(0, new byte[]
|
||||
{
|
||||
0x80, 0x01, // Size - 128
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
||||
})]
|
||||
|
||||
[InlineData(4, new byte[] { 0x00 }, new byte[0])]
|
||||
[InlineData(4, new byte[] { 0x04, 0xAB, 0xCD, 0xEF, 0x12 }, new byte[] { 0xAB, 0xCD, 0xEF, 0x12 })]
|
||||
public void WriteBinaryMessage(int offset, byte[] encoded, byte[] payload)
|
||||
{
|
||||
var output = new MemoryStream();
|
||||
|
|
@ -57,10 +83,10 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "")]
|
||||
[InlineData(0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x41, 0x42, 0x43 }, "ABC")]
|
||||
[InlineData(0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x41, 0x0A, 0x52, 0x0D, 0x43, 0x0D, 0x0A, 0x3B, 0x44, 0x45, 0x46 }, "A\nR\rC\r\n;DEF")]
|
||||
[InlineData(4, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "")]
|
||||
[InlineData(0, new byte[] { 0x00 }, "")]
|
||||
[InlineData(0, new byte[] { 0x03, 0x41, 0x42, 0x43 }, "ABC")]
|
||||
[InlineData(0, new byte[] { 0x0B, 0x41, 0x0A, 0x52, 0x0D, 0x43, 0x0D, 0x0A, 0x3B, 0x44, 0x45, 0x46 }, "A\nR\rC\r\n;DEF")]
|
||||
[InlineData(4, new byte[] { 0x00 }, "")]
|
||||
public void WriteTextMessage(int offset, byte[] encoded, string payload)
|
||||
{
|
||||
var message = Encoding.UTF8.GetBytes(payload);
|
||||
|
|
@ -75,5 +101,36 @@ namespace Microsoft.AspNetCore.Sockets.Tests.Internal.Formatters
|
|||
|
||||
Assert.Equal(encoded, output.ToArray().Skip(offset));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RandomPayloads))]
|
||||
public void RoundTrippingTest(byte[] payload)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
BinaryMessageFormatter.WriteMessage(payload, ms);
|
||||
var buffer = new ReadOnlyBuffer<byte>(ms.ToArray());
|
||||
Assert.True(BinaryMessageParser.TryParseMessage(ref buffer, out var roundtripped));
|
||||
Assert.Equal(payload, roundtripped.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> RandomPayloads()
|
||||
{
|
||||
// boundaries
|
||||
yield return new[] { CreatePayload(0) };
|
||||
yield return new[] { CreatePayload(1) };
|
||||
yield return new[] { CreatePayload(0x7f) };
|
||||
yield return new[] { CreatePayload(0x80) };
|
||||
yield return new[] { CreatePayload(0x3fff) };
|
||||
yield return new[] { CreatePayload(0x4000) };
|
||||
|
||||
// random
|
||||
yield return new[] { CreatePayload(0xc0de) };
|
||||
}
|
||||
|
||||
|
||||
private static byte[] CreatePayload(int size) =>
|
||||
Enumerable.Range(0, size).Select(n => (byte)(n & 0xff)).ToArray();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters
|
|||
public class BinaryMessageParserTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "")]
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x41, 0x42, 0x43 }, "ABC")]
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x41, 0x0A, 0x52, 0x0D, 0x43, 0x0D, 0x0A, 0x3B, 0x44, 0x45, 0x46 }, "A\nR\rC\r\n;DEF")]
|
||||
[InlineData(new byte[] { 0x00 }, "")]
|
||||
[InlineData(new byte[] { 0x03, 0x41, 0x42, 0x43 }, "ABC")]
|
||||
[InlineData(new byte[] { 0x0B, 0x41, 0x0A, 0x52, 0x0D, 0x43, 0x0D, 0x0A, 0x3B, 0x44, 0x45, 0x46 }, "A\nR\rC\r\n;DEF")]
|
||||
public void ReadMessage(byte[] encoded, string payload)
|
||||
{
|
||||
ReadOnlyBuffer<byte> span = encoded;
|
||||
|
|
@ -25,8 +25,31 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, new byte[0])]
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xAB, 0xCD, 0xEF, 0x12 }, new byte[] { 0xAB, 0xCD, 0xEF, 0x12 })]
|
||||
[InlineData(new byte[] { 0x00 }, new byte[0])]
|
||||
[InlineData(new byte[] { 0x04, 0xAB, 0xCD, 0xEF, 0x12 }, new byte[] { 0xAB, 0xCD, 0xEF, 0x12 })]
|
||||
[InlineData(new byte[]
|
||||
{
|
||||
0x80, 0x01, // Size - 128
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
||||
},
|
||||
new byte[]
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
||||
})]
|
||||
public void ReadBinaryMessage(byte[] encoded, byte[] payload)
|
||||
{
|
||||
ReadOnlyBuffer<byte> span = encoded;
|
||||
|
|
@ -35,14 +58,36 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters
|
|||
Assert.Equal(payload, message.ToArray());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF })]
|
||||
[InlineData(new byte[] { 0x80, 0x80, 0x80, 0x80, 0x08 })] // 2GB + 1
|
||||
[InlineData(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF })]
|
||||
public void BinaryMessageParserThrowsForMessagesOver2GB(byte[] payload)
|
||||
{
|
||||
var buffer = new ReadOnlyBuffer<byte>(payload);
|
||||
var ex = Assert.Throws<FormatException>(() => BinaryMessageParser.TryParseMessage(ref buffer, out var message));
|
||||
Assert.Equal("Messages over 2GB in size are not supported.", ex.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[] { })]
|
||||
[InlineData(new byte[] { 0x04, 0xAB, 0xCD, 0xEF })]
|
||||
[InlineData(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x07 })] // 2GB
|
||||
[InlineData(new byte[] { 0x80 })] // size is cut
|
||||
public void BinaryMessageParserReturnsFalseForPartialPayloads(byte[] payload)
|
||||
{
|
||||
var buffer = new ReadOnlyBuffer<byte>(payload);
|
||||
Assert.False(BinaryMessageParser.TryParseMessage(ref buffer, out var message));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadMultipleMessages()
|
||||
{
|
||||
var encoded = new byte[]
|
||||
{
|
||||
/* length: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
/* length: */ 0x00,
|
||||
/* body: <empty> */
|
||||
/* length: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
|
||||
/* length: */ 0x0E,
|
||||
/* body: */ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x0D, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21,
|
||||
};
|
||||
ReadOnlyBuffer<byte> buffer = encoded;
|
||||
|
|
@ -62,7 +107,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Formatters
|
|||
|
||||
[Theory]
|
||||
[InlineData(new byte[0])] // Empty
|
||||
[InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00 })] // Not enough data for payload
|
||||
[InlineData(new byte[] { 0x09, 0x00, 0x00 })] // Not enough data for payload
|
||||
public void ReadIncompleteMessages(byte[] encoded)
|
||||
{
|
||||
ReadOnlyBuffer<byte> buffer = encoded;
|
||||
|
|
|
|||
|
|
@ -117,12 +117,12 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
public void ParserThrowsForInvalidMessages(byte[] payload, string expectedExceptionMessage)
|
||||
{
|
||||
var payloadSize = payload.Length;
|
||||
Debug.Assert(payloadSize <= 0xff, "This test does not support payloads larger than 255");
|
||||
Debug.Assert(payloadSize <= 0x7f, "This test does not support payloads larger than 127 bytes");
|
||||
|
||||
// prefix payload with the size
|
||||
var buffer = new byte[8 + payloadSize];
|
||||
buffer[7] = (byte)(payloadSize & 0xff);
|
||||
Array.Copy(payload, 0, buffer, 8, payloadSize);
|
||||
var buffer = new byte[1 + payloadSize];
|
||||
buffer[0] = (byte)(payloadSize & 0x7f);
|
||||
Array.Copy(payload, 0, buffer, 1, payloadSize);
|
||||
|
||||
var binder = new TestBinder(new[] { typeof(string) }, typeof(string));
|
||||
var exception = Assert.Throws<FormatException>(() => _hubProtocol.TryParseMessages(buffer, binder, out var messages));
|
||||
|
|
@ -131,13 +131,13 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new object[] { new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01 }, 0 })]
|
||||
[InlineData(new object[] { new byte[] { 0x05, 0x01 }, 0 })]
|
||||
[InlineData(new object[] {
|
||||
new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x93, 0x03, 0xa1, 0x78, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x93, 0x03, 0xa1, 0x78, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x93, 0x03, 0xa1
|
||||
0x05, 0x93, 0x03, 0xa1, 0x78, 0x02,
|
||||
0x05, 0x93, 0x03, 0xa1, 0x78, 0x02,
|
||||
0x05, 0x93, 0x03, 0xa1
|
||||
}, 2 })]
|
||||
public void ParserDoesNotConsumePartialData(byte[] payload, int expectedMessagesCount)
|
||||
{
|
||||
|
|
@ -154,7 +154,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
new InvocationMessage("0", false, "A", 1, new CustomObject()),
|
||||
new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x95, 0x01, 0xa1, 0x30, 0xc2, 0xa1, 0x41,
|
||||
0x5b, 0x95, 0x01, 0xa1, 0x30, 0xc2, 0xa1, 0x41,
|
||||
0x92, // argument array
|
||||
0x01, // 1 - first argument
|
||||
// 0x85 - a map of 5 items (properties)
|
||||
|
|
@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
CompletionMessage.WithResult("0", new CustomObject()),
|
||||
new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x94, 0x03, 0xa1, 0x30, 0x03,
|
||||
0x57, 0x94, 0x03, 0xa1, 0x30, 0x03,
|
||||
// 0x85 - a map of 5 items (properties)
|
||||
0x85, 0xac, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x50, 0x72, 0x6f, 0x70, 0xd3, 0x08,
|
||||
0xd4, 0x80, 0x6d, 0xb2, 0x76, 0xc0, 0x00, 0xaa, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x50, 0x72,
|
||||
|
|
@ -186,7 +186,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
new StreamItemMessage("0", new CustomObject()),
|
||||
new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x93, 0x02, 0xa1, 0x30,
|
||||
0x56, 0x93, 0x02, 0xa1, 0x30,
|
||||
// 0x85 - a map of 5 items (properties)
|
||||
0x85, 0xac, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x50, 0x72, 0x6f, 0x70, 0xd3, 0x08,
|
||||
0xd4, 0x80, 0x6d, 0xb2, 0x76, 0xc0, 0x00, 0xaa, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x50, 0x72,
|
||||
|
|
@ -212,10 +212,7 @@ namespace Microsoft.AspNetCore.SignalR.Common.Tests.Internal.Protocol
|
|||
[Fact]
|
||||
public void CanWriteObjectsWithoutDefaultCtors()
|
||||
{
|
||||
var expectedPayload = new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x94, 0x03, 0xa1, 0x30, 0x03, 0x91, 0x2a
|
||||
};
|
||||
var expectedPayload = new byte[] { 0x07, 0x94, 0x03, 0xa1, 0x30, 0x03, 0x91, 0x2a };
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue