Exemplo n.º 1
0
        private static StreamCompletionMessage CreateStreamCompletionMessage(Unpacker unpacker, long arraySize, IInvocationBinder binder)
        {
            Debug.Assert(arraySize == 2 || arraySize == 3, "Unexpected item count");

            var invocationId = ReadInvocationId(unpacker);
            // Error is optional so StreamCompletion without error has 2 items, StreamCompletion with error has 3 items
            var error = arraySize == 3 ? ReadString(unpacker, "error") : null;

            return(new StreamCompletionMessage(invocationId, error));
        }
Exemplo n.º 2
0
        private HubMessage CreateStreamInvocationMessage(ref MessagePackReader reader, IInvocationBinder binder, int itemCount)
        {
            var headers      = ReadHeaders(ref reader);
            var invocationId = ReadInvocationId(ref reader);
            var target       = ReadString(ref reader, "target");

            object[] arguments;
            try
            {
                var parameterTypes = binder.GetParameterTypes(target);
                arguments = BindArguments(ref reader, parameterTypes);
            }
            catch (Exception ex)
            {
                return(new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex)));
            }

            string[]? streams = null;
            // Previous clients will send 5 items, so we check if they sent a stream array or not
            if (itemCount > 5)
            {
                streams = ReadStreamIds(ref reader);
            }

            return(ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, arguments, streams)));
        }
        private static StreamInvocationMessage CreateStreamInvocationMessage(Unpacker unpacker, IInvocationBinder binder)
        {
            var headers        = ReadHeaders(unpacker);
            var invocationId   = ReadInvocationId(unpacker);
            var target         = ReadString(unpacker, "target");
            var parameterTypes = binder.GetParameterTypes(target);

            try
            {
                var arguments = BindArguments(unpacker, parameterTypes);
                return(ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, argumentBindingException: null, arguments: arguments)));
            }
            catch (Exception ex)
            {
                return(ApplyHeaders(headers, new StreamInvocationMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex))));
            }
        }
Exemplo n.º 4
0
 public bool TryParseMessage(ref ReadOnlySequence <byte> input, IInvocationBinder binder, out HubMessage message)
 {
     throw new NotSupportedException();
 }
        private static HubMessage CreateStreamItemMessage(ref MessagePackReader reader, IInvocationBinder binder, MessagePackSerializerOptions msgPackSerializerOptions)
        {
            var    headers      = ReadHeaders(ref reader);
            var    invocationId = ReadInvocationId(ref reader);
            object value;

            try
            {
                var itemType = binder.GetStreamItemType(invocationId);
                value = DeserializeObject(ref reader, itemType, "item", msgPackSerializerOptions);
            }
            catch (Exception ex)
            {
                return(new StreamBindingFailureMessage(invocationId, ExceptionDispatchInfo.Capture(ex)));
            }

            return(ApplyHeaders(headers, new StreamItemMessage(invocationId, value)));
        }
Exemplo n.º 6
0
        private static HubMessage BindCompletionMessage(string invocationId, string?error, object?result, bool hasResult, IInvocationBinder binder)
        {
            if (string.IsNullOrEmpty(invocationId))
            {
                throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'.");
            }

            if (error != null && hasResult)
            {
                throw new InvalidDataException("The 'error' and 'result' properties are mutually exclusive.");
            }

            if (hasResult)
            {
                return(new CompletionMessage(invocationId, error, result, hasResult: true));
            }

            return(new CompletionMessage(invocationId, error, result: null, hasResult: false));
        }
Exemplo n.º 7
0
        private static HubMessage BindInvocationMessage(string?invocationId, string target, object?[]?arguments, bool hasArguments, string[]?streamIds, IInvocationBinder binder)
        {
            if (string.IsNullOrEmpty(target))
            {
                throw new InvalidDataException($"Missing required property '{TargetPropertyName}'.");
            }

            if (!hasArguments)
            {
                throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'.");
            }

            Debug.Assert(arguments != null);

            return(new InvocationMessage(invocationId, target, arguments, streamIds));
        }
Exemplo n.º 8
0
        private static StreamInvocationMessage CreateStreamInvocationMessage(Unpacker unpacker, IInvocationBinder binder)
        {
            var invocationId   = ReadInvocationId(unpacker);
            var metadata       = ReadMetadata(unpacker);
            var target         = ReadString(unpacker, "target");
            var parameterTypes = binder.GetParameterTypes(target);

            try
            {
                var arguments = BindArguments(unpacker, parameterTypes);
                return(new StreamInvocationMessage(invocationId, metadata, target, arguments: arguments));
            }
            catch (Exception ex)
            {
                return(new StreamInvocationMessage(invocationId, metadata, target, ExceptionDispatchInfo.Capture(ex)));
            }
        }
Exemplo n.º 9
0
 public HubMessageReader(IHubProtocol hubProtocol, IInvocationBinder invocationBinder)
 {
     _hubProtocol      = hubProtocol;
     _invocationBinder = invocationBinder;
 }
Exemplo n.º 10
0
        private HubMessage BindParamStreamMessage(string streamId, object item, bool hasItem, IInvocationBinder binder)
        {
            if (string.IsNullOrEmpty(streamId))
            {
                throw new InvalidDataException($"Missing required property '{StreamIdPropertyName}");
            }
            if (!hasItem)
            {
                throw new InvalidDataException($"Missing required property '{ItemPropertyName}");
            }

            return(new StreamDataMessage(streamId, item));
        }
