/// <summary> /// Writes the serialized representation of a <see cref="HandshakeResponseMessage"/> to the specified writer. /// </summary> /// <param name="responseMessage">The message to write.</param> /// <param name="output">The output writer.</param> public static void WriteResponseMessage(HandshakeResponseMessage responseMessage, IBufferWriter <byte> output) { var reusableWriter = ReusableUtf8JsonWriter.Get(output); try { var writer = reusableWriter.GetJsonWriter(); writer.WriteStartObject(); if (!string.IsNullOrEmpty(responseMessage.Error)) { writer.WriteString(ErrorPropertyNameBytes, responseMessage.Error); } writer.WriteEndObject(); writer.Flush(); Debug.Assert(writer.CurrentDepth == 0); } finally { ReusableUtf8JsonWriter.Return(reusableWriter); } TextMessageFormatter.WriteRecordSeparator(output); }
/// <summary> /// Writes the serialized representation of a <see cref="HandshakeResponseMessage"/> to the specified writer. /// </summary> /// <param name="responseMessage">The message to write.</param> /// <param name="output">The output writer.</param> public static void WriteResponseMessage(HandshakeResponseMessage responseMessage, IBufferWriter <byte> output) { var textWriter = Utf8BufferTextWriter.Get(output); try { using (var writer = JsonUtils.CreateJsonTextWriter(textWriter)) { writer.WriteStartObject(); if (!string.IsNullOrEmpty(responseMessage.Error)) { writer.WritePropertyName(ErrorPropertyName); writer.WriteValue(responseMessage.Error); } writer.WritePropertyName(MinorVersionPropertyName); writer.WriteValue(responseMessage.MinorVersion); writer.WriteEndObject(); writer.Flush(); } } finally { Utf8BufferTextWriter.Return(textWriter); } TextMessageFormatter.WriteRecordSeparator(output); }
public async Task TestCloseConnectionMessageWithMigrateOut() { var clientConnectionFactory = new TestClientConnectionFactory(); var connection = CreateServiceConnection(clientConnectionFactory: clientConnectionFactory, handler: new TestConnectionHandler(3000, "foobar")); _ = connection.StartAsync(); await connection.ConnectionInitializedTask.OrTimeout(1000); var openConnectionMessage = new OpenConnectionMessage("foo", Array.Empty <Claim>()); _ = connection.WriteFromServiceAsync(openConnectionMessage); await connection.ClientConnectedTask; Assert.Equal(1, clientConnectionFactory.Connections.Count); var clientConnection = clientConnectionFactory.Connections[0]; Assert.False(clientConnection.IsMigrated); // write a signalr handshake response var message = new SignalRProtocol.HandshakeResponseMessage(""); SignalRProtocol.HandshakeProtocol.WriteResponseMessage(message, clientConnection.Transport.Output); await clientConnection.Transport.Output.FlushAsync(); // write a close connection message with migration header var closeMessage = new CloseConnectionMessage(clientConnection.ConnectionId); closeMessage.Headers.Add(Constants.AsrsMigrateTo, "another-server"); await connection.WriteFromServiceAsync(closeMessage); // wait until app task completed. await Assert.ThrowsAsync <TimeoutException>(async() => await clientConnection.LifetimeTask.OrTimeout(1000)); await clientConnection.LifetimeTask.OrTimeout(3000); // expect a handshake response message. await connection.ExpectSignalRMessage(SignalRProtocol.HandshakeResponseMessage.Empty).OrTimeout(3000); // signalr close message should be skipped. await Assert.ThrowsAsync <TimeoutException>(async() => await connection.ExpectSignalRMessage(SignalRProtocol.CloseMessage.Empty).OrTimeout(1000)); var feature = clientConnection.Features.Get <IConnectionMigrationFeature>(); Assert.NotNull(feature); Assert.Equal("another-server", feature.MigrateTo); await connection.StopAsync(); }
/// <summary> /// Creates a new <see cref="HandshakeResponseMessage"/> from the specified serialized representation. /// </summary> /// <param name="buffer">The serialized representation of the message.</param> /// <param name="responseMessage">When this method returns, contains the parsed message.</param> /// <returns>A value that is <c>true</c> if the <see cref="HandshakeResponseMessage"/> was successfully parsed; otherwise, <c>false</c>.</returns> public static bool TryParseResponseMessage(ref ReadOnlySequence <byte> buffer, out HandshakeResponseMessage responseMessage) { if (!TextMessageParser.TryParseMessage(ref buffer, out var payload)) { responseMessage = null; return(false); } var reader = new Utf8JsonReader(payload, isFinalBlock: true, state: default); reader.CheckRead(); reader.EnsureObjectStart(); string error = null; while (reader.CheckRead()) { if (reader.TokenType == JsonTokenType.PropertyName) { if (reader.ValueTextEquals(TypePropertyNameBytes.EncodedUtf8Bytes)) { // a handshake response does not have a type // check the incoming message was not any other type of message throw new InvalidDataException("Expected a handshake response from the server."); } else if (reader.ValueTextEquals(ErrorPropertyNameBytes.EncodedUtf8Bytes)) { error = reader.ReadAsString(ErrorPropertyName); } else { reader.Skip(); } } else if (reader.TokenType == JsonTokenType.EndObject) { break; } else { throw new InvalidDataException($"Unexpected token '{reader.TokenType}' when reading handshake response JSON."); } } ; responseMessage = new HandshakeResponseMessage(error); return(true); }
/// <summary> /// Writes the serialized representation of a <see cref="HandshakeResponseMessage"/> to the specified writer. /// </summary> /// <param name="responseMessage">The message to write.</param> /// <param name="output">The output writer.</param> public static void WriteResponseMessage(HandshakeResponseMessage responseMessage, IBufferWriter <byte> output) { var writer = new Utf8JsonWriter(output, new JsonWriterState(new JsonWriterOptions() { SkipValidation = true })); writer.WriteStartObject(); if (!string.IsNullOrEmpty(responseMessage.Error)) { writer.WriteString(ErrorPropertyNameBytes, responseMessage.Error); } writer.WriteNumber(MinorVersionPropertyNameBytes, responseMessage.MinorVersion, escape: false); writer.WriteEndObject(); writer.Flush(isFinalBlock: true); TextMessageFormatter.WriteRecordSeparator(output); }
/// <summary> /// Writes the serialized representation of a <see cref="HandshakeResponseMessage"/> to the specified writer. /// </summary> /// <param name="responseMessage">The message to write.</param> /// <param name="output">The output writer.</param> public static void WriteResponseMessage(HandshakeResponseMessage responseMessage, IBufferWriter <byte> output) { using var writer = new Utf8JsonWriter(output, new JsonWriterOptions() { SkipValidation = true }); writer.WriteStartObject(); if (!string.IsNullOrEmpty(responseMessage.Error)) { writer.WriteString(ErrorPropertyNameBytes, responseMessage.Error); } writer.WriteNumber(MinorVersionPropertyNameBytes, responseMessage.MinorVersion); writer.WriteEndObject(); writer.Flush(); Debug.Assert(writer.CurrentDepth == 0); TextMessageFormatter.WriteRecordSeparator(output); }
public async Task TestCloseConnectionMessage() { var clientConnectionFactory = new TestClientConnectionFactory(); var connection = CreateServiceConnection(clientConnectionFactory: clientConnectionFactory, handler: new TestConnectionHandler(3000, "foobar")); _ = connection.StartAsync(); await connection.ConnectionInitializedTask.OrTimeout(1000); var openConnectionMessage = new OpenConnectionMessage("foo", Array.Empty <Claim>()); _ = connection.WriteFromServiceAsync(openConnectionMessage); await connection.ClientConnectedTask; Assert.Equal(1, clientConnectionFactory.Connections.Count); var clientConnection = clientConnectionFactory.Connections[0]; // write a signalr handshake response var message = new SignalRProtocol.HandshakeResponseMessage(""); SignalRProtocol.HandshakeProtocol.WriteResponseMessage(message, clientConnection.Transport.Output); // write close connection message await connection.WriteFromServiceAsync(new CloseConnectionMessage(clientConnection.ConnectionId)); // wait until app task completed. await Assert.ThrowsAsync <TimeoutException>(async() => await clientConnection.LifetimeTask.OrTimeout(1000)); await clientConnection.LifetimeTask; await connection.ExpectSignalRMessage(SignalRProtocol.HandshakeResponseMessage.Empty).OrTimeout(1000); await connection.ExpectStringMessage("foobar").OrTimeout(1000); await connection.ExpectSignalRMessage(SignalRProtocol.CloseMessage.Empty).OrTimeout(1000); await connection.StopAsync(); }
public async Task TestOpenConnectionMessageWithMigrateIn() { var clientConnectionFactory = new TestClientConnectionFactory(); var connection = CreateServiceConnection(clientConnectionFactory: clientConnectionFactory); _ = connection.StartAsync(); await connection.ConnectionInitializedTask.OrTimeout(1000); var openConnectionMessage = new OpenConnectionMessage("foo", Array.Empty <Claim>()); openConnectionMessage.Headers.Add(Constants.AsrsMigrateFrom, "another-server"); _ = connection.WriteFromServiceAsync(openConnectionMessage); await connection.ClientConnectedTask; Assert.Equal(1, clientConnectionFactory.Connections.Count); var clientConnection = clientConnectionFactory.Connections[0]; Assert.True(clientConnection.IsMigrated); // write a handshake response var message = new SignalRProtocol.HandshakeResponseMessage(""); SignalRProtocol.HandshakeProtocol.WriteResponseMessage(message, clientConnection.Transport.Output); await clientConnection.Transport.Output.FlushAsync(); // signalr handshake response should be skipped. await Assert.ThrowsAsync <TimeoutException>(async() => await connection.ExpectSignalRMessage(SignalRProtocol.HandshakeResponseMessage.Empty).OrTimeout(1000)); Assert.True(clientConnection.IsMigrated); var feature = clientConnection.Features.Get <IConnectionMigrationFeature>(); Assert.NotNull(feature); Assert.Equal("another-server", feature.MigrateFrom); await connection.StopAsync(); }
/// <summary> /// Creates a new <see cref="HandshakeResponseMessage"/> from the specified serialized representation. /// </summary> /// <param name="buffer">The serialized representation of the message.</param> /// <param name="responseMessage">When this method returns, contains the parsed message.</param> /// <returns>A value that is <c>true</c> if the <see cref="HandshakeResponseMessage"/> was successfully parsed; otherwise, <c>false</c>.</returns> public static bool TryParseResponseMessage(ref ReadOnlySequence <byte> buffer, out HandshakeResponseMessage responseMessage) { if (!TextMessageParser.TryParseMessage(ref buffer, out var payload)) { responseMessage = null; return(false); } var reader = new Utf8JsonReader(in payload, isFinalBlock: true, state: default);
/// <summary> /// Creates a new <see cref="HandshakeResponseMessage"/> from the specified serialized representation. /// </summary> /// <param name="buffer">The serialized representation of the message.</param> /// <param name="responseMessage">When this method returns, contains the parsed message.</param> /// <returns>A value that is <c>true</c> if the <see cref="HandshakeResponseMessage"/> was successfully parsed; otherwise, <c>false</c>.</returns> public static bool TryParseResponseMessage(ref ReadOnlySequence <byte> buffer, out HandshakeResponseMessage responseMessage) { if (!TextMessageParser.TryParseMessage(ref buffer, out var payload)) { responseMessage = null; return(false); } var textReader = Utf8BufferTextReader.Get(payload); try { using (var reader = JsonUtils.CreateJsonTextReader(textReader)) { JsonUtils.CheckRead(reader); JsonUtils.EnsureObjectStart(reader); int? minorVersion = null; string error = null; var completed = false; while (!completed && JsonUtils.CheckRead(reader)) { switch (reader.TokenType) { case JsonToken.PropertyName: var memberName = reader.Value.ToString(); switch (memberName) { case TypePropertyName: // a handshake response does not have a type // check the incoming message was not any other type of message throw new InvalidDataException("Expected a handshake response from the server."); case ErrorPropertyName: error = JsonUtils.ReadAsString(reader, ErrorPropertyName); break; case MinorVersionPropertyName: minorVersion = JsonUtils.ReadAsInt32(reader, MinorVersionPropertyName); break; default: reader.Skip(); break; } break; case JsonToken.EndObject: completed = true; break; default: throw new InvalidDataException($"Unexpected token '{reader.TokenType}' when reading handshake response JSON."); } } ; responseMessage = new HandshakeResponseMessage(minorVersion, error); return(true); } } finally { Utf8BufferTextReader.Return(textReader); } }