Exemplo n.º 11
0
 private static HubMessage ParseBroadcastDataMessageJson(BroadcastDataMessage bdm, IInvocationBinder binder)
 {
     foreach (var payload in bdm.Payloads)
     {
         if (payload.Key == "json")
         {
             var sequence = new ReadOnlySequence <byte>(payload.Value);
             if (_signalRPro.TryParseMessage(ref sequence, binder, out var signalRRRmessage))
             {
                 return(signalRRRmessage);
             }
         }
     }
     return(null);
 }
Exemplo n.º 12
0
        private static StreamItemMessage CreateStreamItemMessage(ref MessagePackReader reader, IInvocationBinder binder)
        {
            var headers      = ReadHeaders(ref reader);
            var invocationId = ReadString(ref reader, "invocationId");

            var itemType = binder.GetStreamItemType(invocationId);
            var value    = DeserializeObject(ref reader, itemType, "item");

            return(ApplyHeaders(headers, new StreamItemMessage(invocationId, value)));
        }
Exemplo n.º 13
0
 private static HubMessage ParseBroadcastDataMessageJson(BroadcastDataMessage bdm, IInvocationBinder binder)
 {
     foreach (var payload in bdm.Payloads)
     {
         if (payload.Key == "json")
         {
             var sequence = new ReadOnlySequence <byte>(payload.Value);
             if (_signalRPro.TryParseMessage(ref sequence, binder, out var signalRRRmessage))
             {
                 if (signalRRRmessage is InvocationMessage inv)
                 {
                     Console.WriteLine($" -- {bdm}: callback#  {inv.Target} {inv.Arguments[0]}");
                 }
                 else
                 {
                     Console.WriteLine($"oh something else {signalRRRmessage}");
                 }
                 return(signalRRRmessage);
             }
             else
             {
                 Console.WriteLine("failed..");
             }
         }
Exemplo n.º 14
0
        public bool ReadMessages(byte[] input, IInvocationBinder binder, out IList <HubMessage> messages)
        {
            var buffer = _dataEncoder.Decode(input);

            return(_hubProtocol.TryParseMessages(buffer, binder, out messages));
        }
        private HubMessage BindStreamInvocationMessage(string invocationId, string target, object[] arguments, bool hasArguments, string[] streamIds, IInvocationBinder binder)
        {
            if (string.IsNullOrEmpty(invocationId))
            {
                throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'.");
            }

            if (!hasArguments)
            {
                throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'.");
            }

            if (string.IsNullOrEmpty(target))
            {
                throw new InvalidDataException($"Missing required property '{TargetPropertyName}'.");
            }

            return(new StreamInvocationMessage(invocationId, target, arguments, streamIds));
        }
Exemplo n.º 16
0
        public TestClient(bool synchronousCallbacks = false, IHubProtocol protocol = null, IInvocationBinder invocationBinder = null, bool addClaimId = false)
        {
            var options = new PipeOptions(readerScheduler: synchronousCallbacks ? PipeScheduler.Inline : null);
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            Connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Transport, pair.Application);

            var claimValue = Interlocked.Increment(ref _id).ToString();
            var claims     = new List <Claim> {
                new Claim(ClaimTypes.Name, claimValue)
            };

            if (addClaimId)
            {
                claims.Add(new Claim(ClaimTypes.NameIdentifier, claimValue));
            }

            Connection.User = new ClaimsPrincipal(new ClaimsIdentity(claims));
            Connection.Metadata["ConnectedTask"] = new TaskCompletionSource <bool>();

            _protocol         = protocol ?? new JsonHubProtocol();
            _invocationBinder = invocationBinder ?? new DefaultInvocationBinder();

            _cts = new CancellationTokenSource();

            using (var memoryStream = new MemoryStream())
            {
                NegotiationProtocol.WriteMessage(new NegotiationMessage(_protocol.Name), memoryStream);
                Connection.Application.Output.WriteAsync(memoryStream.ToArray());
            }
        }
Exemplo n.º 17
0
        private HubMessage?ParseMessage(Utf8BufferTextReader textReader, IInvocationBinder binder)
        {
            try
            {
                // We parse using the JsonTextReader directly but this has a problem. Some of our properties are dependent on other properties
                // and since reading the json might be unordered, we need to store the parsed content as JToken to re-parse when true types are known.
                // if we're lucky and the state we need to directly parse is available, then we'll use it.

                int?       type         = null;
                string?    invocationId = null;
                string?    target       = null;
                string?    error        = null;
                var        hasItem      = false;
                object?    item         = null;
                JToken?    itemToken    = null;
                var        hasResult    = false;
                object?    result       = null;
                JToken?    resultToken  = null;
                var        hasArguments = false;
                object?[]? arguments    = null;
                string[]? streamIds = null;
                JArray?argumentsToken = null;
                ExceptionDispatchInfo?      argumentBindingException = null;
                Dictionary <string, string>?headers = null;
                var completed      = false;
                var allowReconnect = false;

                using (var reader = JsonUtils.CreateJsonTextReader(textReader))
                {
                    reader.DateParseHandling = DateParseHandling.None;

                    JsonUtils.CheckRead(reader);

                    // We're always parsing a JSON object
                    JsonUtils.EnsureObjectStart(reader);

                    do
                    {
                        switch (reader.TokenType)
                        {
                        case JsonToken.PropertyName:
                            var memberName = reader.Value?.ToString();

                            switch (memberName)
                            {
                            case TypePropertyName:
                                var messageType = JsonUtils.ReadAsInt32(reader, TypePropertyName);

                                if (messageType == null)
                                {
                                    throw new InvalidDataException($"Missing required property '{TypePropertyName}'.");
                                }

                                type = messageType.Value;
                                break;

                            case InvocationIdPropertyName:
                                invocationId = JsonUtils.ReadAsString(reader, InvocationIdPropertyName);
                                break;

                            case StreamIdsPropertyName:
                                JsonUtils.CheckRead(reader);

                                if (reader.TokenType != JsonToken.StartArray)
                                {
                                    throw new InvalidDataException($"Expected '{StreamIdsPropertyName}' to be of type {JTokenType.Array}.");
                                }

                                var newStreamIds = new List <string>();
                                reader.Read();
                                while (reader.TokenType != JsonToken.EndArray)
                                {
                                    newStreamIds.Add(reader.Value?.ToString() ?? throw new InvalidDataException($"Null value for '{StreamIdsPropertyName}' is not valid."));
                                    reader.Read();
                                }

                                streamIds = newStreamIds.ToArray();
                                break;

                            case TargetPropertyName:
                                target = JsonUtils.ReadAsString(reader, TargetPropertyName);
                                break;

                            case ErrorPropertyName:
                                error = JsonUtils.ReadAsString(reader, ErrorPropertyName);
                                break;

                            case AllowReconnectPropertyName:
                                allowReconnect = JsonUtils.ReadAsBoolean(reader, AllowReconnectPropertyName);
                                break;

                            case ResultPropertyName:
                                hasResult = true;

                                if (string.IsNullOrEmpty(invocationId))
                                {
                                    JsonUtils.CheckRead(reader);

                                    // If we don't have an invocation id then we need to store it as a JToken so we can parse it later
                                    resultToken = JToken.Load(reader);
                                }
                                else
                                {
                                    // If we have an invocation id already we can parse the end result
                                    var returnType = binder.GetReturnType(invocationId);

                                    if (!JsonUtils.ReadForType(reader, returnType))
                                    {
                                        throw new JsonReaderException("Unexpected end when reading JSON");
                                    }

                                    result = PayloadSerializer.Deserialize(reader, returnType);
                                }
                                break;

                            case ItemPropertyName:
                                JsonUtils.CheckRead(reader);

                                hasItem = true;


                                string?id = null;
                                if (!string.IsNullOrEmpty(invocationId))
                                {
                                    id = invocationId;
                                }
                                else
                                {
                                    // If we don't have an id yet then we need to store it as a JToken to parse later
                                    itemToken = JToken.Load(reader);
                                    break;
                                }

                                try
                                {
                                    var itemType = binder.GetStreamItemType(id);
                                    item = PayloadSerializer.Deserialize(reader, itemType);
                                }
                                catch (Exception ex)
                                {
                                    return(new StreamBindingFailureMessage(id, ExceptionDispatchInfo.Capture(ex)));
                                }
                                break;

                            case ArgumentsPropertyName:
                                JsonUtils.CheckRead(reader);

                                int initialDepth = reader.Depth;
                                if (reader.TokenType != JsonToken.StartArray)
                                {
                                    throw new InvalidDataException($"Expected '{ArgumentsPropertyName}' to be of type {JTokenType.Array}.");
                                }

                                hasArguments = true;

                                if (string.IsNullOrEmpty(target))
                                {
                                    // We don't know the method name yet so just parse an array of generic JArray
                                    argumentsToken = JArray.Load(reader);
                                }
                                else
                                {
                                    try
                                    {
                                        var paramTypes = binder.GetParameterTypes(target);
                                        arguments = BindArguments(reader, paramTypes);
                                    }
                                    catch (Exception ex)
                                    {
                                        argumentBindingException = ExceptionDispatchInfo.Capture(ex);

                                        // Could be at any point in argument array JSON when an error is thrown
                                        // Read until the end of the argument JSON array
                                        while (reader.Depth == initialDepth && reader.TokenType == JsonToken.StartArray ||
                                               reader.Depth > initialDepth)
                                        {
                                            JsonUtils.CheckRead(reader);
                                        }
                                    }
                                }
                                break;

                            case HeadersPropertyName:
                                JsonUtils.CheckRead(reader);
                                headers = ReadHeaders(reader);
                                break;

                            default:
                                // Skip read the property name
                                JsonUtils.CheckRead(reader);
                                // Skip the value for this property
                                reader.Skip();
                                break;
                            }
                            break;

                        case JsonToken.EndObject:
                            completed = true;
                            break;
                        }
                    }while (!completed && JsonUtils.CheckRead(reader));
                }

                HubMessage message;

                switch (type)
                {
                case HubProtocolConstants.InvocationMessageType:
                {
                    if (target is null)
                    {
                        throw new InvalidDataException($"Missing required property '{TargetPropertyName}'.");
                    }

                    if (argumentsToken != null)
                    {
                        // We weren't able to bind the arguments because they came before the 'target', so try to bind now that we've read everything.
                        try
                        {
                            var paramTypes = binder.GetParameterTypes(target);
                            arguments = BindArguments(argumentsToken, paramTypes);
                        }
                        catch (Exception ex)
                        {
                            argumentBindingException = ExceptionDispatchInfo.Capture(ex);
                        }
                    }

                    message = argumentBindingException != null
                                ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException)
                                : BindInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder);
                }
                break;

                case HubProtocolConstants.StreamInvocationMessageType:
                {
                    if (target is null)
                    {
                        throw new InvalidDataException($"Missing required property '{TargetPropertyName}'.");
                    }

                    if (argumentsToken != null)
                    {
                        // We weren't able to bind the arguments because they came before the 'target', so try to bind now that we've read everything.
                        try
                        {
                            var paramTypes = binder.GetParameterTypes(target);
                            arguments = BindArguments(argumentsToken, paramTypes);
                        }
                        catch (Exception ex)
                        {
                            argumentBindingException = ExceptionDispatchInfo.Capture(ex);
                        }
                    }

                    message = argumentBindingException != null
                                ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException)
                                : BindStreamInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder);
                }
                break;

                case HubProtocolConstants.StreamItemMessageType:
                    if (invocationId is null)
                    {
                        throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'.");
                    }

                    if (itemToken != null)
                    {
                        try
                        {
                            var itemType = binder.GetStreamItemType(invocationId);
                            item = itemToken.ToObject(itemType, PayloadSerializer);
                        }
                        catch (Exception ex)
                        {
                            message = new StreamBindingFailureMessage(invocationId, ExceptionDispatchInfo.Capture(ex));
                            break;
                        };
                    }

                    message = BindStreamItemMessage(invocationId, item, hasItem, binder);
                    break;

                case HubProtocolConstants.CompletionMessageType:
                    if (invocationId is null)
                    {
                        throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'.");
                    }

                    if (resultToken != null)
                    {
                        var returnType = binder.GetReturnType(invocationId);
                        result = resultToken.ToObject(returnType, PayloadSerializer);
                    }

                    message = BindCompletionMessage(invocationId, error, result, hasResult, binder);
                    break;

                case HubProtocolConstants.CancelInvocationMessageType:
                    message = BindCancelInvocationMessage(invocationId);
                    break;

                case HubProtocolConstants.PingMessageType:
                    return(PingMessage.Instance);

                case HubProtocolConstants.CloseMessageType:
                    return(BindCloseMessage(error, allowReconnect));

                case null:
                    throw new InvalidDataException($"Missing required property '{TypePropertyName}'.");

                default:
                    // Future protocol changes can add message types, old clients can ignore them
                    return(null);
                }

                return(ApplyHeaders(message, headers));
            }
            catch (JsonReaderException jrex)
            {
                throw new InvalidDataException("Error reading JSON.", jrex);
            }
        }
Exemplo n.º 18
0
        public TestClient(bool synchronousCallbacks = false, IHubProtocol protocol = null, IInvocationBinder invocationBinder = null, bool addClaimId = false)
        {
            var pair = DuplexPipePair.GetConnectionTransport(synchronousCallbacks);

            Connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Transport, pair.Application);

            // Add features SignalR needs for testing
            Connection.Features.Set <ITransferFormatFeature>(this);
            Connection.Features.Set <IConnectionHeartbeatFeature>(this);

            var claimValue = Interlocked.Increment(ref _id).ToString();
            var claims     = new List <Claim> {
                new Claim(ClaimTypes.Name, claimValue)
            };

            if (addClaimId)
            {
                claims.Add(new Claim(ClaimTypes.NameIdentifier, claimValue));
            }

            Connection.User = new ClaimsPrincipal(new ClaimsIdentity(claims));
            Connection.Items["ConnectedTask"] = new TaskCompletionSource <bool>();

            _protocol         = protocol ?? new JsonHubProtocol();
            _invocationBinder = invocationBinder ?? new DefaultInvocationBinder();

            _cts = new CancellationTokenSource();
        }
Exemplo n.º 19
0
        private static HubMessage BindStreamItemMessage(string invocationId, object?item, bool hasItem, IInvocationBinder binder)
        {
            if (string.IsNullOrEmpty(invocationId))
            {
                throw new InvalidDataException($"Missing required property '{InvocationIdPropertyName}'.");
            }

            if (!hasItem)
            {
                throw new InvalidDataException($"Missing required property '{ItemPropertyName}'.");
            }

            return(new StreamItemMessage(invocationId, item));
        }
Exemplo n.º 20
0
 public bool TryParseMessage(ref ReadOnlySequence <byte> input, IInvocationBinder binder, out HubMessage message)
 {
     return(_innerProtocol.TryParseMessage(ref input, binder, out message));
 }
Exemplo n.º 21
0
 /// <inheritdoc />
 public bool TryParseMessage(ref ReadOnlySequence <byte> input, IInvocationBinder binder, out HubMessage message)
 => _worker.TryParseMessage(ref input, binder, out message);
Exemplo n.º 22
0
 public bool TryParseMessages(ReadOnlySpan <byte> input, IInvocationBinder binder, IList <HubMessage> messages)
 {
     return(false);
 }
        private static HubMessage CreateInvocationMessage(ref MessagePackReader reader, IInvocationBinder binder, MessagePackSerializerOptions msgPackSerializerOptions, int itemCount)
        {
            var headers      = ReadHeaders(ref reader);
            var invocationId = ReadInvocationId(ref reader);

            // For MsgPack, we represent an empty invocation ID as an empty string,
            // so we need to normalize that to "null", which is what indicates a non-blocking invocation.
            if (string.IsNullOrEmpty(invocationId))
            {
                invocationId = null;
            }

            var target = ReadString(ref reader, "target");

            object[] arguments = null;
            try
            {
                var parameterTypes = binder.GetParameterTypes(target);
                arguments = BindArguments(ref reader, parameterTypes, msgPackSerializerOptions);
            }
            catch (Exception ex)
            {
                return(new InvocationBindingFailureMessage(invocationId, target, ExceptionDispatchInfo.Capture(ex)));
            }

            string[] streams = null;
            // Previous clients will send 5 items, so we check if they sent a stream array or not
            if (itemCount > 5)
            {
                streams = ReadStreamIds(ref reader);
            }

            return(ApplyHeaders(headers, new InvocationMessage(invocationId, target, arguments, streams)));
        }
Exemplo n.º 24
0
        private HubMessage ParseMessage(ReadOnlySequence <byte> input, IInvocationBinder binder)
        {
            try
            {
                // We parse using the Utf8JsonReader directly but this has a problem. Some of our properties are dependent on other properties
                // and since reading the json might be unordered, we need to store the parsed content as JsonDocument to re-parse when true types are known.
                // if we're lucky and the state we need to directly parse is available, then we'll use it.

                int?                        type                     = null;
                string                      invocationId             = null;
                string                      target                   = null;
                string                      error                    = null;
                var                         hasItem                  = false;
                object                      item                     = null;
                var                         hasResult                = false;
                object                      result                   = null;
                var                         hasArguments             = false;
                object[]                    arguments                = null;
                string[]                    streamIds                = null;
                bool                        hasArgumentsToken        = false;
                Utf8JsonReader              argumentsToken           = default;
                bool                        hasItemsToken            = false;
                Utf8JsonReader              itemsToken               = default;
                bool                        hasResultToken           = false;
                Utf8JsonReader              resultToken              = default;
                ExceptionDispatchInfo       argumentBindingException = null;
                Dictionary <string, string> headers                  = null;
                var                         completed                = false;

                var reader = new Utf8JsonReader(input, isFinalBlock: true, state: default);

                reader.CheckRead();

                // We're always parsing a JSON object
                reader.EnsureObjectStart();

                do
                {
                    switch (reader.TokenType)
                    {
                    case JsonTokenType.PropertyName:
                        if (reader.ValueTextEquals(TypePropertyNameBytes.EncodedUtf8Bytes))
                        {
                            type = reader.ReadAsInt32(TypePropertyName);

                            if (type == null)
                            {
                                throw new InvalidDataException($"Expected '{TypePropertyName}' to be of type {JsonTokenType.Number}.");
                            }
                        }
                        else if (reader.ValueTextEquals(InvocationIdPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            invocationId = reader.ReadAsString(InvocationIdPropertyName);
                        }
                        else if (reader.ValueTextEquals(StreamIdsPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            reader.CheckRead();

                            if (reader.TokenType != JsonTokenType.StartArray)
                            {
                                throw new InvalidDataException(
                                          $"Expected '{StreamIdsPropertyName}' to be of type {SystemTextJsonExtensions.GetTokenString(JsonTokenType.StartArray)}.");
                            }

                            var newStreamIds = new List <string>();
                            reader.Read();
                            while (reader.TokenType != JsonTokenType.EndArray)
                            {
                                newStreamIds.Add(reader.GetString());
                                reader.Read();
                            }

                            streamIds = newStreamIds.ToArray();
                        }
                        else if (reader.ValueTextEquals(TargetPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            target = reader.ReadAsString(TargetPropertyName);
                        }
                        else if (reader.ValueTextEquals(ErrorPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            error = reader.ReadAsString(ErrorPropertyName);
                        }
                        else if (reader.ValueTextEquals(ResultPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            hasResult = true;

                            reader.CheckRead();

                            if (string.IsNullOrEmpty(invocationId))
                            {
                                // If we don't have an invocation id then we need to value copy the reader so we can parse it later
                                hasResultToken = true;
                                resultToken    = reader;
                                reader.Skip();
                            }
                            else
                            {
                                // If we have an invocation id already we can parse the end result
                                var returnType = binder.GetReturnType(invocationId);
                                result = BindType(ref reader, returnType);
                            }
                        }
                        else if (reader.ValueTextEquals(ItemPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            reader.CheckRead();

                            hasItem = true;

                            string id = null;
                            if (!string.IsNullOrEmpty(invocationId))
                            {
                                id = invocationId;
                            }
                            else
                            {
                                // If we don't have an id yet then we need to value copy the reader so we can parse it later
                                hasItemsToken = true;
                                itemsToken    = reader;
                                reader.Skip();
                                continue;
                            }

                            try
                            {
                                var itemType = binder.GetStreamItemType(id);
                                item = BindType(ref reader, itemType);
                            }
                            catch (Exception ex)
                            {
                                return(new StreamBindingFailureMessage(id, ExceptionDispatchInfo.Capture(ex)));
                            }
                        }
                        else if (reader.ValueTextEquals(ArgumentsPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            reader.CheckRead();

                            int initialDepth = reader.CurrentDepth;
                            if (reader.TokenType != JsonTokenType.StartArray)
                            {
                                throw new InvalidDataException($"Expected '{ArgumentsPropertyName}' to be of type {SystemTextJsonExtensions.GetTokenString(JsonTokenType.StartArray)}.");
                            }

                            hasArguments = true;

                            if (string.IsNullOrEmpty(target))
                            {
                                // We don't know the method name yet so just value copy the reader so we can parse it later
                                hasArgumentsToken = true;
                                argumentsToken    = reader;
                                reader.Skip();
                            }
                            else
                            {
                                try
                                {
                                    var paramTypes = binder.GetParameterTypes(target);
                                    arguments = BindTypes(ref reader, paramTypes);
                                }
                                catch (Exception ex)
                                {
                                    argumentBindingException = ExceptionDispatchInfo.Capture(ex);

                                    // Could be at any point in argument array JSON when an error is thrown
                                    // Read until the end of the argument JSON array
                                    while (reader.CurrentDepth == initialDepth && reader.TokenType == JsonTokenType.StartArray ||
                                           reader.CurrentDepth > initialDepth)
                                    {
                                        reader.CheckRead();
                                    }
                                }
                            }
                        }
                        else if (reader.ValueTextEquals(HeadersPropertyNameBytes.EncodedUtf8Bytes))
                        {
                            reader.CheckRead();
                            headers = ReadHeaders(ref reader);
                        }
                        else
                        {
                            reader.CheckRead();
                            reader.Skip();
                        }
                        break;

                    case JsonTokenType.EndObject:
                        completed = true;
                        break;
                    }
                }while (!completed && reader.CheckRead());

                HubMessage message;

                switch (type)
                {
                case HubProtocolConstants.InvocationMessageType:
                {
                    if (hasArgumentsToken)
                    {
                        // We weren't able to bind the arguments because they came before the 'target', so try to bind now that we've read everything.
                        try
                        {
                            var paramTypes = binder.GetParameterTypes(target);
                            arguments = BindTypes(ref argumentsToken, paramTypes);
                        }
                        catch (Exception ex)
                        {
                            argumentBindingException = ExceptionDispatchInfo.Capture(ex);
                        }
                    }

                    message = argumentBindingException != null
                                ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException)
                                : BindInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder);
                }
                break;

                case HubProtocolConstants.StreamInvocationMessageType:
                {
                    if (hasArgumentsToken)
                    {
                        // We weren't able to bind the arguments because they came before the 'target', so try to bind now that we've read everything.
                        try
                        {
                            var paramTypes = binder.GetParameterTypes(target);
                            arguments = BindTypes(ref argumentsToken, paramTypes);
                        }
                        catch (Exception ex)
                        {
                            argumentBindingException = ExceptionDispatchInfo.Capture(ex);
                        }
                    }

                    message = argumentBindingException != null
                                ? new InvocationBindingFailureMessage(invocationId, target, argumentBindingException)
                                : BindStreamInvocationMessage(invocationId, target, arguments, hasArguments, streamIds, binder);
                }
                break;

                case HubProtocolConstants.StreamItemMessageType:
                    if (hasItemsToken)
                    {
                        try
                        {
                            var returnType = binder.GetStreamItemType(invocationId);
                            item = BindType(ref itemsToken, returnType);
                        }
                        catch (JsonException ex)
                        {
                            message = new StreamBindingFailureMessage(invocationId, ExceptionDispatchInfo.Capture(ex));
                            break;
                        }
                    }

                    message = BindStreamItemMessage(invocationId, item, hasItem, binder);
                    break;

                case HubProtocolConstants.CompletionMessageType:
                    if (hasResultToken)
                    {
                        var returnType = binder.GetReturnType(invocationId);
                        result = BindType(ref resultToken, returnType);
                    }

                    message = BindCompletionMessage(invocationId, error, result, hasResult, binder);
                    break;

                case HubProtocolConstants.CancelInvocationMessageType:
                    message = BindCancelInvocationMessage(invocationId);
                    break;

                case HubProtocolConstants.PingMessageType:
                    return(PingMessage.Instance);

                case HubProtocolConstants.CloseMessageType:
                    return(BindCloseMessage(error));

                case null:
                    throw new InvalidDataException($"Missing required property '{TypePropertyName}'.");

                default:
                    // Future protocol changes can add message types, old clients can ignore them
                    return(null);
                }

                return(ApplyHeaders(message, headers));
            }
            catch (JsonException jrex)
            {
                throw new InvalidDataException("Error reading JSON.", jrex);
            }
        }
Exemplo n.º 25
0
 public bool TryParseMessage(ref ReadOnlySequence<byte> input, IInvocationBinder binder, out HubMessage message)
 {
     message = null;
     return false;
 }
Exemplo n.º 26
0
        private HubMessage BindInvocationMessage(string invocationId, string target, ExceptionDispatchInfo argumentBindingException, object[] arguments, bool hasArguments, IInvocationBinder binder)
        {
            if (string.IsNullOrEmpty(target))
            {
                throw new InvalidDataException($"Missing required property '{TargetPropertyName}'.");
            }

            if (!hasArguments)
            {
                throw new InvalidDataException($"Missing required property '{ArgumentsPropertyName}'.");
            }

            return(new InvocationMessage(invocationId, target, argumentBindingException: argumentBindingException, arguments: arguments));
        }
Exemplo n.º 27
0
        private CompletionMessage CreateCompletionMessage(ref MessagePackReader reader, IInvocationBinder binder)
        {
            var headers      = ReadHeaders(ref reader);
            var invocationId = ReadInvocationId(ref reader);
            var resultKind   = ReadInt32(ref reader, "resultKind");

            string?error     = null;
            object?result    = null;
            var    hasResult = false;

            switch (resultKind)
            {
            case ErrorResult:
                error = ReadString(ref reader, "error");
                break;

            case NonVoidResult:
                var itemType = binder.GetReturnType(invocationId);
                result    = DeserializeObject(ref reader, itemType, "argument");
                hasResult = true;
                break;

            case VoidResult:
                hasResult = false;
                break;

            default:
                throw new InvalidDataException("Invalid invocation result kind.");
            }

            return(ApplyHeaders(headers, new CompletionMessage(invocationId, error, result, hasResult)));
        }
Exemplo n.º 28
0
        private HubMessage ParseMessage(Utf8BufferTextReader textReader, IInvocationBinder binder)
        {
            try
            {
                // We parse using the JsonTextReader directly but this has a problem. Some of our properties are dependent on other properties
                // and since reading the json might be unordered, we need to store the parsed content as JToken to re-parse when true types are known.
                // if we're lucky and the state we need to directly parse is available, then we'll use it.

                int?     type           = null;
                string   invocationId   = null;
                string   target         = null;
                string   error          = null;
                var      hasItem        = false;
                object   item           = null;
                JToken   itemToken      = null;
                var      hasResult      = false;
                object   result         = null;
                JToken   resultToken    = null;
                var      hasArguments   = false;
                object[] arguments      = null;
                JArray   argumentsToken = null;
                ExceptionDispatchInfo       argumentBindingException = null;
                Dictionary <string, string> headers = null;
                var completed = false;

                using (var reader = JsonUtils.CreateJsonTextReader(textReader))
                {
                    reader.DateParseHandling = DateParseHandling.None;

                    JsonUtils.CheckRead(reader);

                    // We're always parsing a JSON object
                    JsonUtils.EnsureObjectStart(reader);

                    do
                    {
                        switch (reader.TokenType)
                        {
                        case JsonToken.PropertyName:
                            var memberName = reader.Value.ToString();

                            switch (memberName)
                            {
                            case TypePropertyName:
                                var messageType = JsonUtils.ReadAsInt32(reader, TypePropertyName);

                                if (messageType == null)
                                {
                                    throw new InvalidDataException($"Missing required property '{TypePropertyName}'.");
                                }

                                type = messageType.Value;
                                break;

                            case InvocationIdPropertyName:
                                invocationId = JsonUtils.ReadAsString(reader, InvocationIdPropertyName);
                                break;

                            case TargetPropertyName:
                                target = JsonUtils.ReadAsString(reader, TargetPropertyName);
                                break;

                            case ErrorPropertyName:
                                error = JsonUtils.ReadAsString(reader, ErrorPropertyName);
                                break;

                            case ResultPropertyName:
                                JsonUtils.CheckRead(reader);

                                hasResult = true;

                                if (string.IsNullOrEmpty(invocationId))
                                {
                                    // If we don't have an invocation id then we need to store it as a JToken so we can parse it later
                                    resultToken = JToken.Load(reader);
                                }
                                else
                                {
                                    // If we have an invocation id already we can parse the end result
                                    var returnType = binder.GetReturnType(invocationId);
                                    result = PayloadSerializer.Deserialize(reader, returnType);
                                }
                                break;

                            case ItemPropertyName:
                                JsonUtils.CheckRead(reader);

                                hasItem = true;

                                if (string.IsNullOrEmpty(invocationId))
                                {
                                    // If we don't have an invocation id then we need to store it as a JToken so we can parse it later
                                    itemToken = JToken.Load(reader);
                                }
                                else
                                {
                                    var returnType = binder.GetReturnType(invocationId);
                                    item = PayloadSerializer.Deserialize(reader, returnType);
                                }
                                break;

                            case ArgumentsPropertyName:
                                JsonUtils.CheckRead(reader);

                                if (reader.TokenType != JsonToken.StartArray)
                                {
                                    throw new InvalidDataException($"Expected '{ArgumentsPropertyName}' to be of type {JTokenType.Array}.");
                                }

                                hasArguments = true;

                                if (string.IsNullOrEmpty(target))
                                {
                                    // We don't know the method name yet so just parse an array of generic JArray
                                    argumentsToken = JArray.Load(reader);
                                }
                                else
                                {
                                    try
                                    {
                                        var paramTypes = binder.GetParameterTypes(target);
                                        arguments = BindArguments(reader, paramTypes);
                                    }
                                    catch (Exception ex)
                                    {
                                        argumentBindingException = ExceptionDispatchInfo.Capture(ex);
                                    }
                                }
                                break;

                            case HeadersPropertyName:
                                JsonUtils.CheckRead(reader);
                                headers = ReadHeaders(reader);
                                break;

                            default:
                                // Skip read the property name
                                JsonUtils.CheckRead(reader);
                                // Skip the value for this property
                                reader.Skip();
                                break;
                            }
                            break;

                        case JsonToken.EndObject:
                            completed = true;
                            break;
                        }
                    }while (!completed && JsonUtils.CheckRead(reader));
                }

                HubMessage message;

                switch (type)
                {
                case HubProtocolConstants.InvocationMessageType:
                {
                    if (argumentsToken != null)
                    {
                        try
                        {
                            var paramTypes = binder.GetParameterTypes(target);
                            arguments = BindArguments(argumentsToken, paramTypes);
                        }
                        catch (Exception ex)
                        {
                            argumentBindingException = ExceptionDispatchInfo.Capture(ex);
                        }
                    }

                    message = BindInvocationMessage(invocationId, target, argumentBindingException, arguments, hasArguments, binder);
                }
                break;

                case HubProtocolConstants.StreamInvocationMessageType:
                {
                    if (argumentsToken != null)
                    {
                        try
                        {
                            var paramTypes = binder.GetParameterTypes(target);
                            arguments = BindArguments(argumentsToken, paramTypes);
                        }
                        catch (Exception ex)
                        {
                            argumentBindingException = ExceptionDispatchInfo.Capture(ex);
                        }
                    }

                    message = BindStreamInvocationMessage(invocationId, target, argumentBindingException, arguments, hasArguments, binder);
                }
                break;

                case HubProtocolConstants.StreamItemMessageType:
                    if (itemToken != null)
                    {
                        var returnType = binder.GetReturnType(invocationId);
                        item = itemToken.ToObject(returnType, PayloadSerializer);
                    }

                    message = BindStreamItemMessage(invocationId, item, hasItem, binder);
                    break;

                case HubProtocolConstants.CompletionMessageType:
                    if (resultToken != null)
                    {
                        var returnType = binder.GetReturnType(invocationId);
                        result = resultToken.ToObject(returnType, PayloadSerializer);
                    }

                    message = BindCompletionMessage(invocationId, error, result, hasResult, binder);
                    break;

                case HubProtocolConstants.CancelInvocationMessageType:
                    message = BindCancelInvocationMessage(invocationId);
                    break;

                case HubProtocolConstants.PingMessageType:
                    return(PingMessage.Instance);

                case HubProtocolConstants.CloseMessageType:
                    return(BindCloseMessage(error));

                case null:
                    throw new InvalidDataException($"Missing required property '{TypePropertyName}'.");

                default:
                    // Future protocol changes can add message types, old clients can ignore them
                    return(null);
                }

                return(ApplyHeaders(message, headers));
            }
            catch (JsonReaderException jrex)
            {
                throw new InvalidDataException("Error reading JSON.", jrex);
            }
        }
Exemplo n.º 29
0
 private HubProtocol(ConnectionContext connection, int?maximumMessageSize, IHubProtocol hubProtocol, IInvocationBinder invocationBinder)
 {
     _connection         = connection;
     _maximumMessageSize = maximumMessageSize;
     _hubProtocol        = hubProtocol;
     _invocationBinder   = invocationBinder;
     _runningTask        = RunAsync();
 }
Exemplo n.º 30
0
        public TestClient(bool synchronousCallbacks = false, IHubProtocol protocol = null, IInvocationBinder invocationBinder = null, bool addClaimId = false)
        {
            var options = new ChannelOptimizations {
                AllowSynchronousContinuations = synchronousCallbacks
            };
            var transportToApplication = Channel.CreateUnbounded <byte[]>(options);
            var applicationToTransport = Channel.CreateUnbounded <byte[]>(options);

            Application = ChannelConnection.Create <byte[]>(input: applicationToTransport, output: transportToApplication);
            _transport  = ChannelConnection.Create <byte[]>(input: transportToApplication, output: applicationToTransport);

            Connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), _transport, Application);

            var claimValue = Interlocked.Increment(ref _id).ToString();
            var claims     = new List <Claim> {
                new Claim(ClaimTypes.Name, claimValue)
            };

            if (addClaimId)
            {
                claims.Add(new Claim(ClaimTypes.NameIdentifier, claimValue));
            }

            Connection.User = new ClaimsPrincipal(new ClaimsIdentity(claims));
            Connection.Metadata["ConnectedTask"] = new TaskCompletionSource <bool>();

            protocol = protocol ?? new JsonHubProtocol();
            _protocolReaderWriter = new HubProtocolReaderWriter(protocol, new PassThroughEncoder());
            _invocationBinder     = invocationBinder ?? new DefaultInvocationBinder();

            _cts = new CancellationTokenSource();

            using (var memoryStream = new MemoryStream())
            {
                NegotiationProtocol.WriteMessage(new NegotiationMessage(protocol.Name), memoryStream);
                Application.Out.TryWrite(memoryStream.ToArray());
            }
        }