예제 #1
0
        /// <summary>
        /// Read data from pipeline when available, constructing new RCON packets
        /// </summary>
        /// <param name="reader"></param>
        /// <returns>Consumer Task</returns>
        async Task ReadPipeAsync(PipeReader reader)
        {
            byte[] byteArr = new byte[Constants.MAX_PACKET_SIZE];
            while (true)
            {
                ReadResult result = await reader.ReadAsync();

                ReadOnlySequence <byte> buffer      = result.Buffer;
                SequencePosition        packetStart = buffer.Start;

                if (buffer.Length < 4)
                {
                    if (result.IsCompleted)
                    {
                        break;
                    }
                    reader.AdvanceTo(packetStart, buffer.End);
                    continue;
                    // Complete header not yet received
                }
                int size = BitConverter.ToInt32(buffer.Slice(packetStart, 4).ToArray(), 0);
                if (buffer.Length >= size + 4)
                {
                    // Get packet end positions
                    SequencePosition packetEnd = buffer.GetPosition(size + 4, packetStart);
                    byteArr = buffer.Slice(packetStart, packetEnd).ToArray();
                    RCONPacket packet = RCONPacket.FromBytes(byteArr);

                    if (packet.Type == PacketType.AuthResponse)
                    {
                        // Failed auth responses return with an ID of -1
                        if (packet.Id == -1)
                        {
                            _authenticationTask.SetException(
                                new AuthenticationException($"Authentication failed for {_tcp.RemoteEndPoint}.")
                                );
                        }
                        // Tell Connect that authentication succeeded
                        _authenticationTask.SetResult(true);
                    }

                    // Forward rcon packet to handler
                    RCONPacketReceived(packet);

                    reader.AdvanceTo(packetEnd);
                }
                else
                {
                    reader.AdvanceTo(packetStart, buffer.End);
                }

                // Tell the PipeReader how much of the buffer we have consumed

                // Stop reading if there's no more data coming
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    break; // exit loop
                }
            }

            // If authentication did not complete
            _authenticationTask.TrySetException(
                new AuthenticationException($"Server did not respond to auth {_tcp.RemoteEndPoint}.")
                );

            // Mark the PipeReader as complete
            await reader.CompleteAsync();
        }
예제 #2
0
        public static ParsedMessage?TryParseMessage(ReadOnlySequence <byte> buf)
        {
            var be = Binary.BigEndian;

            if (buf.Length < 4)
            {
                return(null);
            }

            var off = 4;
            var len = be.GetUInt32(buf.Slice(0, 4).ToArray());

            if (len == 0)
            {
                return new ParsedMessage {
                           Message  = new KeepAlive(),
                           Position = buf.GetPosition(off)
                }
            }
            ;

            if (len + off > buf.Length)
            {
                return(null);
            }

            var type = buf.Slice(off++, 1).FirstSpan[0];

            IProtocolMessage?parsed = null;

            switch (type)
            {
            case 0:
                parsed = new Choke();
                break;

            case 1:
                parsed = new Unchoke();
                break;

            case 2:
                parsed = new Interested();
                break;

            case 3:
                parsed = new NotInterested();
                break;

            case 4: {
                var idx = be.GetUInt32(buf.Slice(off, 4).ToArray());
                off   += 4;
                parsed = new Have {
                    PieceIndex = idx
                };
                break;
            }

            case 5: {
                var bitfieldLen = (int)(len - 1);
                var bits        = buf.Slice(off, bitfieldLen).ToArray();
                off   += bitfieldLen;
                parsed = new Bitfield {
                    Bits = bits
                };
                break;
            }

            case 6:
                throw new NotImplementedException("Request");

            case 7:
                throw new NotImplementedException("Piece");

            case 8:
                throw new NotImplementedException("Cancel");

            case 20:
                throw new NotImplementedException("Extension Message");

            default:
                throw new ArgumentOutOfRangeException(nameof(type), $"Invalid Peer Message type {type}");
            }

            if (parsed != null)
            {
                return new ParsedMessage {
                           Message  = parsed,
                           Position = buf.GetPosition(off)
                }
            }
            ;

            return(null);
        }
    }
}
        public ParseResult ParseMessage(ReadOnlySequence <byte> buffer, out SequencePosition consumed, out SequencePosition examined, out byte[] message)
        {
            consumed = buffer.Start;
            examined = buffer.End;
            message  = null;

            var start = consumed;

            while (buffer.Length > 0)
            {
                if (!(buffer.PositionOf(ByteLF) is SequencePosition lineEnd))
                {
                    // For the case of data: Foo\r\n\r\<Anything except \n>
                    if (_internalParserState == InternalParseState.ReadEndOfMessage)
                    {
                        if (ConvertBufferToSpan(buffer.Slice(start, buffer.End)).Length > 1)
                        {
                            throw new FormatException("Expected a \\r\\n frame ending");
                        }
                    }

                    // Partial message. We need to read more.
                    return(ParseResult.Incomplete);
                }

                lineEnd = buffer.GetPosition(1, lineEnd);
                var line = ConvertBufferToSpan(buffer.Slice(start, lineEnd));
                buffer = buffer.Slice(line.Length);

                if (line.Length <= 1)
                {
                    throw new FormatException("There was an error in the frame format");
                }

                // Skip comments
                if (line[0] == ByteColon)
                {
                    start    = lineEnd;
                    consumed = lineEnd;
                    continue;
                }

                if (IsMessageEnd(line))
                {
                    _internalParserState = InternalParseState.ReadEndOfMessage;
                }

                // To ensure that the \n was preceded by a \r
                // since messages can't contain \n.
                // data: foo\n\bar should be encoded as
                // data: foo\r\n
                // data: bar\r\n
                else if (line[line.Length - SseLineEnding.Length] != ByteCR)
                {
                    throw new FormatException("Unexpected '\\n' in message. A '\\n' character can only be used as part of the newline sequence '\\r\\n'");
                }
                else
                {
                    EnsureStartsWithDataPrefix(line);
                }

                var payload = Array.Empty <byte>();
                switch (_internalParserState)
                {
                case InternalParseState.ReadMessagePayload:
                    EnsureStartsWithDataPrefix(line);

                    // Slice away the 'data: '
                    var payloadLength = line.Length - (DataPrefix.Length + SseLineEnding.Length);
                    var newData       = line.Slice(DataPrefix.Length, payloadLength).ToArray();
                    _data.Add(newData);

                    start    = lineEnd;
                    consumed = lineEnd;
                    break;

                case InternalParseState.ReadEndOfMessage:
                    if (_data.Count == 1)
                    {
                        payload = _data[0];
                    }
                    else if (_data.Count > 1)
                    {
                        // Find the final size of the payload
                        var payloadSize = 0;
                        foreach (var dataLine in _data)
                        {
                            payloadSize += dataLine.Length;
                        }

                        payloadSize += _newLine.Length * _data.Count;

                        // Allocate space in the payload buffer for the data and the new lines.
                        // Subtract newLine length because we don't want a trailing newline.
                        payload = new byte[payloadSize - _newLine.Length];

                        var offset = 0;
                        foreach (var dataLine in _data)
                        {
                            dataLine.CopyTo(payload, offset);
                            offset += dataLine.Length;
                            if (offset < payload.Length)
                            {
                                _newLine.CopyTo(payload, offset);
                                offset += _newLine.Length;
                            }
                        }
                    }

                    message  = payload;
                    consumed = lineEnd;
                    examined = consumed;
                    return(ParseResult.Completed);
                }

                if (buffer.Length > 0 && buffer.First.Span[0] == ByteCR)
                {
                    _internalParserState = InternalParseState.ReadEndOfMessage;
                }
            }
            return(ParseResult.Incomplete);
        }
        /// <summary>
        /// Searches for a byte in the <see cref="ReadOnlyBuffer"/> and returns a sliced <see cref="ReadOnlyBuffer"/> that
        /// contains all data up to and excluding the byte, and a <see cref="SequencePosition"/> that points to the byte.
        /// </summary>
        /// <param name="b1">The first byte to search for</param>
        /// <param name="slice">A <see cref="ReadOnlyBuffer"/> slice that contains all data up to and excluding the first byte.</param>
        /// <param name="cursor">A <see cref="SequencePosition"/> that points to the second byte</param>
        /// <returns>True if the byte sequence was found, false if not found</returns>
        public static bool TrySliceTo(this ReadOnlySequence <byte> buffer, byte b1, out ReadOnlySequence <byte> slice, out SequencePosition cursor)
        {
            if (buffer.IsEmpty)
            {
                slice  = default;
                cursor = default;
                return(false);
            }

            var byte0Vector = GetVector(b1);

            var seek = 0;

            foreach (var memory in buffer)
            {
                var currentSpan = memory.Span;
                var found       = false;

                if (Vector.IsHardwareAccelerated)
                {
                    while (currentSpan.Length >= VectorWidth)
                    {
                        var data        = MemoryMarshal.Read <Vector <byte> >(currentSpan);
                        var byte0Equals = Vector.Equals(data, byte0Vector);

                        if (byte0Equals.Equals(Vector <byte> .Zero))
                        {
                            currentSpan = currentSpan.Slice(VectorWidth);
                            seek       += VectorWidth;
                        }
                        else
                        {
                            var index = FindFirstEqualByte(ref byte0Equals);
                            seek += index;
                            found = true;
                            break;
                        }
                    }
                }

                if (!found)
                {
                    // Slow search
                    for (int i = 0; i < currentSpan.Length; i++)
                    {
                        if (currentSpan[i] == b1)
                        {
                            found = true;
                            break;
                        }
                        seek++;
                    }
                }

                if (found)
                {
                    cursor = buffer.GetPosition(seek);
                    slice  = buffer.Slice(buffer.Start, cursor);
                    return(true);
                }
            }

            slice  = default;
            cursor = default;
            return(false);
        }
        public async Task OnConnectedAsync(FramingConnection connection)
        {
            TimeSpan receiveTimeout = connection.ServiceDispatcher.Binding.ReceiveTimeout;
            var      timeoutHelper  = new TimeoutHelper(receiveTimeout);
            bool     success        = false;

            try
            {
                var decoder = connection.FramingDecoder as ServerSingletonDecoder;
                Fx.Assert(decoder != null, "FramingDecoder must be non-null and an instance of ServerSessionDecoder");

                // first validate our content type
                //ValidateContentType(connection, decoder);
                UpgradeState upgradeState = UpgradeState.None;
                // next read any potential upgrades and finish consuming the preamble
                ReadOnlySequence <byte> buffer = ReadOnlySequence <byte> .Empty;
                while (true)
                {
                    if (buffer.Length == 0 && CanReadAndDecode(upgradeState))
                    {
                        System.IO.Pipelines.ReadResult readResult = await connection.Input.ReadAsync();

                        buffer = readResult.Buffer;
                        if (readResult.IsCompleted)
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(decoder.CreatePrematureEOFException());
                        }
                    }

                    while (true)
                    {
                        if (CanReadAndDecode(upgradeState))
                        {
                            Fx.Assert(buffer.Length > 0, "There must be something in the buffer to decode");
                            int bytesDecoded = decoder.Decode(buffer);
                            if (bytesDecoded > 0)
                            {
                                buffer = buffer.Slice(bytesDecoded);
                                if (buffer.Length == 0)
                                {
                                    connection.Input.AdvanceTo(buffer.Start);
                                }
                            }
                        }

                        switch (decoder.CurrentState)
                        {
                        case ServerSingletonDecoder.State.UpgradeRequest:
                            switch (upgradeState)
                            {
                            case UpgradeState.None:
                                //change the state so that we don't read/decode until it is safe
                                ChangeUpgradeState(ref upgradeState, UpgradeState.VerifyingUpgradeRequest);
                                break;

                            case UpgradeState.VerifyingUpgradeRequest:
                                if (connection.StreamUpgradeAcceptor == null)
                                {
                                    await connection.SendFaultAsync(FramingEncodingString.UpgradeInvalidFault, timeoutHelper.RemainingTime(), TransportDefaults.MaxDrainSize);

                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                                              new ProtocolException(SR.Format(SR.UpgradeRequestToNonupgradableService, decoder.Upgrade)));
                                }

                                if (!connection.StreamUpgradeAcceptor.CanUpgrade(decoder.Upgrade))
                                {
                                    await connection.SendFaultAsync(FramingEncodingString.UpgradeInvalidFault, timeoutHelper.RemainingTime(), TransportDefaults.MaxDrainSize);

                                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.Format(SR.UpgradeProtocolNotSupported, decoder.Upgrade)));
                                }

                                ChangeUpgradeState(ref upgradeState, UpgradeState.WritingUpgradeAck);
                                // accept upgrade
                                await connection.Output.WriteAsync(ServerSingletonEncoder.UpgradeResponseBytes, timeoutHelper.GetCancellationToken());

                                await connection.Output.FlushAsync(timeoutHelper.GetCancellationToken());

                                ChangeUpgradeState(ref upgradeState, UpgradeState.UpgradeAckSent);
                                break;

                            case UpgradeState.UpgradeAckSent:
                                // This state was used to capture any extra read bytes into PreReadConnection but we don't need to do that when using pipes.
                                // This extra state transition has been left here to maintain the same state transitions as on .NET Framework to make comparison easier.
                                ChangeUpgradeState(ref upgradeState, UpgradeState.BeginUpgrade);
                                break;

                            case UpgradeState.BeginUpgrade:
                                // Set input pipe so that the next read will return all the unconsumed bytes.
                                // If all bytes have already been consumed so the buffer has 0 length, AdvanceTo would throw
                                // as it's already been called.
                                if (buffer.Length > 0)
                                {
                                    connection.Input.AdvanceTo(buffer.Start);
                                }

                                buffer = ReadOnlySequence <byte> .Empty;
                                try
                                {
                                    await UpgradeConnectionAsync(connection);

                                    ChangeUpgradeState(ref upgradeState, UpgradeState.EndUpgrade);
                                }
                                catch (Exception exception)
                                {
                                    if (Fx.IsFatal(exception))
                                    {
                                        throw;
                                    }

                                    throw;
                                }
                                break;

                            case UpgradeState.EndUpgrade:
                                //Must be a different state here than UpgradeComplete so that we don't try to read from the connection
                                ChangeUpgradeState(ref upgradeState, UpgradeState.UpgradeComplete);
                                break;

                            case UpgradeState.UpgradeComplete:
                                //Client is doing more than one upgrade, reset the state
                                ChangeUpgradeState(ref upgradeState, UpgradeState.VerifyingUpgradeRequest);
                                break;
                            }
                            break;

                        case ServerSingletonDecoder.State.Start:
                            SetupSecurityIfNecessary(connection);
                            if (upgradeState == UpgradeState.UpgradeComplete ||  //We have done at least one upgrade, but we are now done.
                                upgradeState == UpgradeState.None)       //no upgrade, just send the preample end bytes
                            {
                                ChangeUpgradeState(ref upgradeState, UpgradeState.WritingPreambleEnd);
                                // we've finished the preamble. Ack and return.
                                await connection.Output.WriteAsync(ServerSessionEncoder.AckResponseBytes);

                                await connection.Output.FlushAsync();

                                //terminal state
                                ChangeUpgradeState(ref upgradeState, UpgradeState.PreambleEndSent);
                            }
                            // If all bytes have already been consumed so the buffer has 0 length, AdvanceTo would throw
                            // as it's already been called.
                            if (buffer.Length > 0)
                            {
                                connection.Input.AdvanceTo(buffer.Start);
                            }

                            success = true;
                            await _next(connection);

                            return;
                        }

                        if (buffer.Length == 0)
                        {
                            break;
                        }
                    }
                }
            }
            finally
            {
                if (!success)
                {
                    connection.Abort();
                }
            }
        }
        public static void TestPartialJsonReaderMultiSegment(bool compactData, TestCaseType type, string jsonString)
        {
            // Skipping really large JSON since slicing them (O(n^2)) is too slow.
            if (type == TestCaseType.Json40KB || type == TestCaseType.Json400KB || type == TestCaseType.ProjectLockJson ||
                type == TestCaseType.DeepTree || type == TestCaseType.BroadTree || type == TestCaseType.LotsOfNumbers ||
                type == TestCaseType.LotsOfStrings || type == TestCaseType.Json4KB)
            {
                return;
            }

            // Remove all formatting/indendation
            if (compactData)
            {
                using (JsonTextReader jsonReader = new JsonTextReader(new StringReader(jsonString)))
                {
                    jsonReader.FloatParseHandling = FloatParseHandling.Decimal;
                    JToken jtoken       = JToken.ReadFrom(jsonReader);
                    var    stringWriter = new StringWriter();
                    using (JsonTextWriter jsonWriter = new JsonTextWriter(stringWriter))
                    {
                        jtoken.WriteTo(jsonWriter);
                        jsonString = stringWriter.ToString();
                    }
                }
            }

            byte[] dataUtf8 = Encoding.UTF8.GetBytes(jsonString);
            ReadOnlyMemory <byte> dataMemory = dataUtf8;

            var sequences = new List <ReadOnlySequence <byte> >
            {
                new ReadOnlySequence <byte>(dataMemory)
            };

            for (int i = 0; i < dataUtf8.Length; i++)
            {
                var firstSegment = new BufferSegment <byte>(dataMemory.Slice(0, i));
                ReadOnlyMemory <byte> secondMem     = dataMemory.Slice(i);
                BufferSegment <byte>  secondSegment = firstSegment.Append(secondMem);
                var sequence = new ReadOnlySequence <byte>(firstSegment, 0, secondSegment, secondMem.Length);
                sequences.Add(sequence);
            }

            for (int i = 0; i < sequences.Count; i++)
            {
                var json = new Utf8JsonReader(sequences[i], isFinalBlock: true, default);
                while (json.Read())
                {
                    ;
                }
                Assert.Equal(sequences[i].Length, json.BytesConsumed);
                Assert.Equal(sequences[i].Length, json.CurrentState.BytesConsumed);

                Assert.True(sequences[i].Slice(json.Position).IsEmpty);
                Assert.True(sequences[i].Slice(json.CurrentState.Position).IsEmpty);
            }

            for (int i = 0; i < sequences.Count; i++)
            {
                ReadOnlySequence <byte> sequence = sequences[i];
                for (int j = 0; j < dataUtf8.Length; j++)
                {
                    var json = new Utf8JsonReader(sequence.Slice(0, j), isFinalBlock: false, default);
                    while (json.Read())
                    {
                        ;
                    }

                    long            consumed      = json.BytesConsumed;
                    JsonReaderState jsonState     = json.CurrentState;
                    byte[]          consumedArray = sequence.Slice(0, consumed).ToArray();
                    Assert.Equal(consumedArray, sequence.Slice(0, json.Position).ToArray());
                    Assert.Equal(consumedArray, sequence.Slice(0, jsonState.Position).ToArray());
                    json = new Utf8JsonReader(sequence.Slice(consumed), isFinalBlock: true, json.CurrentState);
                    while (json.Read())
                    {
                        ;
                    }
                    Assert.Equal(dataUtf8.Length - consumed, json.BytesConsumed);
                    Assert.Equal(json.BytesConsumed, json.CurrentState.BytesConsumed);
                }
            }
        }
예제 #7
0
        public Task OnDataAsync(Http2Frame dataFrame, ReadOnlySequence <byte> payload)
        {
            // Since padding isn't buffered, immediately count padding bytes as read for flow control purposes.
            if (dataFrame.DataHasPadding)
            {
                // Add 1 byte for the padding length prefix.
                OnDataRead(dataFrame.DataPadLength + 1);
            }

            var dataPayload = payload.Slice(0, dataFrame.DataPayloadLength); // minus padding
            var endStream   = dataFrame.DataEndStream;

            if (dataPayload.Length > 0)
            {
                RequestBodyStarted = true;

                if (endStream)
                {
                    // No need to send any more window updates for this stream now that we've received all the data.
                    // Call before flushing the request body pipe, because that might induce a window update.
                    _inputFlowControl.StopWindowUpdates();
                }

                _inputFlowControl.Advance((int)dataPayload.Length);

                lock (_completionLock)
                {
                    if (IsAborted)
                    {
                        // Ignore data frames for aborted streams, but only after counting them for purposes of connection level flow control.
                        return(Task.CompletedTask);
                    }

                    // This check happens after flow control so that when we throw and abort, the byte count is returned to the connection
                    // level accounting.
                    if (InputRemaining.HasValue)
                    {
                        // https://tools.ietf.org/html/rfc7540#section-8.1.2.6
                        if (dataPayload.Length > InputRemaining.Value)
                        {
                            throw new Http2StreamErrorException(StreamId, CoreStrings.Http2StreamErrorMoreDataThanLength, Http2ErrorCode.PROTOCOL_ERROR);
                        }

                        InputRemaining -= dataPayload.Length;
                    }

                    foreach (var segment in dataPayload)
                    {
                        RequestBodyPipe.Writer.Write(segment.Span);
                    }
                    var flushTask = RequestBodyPipe.Writer.FlushAsync();

                    // It shouldn't be possible for the RequestBodyPipe to fill up an return an incomplete task if
                    // _inputFlowControl.Advance() didn't throw.
                    Debug.Assert(flushTask.IsCompleted);
                }
            }

            if (endStream)
            {
                OnEndStreamReceived();
            }

            return(Task.CompletedTask);
        }
예제 #8
0
        internal static bool TryParseValue(
            ref Utf8JsonReader reader,
            [NotNullWhen(true)] out JsonDocument?document,
            bool shouldThrow,
            bool useArrayPools)
        {
            JsonReaderState state = reader.CurrentState;

            CheckSupportedOptions(state.Options, nameof(reader));

            // Value copy to overwrite the ref on an exception and undo the destructive reads.
            Utf8JsonReader restore = reader;

            ReadOnlySpan <byte>     valueSpan     = default;
            ReadOnlySequence <byte> valueSequence = default;

            try
            {
                switch (reader.TokenType)
                {
                // A new reader was created and has never been read,
                // so we need to move to the first token.
                // (or a reader has terminated and we're about to throw)
                case JsonTokenType.None:
                // Using a reader loop the caller has identified a property they wish to
                // hydrate into a JsonDocument. Move to the value first.
                case JsonTokenType.PropertyName:
                {
                    if (!reader.Read())
                    {
                        if (shouldThrow)
                        {
                            ThrowHelper.ThrowJsonReaderException(
                                ref reader,
                                ExceptionResource.ExpectedJsonTokens);
                        }

                        reader   = restore;
                        document = null;
                        return(false);
                    }

                    break;
                }
                }

                switch (reader.TokenType)
                {
                // Any of the "value start" states are acceptable.
                case JsonTokenType.StartObject:
                case JsonTokenType.StartArray:
                {
                    long startingOffset = reader.TokenStartIndex;

                    if (!reader.TrySkip())
                    {
                        if (shouldThrow)
                        {
                            ThrowHelper.ThrowJsonReaderException(
                                ref reader,
                                ExceptionResource.ExpectedJsonTokens);
                        }

                        reader   = restore;
                        document = null;
                        return(false);
                    }

                    long totalLength = reader.BytesConsumed - startingOffset;
                    ReadOnlySequence <byte> sequence = reader.OriginalSequence;

                    if (sequence.IsEmpty)
                    {
                        valueSpan = reader.OriginalSpan.Slice(
                            checked ((int)startingOffset),
                            checked ((int)totalLength));
                    }
                    else
                    {
                        valueSequence = sequence.Slice(startingOffset, totalLength);
                    }

                    Debug.Assert(
                        reader.TokenType == JsonTokenType.EndObject ||
                        reader.TokenType == JsonTokenType.EndArray);

                    break;
                }

                case JsonTokenType.False:
                case JsonTokenType.True:
                case JsonTokenType.Null:
                    if (useArrayPools)
                    {
                        if (reader.HasValueSequence)
                        {
                            valueSequence = reader.ValueSequence;
                        }
                        else
                        {
                            valueSpan = reader.ValueSpan;
                        }

                        break;
                    }

                    document = CreateForLiteral(reader.TokenType);
                    return(true);

                case JsonTokenType.Number:
                {
                    if (reader.HasValueSequence)
                    {
                        valueSequence = reader.ValueSequence;
                    }
                    else
                    {
                        valueSpan = reader.ValueSpan;
                    }

                    break;
                }

                // String's ValueSequence/ValueSpan omits the quotes, we need them back.
                case JsonTokenType.String:
                {
                    ReadOnlySequence <byte> sequence = reader.OriginalSequence;

                    if (sequence.IsEmpty)
                    {
                        // Since the quoted string fit in a ReadOnlySpan originally
                        // the contents length plus the two quotes can't overflow.
                        int payloadLength = reader.ValueSpan.Length + 2;
                        Debug.Assert(payloadLength > 1);

                        ReadOnlySpan <byte> readerSpan = reader.OriginalSpan;

                        Debug.Assert(
                            readerSpan[(int)reader.TokenStartIndex] == (byte)'"',
                            $"Calculated span starts with {readerSpan[(int)reader.TokenStartIndex]}");

                        Debug.Assert(
                            readerSpan[(int)reader.TokenStartIndex + payloadLength - 1] == (byte)'"',
                            $"Calculated span ends with {readerSpan[(int)reader.TokenStartIndex + payloadLength - 1]}");

                        valueSpan = readerSpan.Slice((int)reader.TokenStartIndex, payloadLength);
                    }
                    else
                    {
                        long payloadLength = 2;

                        if (reader.HasValueSequence)
                        {
                            payloadLength += reader.ValueSequence.Length;
                        }
                        else
                        {
                            payloadLength += reader.ValueSpan.Length;
                        }

                        valueSequence = sequence.Slice(reader.TokenStartIndex, payloadLength);
                        Debug.Assert(
                            valueSequence.First.Span[0] == (byte)'"',
                            $"Calculated sequence starts with {valueSequence.First.Span[0]}");

                        Debug.Assert(
                            valueSequence.ToArray()[payloadLength - 1] == (byte)'"',
                            $"Calculated sequence ends with {valueSequence.ToArray()[payloadLength - 1]}");
                    }

                    break;
                }

                default:
                {
                    if (shouldThrow)
                    {
                        // Default case would only hit if TokenType equals JsonTokenType.EndObject or JsonTokenType.EndArray in which case it would never be sequence
                        Debug.Assert(!reader.HasValueSequence);
                        byte displayByte = reader.ValueSpan[0];

                        ThrowHelper.ThrowJsonReaderException(
                            ref reader,
                            ExceptionResource.ExpectedStartOfValueNotFound,
                            displayByte);
                    }

                    reader   = restore;
                    document = null;
                    return(false);
                }
                }
            }
            catch
            {
                reader = restore;
                throw;
            }

            int length = valueSpan.IsEmpty ? checked ((int)valueSequence.Length) : valueSpan.Length;

            if (useArrayPools)
            {
                byte[] rented = ArrayPool <byte> .Shared.Rent(length);

                Span <byte> rentedSpan = rented.AsSpan(0, length);

                try
                {
                    if (valueSpan.IsEmpty)
                    {
                        valueSequence.CopyTo(rentedSpan);
                    }
                    else
                    {
                        valueSpan.CopyTo(rentedSpan);
                    }

                    document = Parse(rented.AsMemory(0, length), state.Options, rented);
                }
                catch
                {
                    // This really shouldn't happen since the document was already checked
                    // for consistency by Skip.  But if data mutations happened just after
                    // the calls to Read then the copy may not be valid.
                    rentedSpan.Clear();
                    ArrayPool <byte> .Shared.Return(rented);

                    throw;
                }
            }
            else
            {
                byte[] owned;

                if (valueSpan.IsEmpty)
                {
                    owned = valueSequence.ToArray();
                }
                else
                {
                    owned = valueSpan.ToArray();
                }

                document = ParseUnrented(owned, state.Options, reader.TokenType);
            }

            return(true);
        }
예제 #9
0
        public bool TryEncode(ReadOnlySequence <byte> sequence, out byte[] text, bool includePrefix = false)
        {
            text = Array.Empty <byte>();

            if (sequence.IsEmpty)
            {
                return(true);
            }

            // Skip & count leading zeroes.
            int zeroCount = 0;

            foreach (var segment in sequence)
            {
                fixed(byte *p_segment_fixed = segment.Span)
                {
                    byte *p_segment_start = p_segment_fixed;
                    byte *p_segment_end   = p_segment_fixed + segment.Length;

                    while (p_segment_start != p_segment_end && *p_segment_start == 0)
                    {
                        zeroCount++;
                        p_segment_start++;
                    }
                }
            }

            int length = 0;

            // Allocate enough space in big-endian base58 representation.
            int b58Length = ((int)(sequence.Length - zeroCount) * 138 / 100) + 1; // log(256) / log(58), rounded up.

            using (var b58 = MemoryPool <byte> .Shared.Rent(b58Length))
            {
                BytesOperations.Zero(b58.Memory.Span);

                fixed(byte *p_b58_fixed = b58.Memory.Span)
                {
                    // Process the bytes.
                    foreach (var segment in sequence.Slice(zeroCount))
                    {
                        fixed(byte *p_segment_fixed = segment.Span)
                        {
                            byte *p_segment_start = p_segment_fixed;
                            byte *p_segment_end   = p_segment_fixed + segment.Length;

                            while (p_segment_start != p_segment_end)
                            {
                                int carry = *p_segment_start;
                                int i     = 0;

                                // Apply "b58 = b58 * 256 + ch".
                                byte *p_b58_start = (p_b58_fixed + b58Length) - 1;
                                byte *p_b58_end   = p_b58_fixed - 1;

                                while (p_b58_start != p_b58_end && (carry != 0 || i < length))
                                {
                                    carry += 256 * (*p_b58_start);
                                    *p_b58_start = (byte)(carry % 58);
                                    carry /= 58;

                                    p_b58_start--;
                                    i++;
                                }

                                length = i;
                                p_segment_start++;
                            }
                        }
                    }

                    {
                        byte *p_b58_start = p_b58_fixed + (b58Length - length);
                        byte *p_b58_end   = p_b58_start + length;

                        // Skip leading zeroes in base58 result.
                        while (p_b58_start != p_b58_end && *p_b58_start == 0)
                        {
                            p_b58_start++;
                        }

                        var result = new byte[(includePrefix ? 1 : 0) + zeroCount + (p_b58_end - p_b58_start)];

                        fixed(byte *p_result_fixed = result)
                        {
                            byte *p_result_start = p_result_fixed;

                            if (includePrefix)
                            {
                                *p_result_start++ = (byte)'z';
                            }

                            for (int i = zeroCount - 1; i >= 0; i--)
                            {
                                *p_result_start++ = (byte)'1';
                            }

                            while (p_b58_start != p_b58_end)
                            {
                                *p_result_start++ = (byte)_base58Chars[*p_b58_start++];
                            }
                        }

                        text = result;
                    }
                }
            }

            return(true);
        }
예제 #10
0
        public int Decode(ReadOnlySequence <byte> buffer)
        {
            DecoderHelper.ValidateSize(buffer.Length);

            int bytesConsumed;

            switch (currentState)
            {
            case State.ReadingSize:
                bytesConsumed = sizeDecoder.Decode(buffer);
                if (sizeDecoder.IsValueDecoded)
                {
                    encodedSize = sizeDecoder.Value;
                    if (encodedSize > sizeQuota)
                    {
                        Exception quotaExceeded = OnSizeQuotaExceeded(encodedSize);
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(quotaExceeded);
                    }
                    if (encodedBytes == null || encodedBytes.Length < encodedSize)
                    {
                        encodedBytes = Fx.AllocateByteArray(encodedSize);
                        value        = null;
                    }
                    currentState = State.ReadingBytes;
                    bytesNeeded  = encodedSize;
                }
                break;

            case State.ReadingBytes:
                if (value != null && valueLengthInBytes == encodedSize && bytesNeeded == encodedSize &&
                    buffer.Length >= encodedSize && CompareBuffers(encodedBytes, buffer))
                {
                    bytesConsumed = bytesNeeded;
                    OnComplete(value);
                }
                else
                {
                    bytesConsumed = bytesNeeded;
                    if (buffer.Length < bytesNeeded)
                    {
                        bytesConsumed = (int)buffer.Length;
                    }

                    Span <byte> span        = encodedBytes;
                    Span <byte> slicedBytes = span.Slice(encodedSize - bytesNeeded, bytesConsumed);
                    var         tempBuffer  = buffer.Slice(0, bytesConsumed);
                    tempBuffer.CopyTo(slicedBytes);
                    bytesNeeded -= bytesConsumed;
                    if (bytesNeeded == 0)
                    {
                        value = Encoding.UTF8.GetString(encodedBytes, 0, encodedSize);
                        valueLengthInBytes = encodedSize;
                        OnComplete(value);
                    }
                }
                break;

            default:
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.InvalidDecoderStateMachine));
            }

            return(bytesConsumed);
        }
예제 #11
0
        public (int RequiredBytes, int HeaderLength, int BodyLength) TryRead(ref ReadOnlySequence <byte> input, out Message message)
        {
            if (input.Length < FramingLength)
            {
                message = default;
                return(FramingLength, 0, 0);
            }

            Span <byte> lengthBytes = stackalloc byte[FramingLength];

            input.Slice(input.Start, FramingLength).CopyTo(lengthBytes);
            var headerLength = BinaryPrimitives.ReadInt32LittleEndian(lengthBytes);
            var bodyLength   = BinaryPrimitives.ReadInt32LittleEndian(lengthBytes.Slice(4));

            // Check lengths
            ThrowIfLengthsInvalid(headerLength, bodyLength);

            var requiredBytes = FramingLength + headerLength + bodyLength;

            if (input.Length < requiredBytes)
            {
                message = default;
                return(requiredBytes, 0, 0);
            }

            try
            {
                // Decode header
                var header = input.Slice(FramingLength, headerLength);

                // Decode body
                int bodyOffset = FramingLength + headerLength;
                var body       = input.Slice(bodyOffset, bodyLength);

                // Build message
                message = new();
                if (header.IsSingleSegment)
                {
                    var headersReader = Reader.Create(header.First.Span, _deserializationSession);
                    DeserializeFast(ref headersReader, message);
                }
                else
                {
                    var headersReader = Reader.Create(header, _deserializationSession);
                    DeserializeFast(ref headersReader, message);
                }

                _deserializationSession.PartialReset();

                // Body deserialization is more likely to fail than header deserialization.
                // Separating the two allows for these kinds of errors to be propagated back to the caller.
                if (body.IsSingleSegment)
                {
                    message.BodyObject = _bodySerializer.Deserialize(body.First.Span, _deserializationSession);
                }
                else
                {
                    message.BodyObject = _bodySerializer.Deserialize(body, _deserializationSession);
                }

                return(0, headerLength, bodyLength);
            }
            finally
            {
                input = input.Slice(requiredBytes);
                _deserializationSession.PartialReset();
            }
        }
예제 #12
0
파일: JsonParser.cs 프로젝트: telefrek/core
        /// <summary>
        /// Parse the sequence as Json
        /// </summary>
        /// <param name="stream">The sequence to parse</param>
        /// <returns>A JsonElement that represents the sequence</returns>
        /// <exception cref="Telefrek.Core.Json.InvalidJsonFormatException">If the buffer is not proper Json</exception>
        internal static JsonElement ParseBuffer(ReadOnlySequence <byte> buffer)
        {
            var tree    = new Stack <JsonElement>();
            var current = (JsonElement)null;
            var parent  = (JsonElement)null;
            var isName  = false;

            while (true)
            {
                if (buffer.Length > 0)
                {
                    Trim(ref buffer);
                    switch (buffer.FirstSpan[0])
                    {
                    case START_ARRAY:
                        tree.Push(current);
                        current = new JsonArray();
                        buffer  = buffer.Slice(1);
                        break;

                    case END_ARRAY:
                        parent = tree.Pop();
                        buffer = buffer.Slice(1);
                        if (parent != null)
                        {
                            if (parent.IsJsonArray())
                            {
                                parent.AsJsonArray().Items.Add(current);
                            }
                            else if (parent.IsJsonObject())
                            {
                                parent.AsJsonObject().Properties[parent.AsJsonObject().Properties.Count - 1].Value = current;
                            }

                            current = parent;
                        }
                        break;

                    case START_OBJECT:
                        tree.Push(current);
                        isName  = true;
                        current = new JsonObject();
                        buffer  = buffer.Slice(1);
                        break;

                    case END_OBJECT:
                        parent = tree.Pop();
                        isName = false;
                        buffer = buffer.Slice(1);
                        if (parent != null)
                        {
                            if (parent.IsJsonArray())
                            {
                                parent.AsJsonArray().Items.Add(current);
                            }
                            else if (parent.IsJsonObject())
                            {
                                parent.AsJsonObject().Properties[parent.AsJsonObject().Properties.Count - 1].Value = current;
                                isName = true;
                            }
                            current = parent;
                        }
                        break;

                    case COMMA:
                        // End of one object, properties should add here? child objects in array?
                        buffer = buffer.Slice(1);
                        isName = current != null && current.IsJsonObject();
                        break;

                    case COLON:
                        buffer = buffer.Slice(1);
                        isName = false;
                        break;

                    default:
                        // Check the current state for property reading
                        if (isName && TryReadString(ref buffer, out ReadOnlySequence <byte> name))
                        {
                            // Verify the state
                            if (current == null || !current.IsJsonObject())
                            {
                                throw new InvalidJsonFormatException("Attempted to read property without parent object");
                            }

                            // Create the property
                            var prop = new JsonProperty {
                                Name = Encoding.UTF8.GetString(name.ToArray()), Value = JsonNull.Instance
                            };
                            current.AsJsonObject().Properties.Add(prop);
                            isName = false;
                        }
                        // Try to read a primitive off the buffer
                        else if (TryReadPrimitive(ref buffer, out JsonElement element))
                        {
                            if (current == null)
                            {
                                current = element;
                            }
                            else if (current.IsJsonArray())
                            {
                                current.AsJsonArray().Items.Add(element);
                            }
                            else if (current.IsJsonObject())
                            {
                                var prop = current.AsJsonObject().Properties[current.AsJsonObject().Properties.Count - 1];
                                prop.Value = element;
                            }
                            else
                            {
                                throw new InvalidJsonFormatException("Attempted to add primitive to non object/array");
                            }
                        }
                        // This is an invalid buffer
                        else
                        {
                            throw new InvalidJsonFormatException("Failed to parse the buffer");
                        }
                        break;
                    }
                }
예제 #13
0
        // For multi-segment parsing of a read only sequence
        private void ParseValuesSlow(
            ref ReadOnlySequence <byte> buffer,
            ref KeyValueAccumulator accumulator,
            bool isFinalBlock)
        {
            var sequenceReader  = new SequenceReader <byte>(buffer);
            var consumed        = sequenceReader.Position;
            var equalsDelimiter = GetEqualsForEncoding();
            var andDelimiter    = GetAndForEncoding();

            while (!sequenceReader.End)
            {
                // TODO seems there is a bug with TryReadTo (advancePastDelimiter: true). It isn't advancing past the delimiter on second read.
                if (!sequenceReader.TryReadTo(out ReadOnlySequence <byte> key, equalsDelimiter, advancePastDelimiter: false) ||
                    !sequenceReader.IsNext(equalsDelimiter, true))
                {
                    if (sequenceReader.Consumed > KeyLengthLimit)
                    {
                        ThrowKeyTooLargeException();
                    }

                    break;
                }

                if (key.Length > KeyLengthLimit)
                {
                    ThrowKeyTooLargeException();
                }

                if (!sequenceReader.TryReadTo(out ReadOnlySequence <byte> value, andDelimiter, false) ||
                    !sequenceReader.IsNext(andDelimiter, true))
                {
                    if (!isFinalBlock)
                    {
                        if (sequenceReader.Consumed - key.Length > ValueLengthLimit)
                        {
                            ThrowValueTooLargeException();
                        }
                        break;
                    }

                    value = buffer.Slice(sequenceReader.Position);

                    sequenceReader.Advance(value.Length);
                }

                if (value.Length > ValueLengthLimit)
                {
                    ThrowValueTooLargeException();
                }

                // Need to call ToArray if the key/value spans multiple segments
                var decodedKey   = GetDecodedStringFromReadOnlySequence(key);
                var decodedValue = GetDecodedStringFromReadOnlySequence(value);

                AppendAndVerify(ref accumulator, decodedKey, decodedValue);

                consumed = sequenceReader.Position;
            }

            buffer = buffer.Slice(consumed);
        }
예제 #14
0
        private ValueTask <bool> TryProcessPacketAsync(
            ref ReadOnlySequence <byte> sequence,
            CancellationToken cancellationToken = default)
        {
            var reader = new Utf8JsonReader(sequence);

            VoiceGatewayPayload payload = default;

            if (!Payload.TryReadOpcode(ref reader, out payload.Opcode))
            {
                return(new ValueTask <bool>(false));
            }

            switch (payload.Opcode)
            {
            case VoiceGatewayOpcode.Hello:
            {
                if (!Payload.TryReadHello(ref reader, out payload.Hello))
                {
                    return(new ValueTask <bool>(false));
                }

                break;
            }

            case VoiceGatewayOpcode.Ready:
            {
                if (!Payload.TryReadReady(ref reader, out payload.Ready))
                {
                    return(new ValueTask <bool>(false));
                }

                break;
            }

            case VoiceGatewayOpcode.SessionDescription:
            {
                if (!Payload.TryReadSessionDescription(ref reader,
                                                       _sessionEncryptionKey.Memory.Span.Slice(0,
                                                                                               SessionEncryptionKeyLength)))
                {
                    return(new ValueTask <bool>(false));
                }

                break;
            }

            case VoiceGatewayOpcode.HeartbeatAck:
            {
                if (!Payload.TryReadHeartbeatAck(ref reader,
                                                 out payload.Nonce))
                {
                    return(new ValueTask <bool>(false));
                }

                break;
            }

            case VoiceGatewayOpcode.Speaking:
            {
                return(new ValueTask <bool>(reader.TrySkip()));
            }

            default:
            {
                return(new ValueTask <bool>(reader.TrySkip()));
            }
            }

            if (!reader.TryReadToken(JsonTokenType.EndObject))
            {
                return(new ValueTask <bool>(false));
            }

            sequence = sequence.Slice(reader.Position);

            return(TryProcessOpcodeAsync(ref payload, cancellationToken));
        }
예제 #15
0
        // For multi-segment parsing of a read only sequence
        private void ParseValuesSlow(
            ref ReadOnlySequence <byte> buffer,
            ref KeyValueAccumulator accumulator,
            bool isFinalBlock)
        {
            var sequenceReader = new SequenceReader <byte>(buffer);
            ReadOnlySequence <byte> keyValuePair;

            var consumed        = sequenceReader.Position;
            var consumedBytes   = default(long);
            var equalsDelimiter = GetEqualsForEncoding();
            var andDelimiter    = GetAndForEncoding();

            while (!sequenceReader.End)
            {
                if (!sequenceReader.TryReadTo(out keyValuePair, andDelimiter))
                {
                    if (!isFinalBlock)
                    {
                        // Don't buffer indefinitely
                        if ((uint)(sequenceReader.Consumed - consumedBytes) > (uint)KeyLengthLimit + (uint)ValueLengthLimit)
                        {
                            ThrowKeyOrValueTooLargeException();
                        }
                        break;
                    }

                    // This must be the final key=value pair
                    keyValuePair = buffer.Slice(sequenceReader.Position);
                    sequenceReader.Advance(keyValuePair.Length);
                }

                if (keyValuePair.IsSingleSegment)
                {
                    ParseFormValuesFast(keyValuePair.FirstSpan, ref accumulator, isFinalBlock: true, out var segmentConsumed);
                    Debug.Assert(segmentConsumed == keyValuePair.FirstSpan.Length);
                    consumedBytes = sequenceReader.Consumed;
                    consumed      = sequenceReader.Position;
                    continue;
                }

                var keyValueReader = new SequenceReader <byte>(keyValuePair);
                ReadOnlySequence <byte> value;

                if (keyValueReader.TryReadTo(out var key, equalsDelimiter))
                {
                    if (key.Length > KeyLengthLimit)
                    {
                        ThrowKeyTooLargeException();
                    }

                    value = keyValuePair.Slice(keyValueReader.Position);
                    if (value.Length > ValueLengthLimit)
                    {
                        ThrowValueTooLargeException();
                    }
                }
                else
                {
                    // Too long for the whole segment to be a key.
                    if (keyValuePair.Length > KeyLengthLimit)
                    {
                        ThrowKeyTooLargeException();
                    }

                    // There is no more data, this segment must be "key" with no equals or value.
                    key   = keyValuePair;
                    value = default;
                }

                var decodedKey   = GetDecodedStringFromReadOnlySequence(key);
                var decodedValue = GetDecodedStringFromReadOnlySequence(value);

                AppendAndVerify(ref accumulator, decodedKey, decodedValue);

                consumedBytes = sequenceReader.Consumed;
                consumed      = sequenceReader.Position;
            }

            buffer = buffer.Slice(consumed);
        }
예제 #16
0
 protected override int ParseBodySizeFromHeader(ref ReadOnlySequence<byte> buffer)
 {
     return BitConverter.ToInt32(buffer.Slice(0, 4).FirstSpan);
 }
        public static bool TryParseMessage(ref ReadOnlySequence <byte> buffer, out ReadOnlySequence <byte> payload)
        {
            if (buffer.IsEmpty)
            {
                payload = default;
                return(false);
            }

            // 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 0x07 - hence the maximum length prefix is 5 bytes.

            var length   = 0U;
            var numBytes = 0;

            var lengthPrefixBuffer = buffer.Slice(0, Math.Min(MaxLengthPrefixSize, buffer.Length));
            var span = GetSpan(lengthPrefixBuffer);

            byte byteRead;

            do
            {
                byteRead = span[numBytes];
                length   = length | (((uint)(byteRead & 0x7f)) << (numBytes * 7));
                numBytes++;
            }while (numBytes < lengthPrefixBuffer.Length && ((byteRead & 0x80) != 0));

            // size bytes are missing
            if ((byteRead & 0x80) != 0 && (numBytes < MaxLengthPrefixSize))
            {
                payload = default;
                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 < length + numBytes)
            {
                payload = default;
                return(false);
            }

            // Get the payload
            payload = buffer.Slice(numBytes, (int)length);

            // Skip the payload
            buffer = buffer.Slice(numBytes + (int)length);
            return(true);
        }
 /// <summary>
 /// Gets the packet header from the current packet.
 /// </summary>
 public int GetHeader(ReadOnlySequence <byte> buffer) => RecvCipher
 .Handshaken
     ? 4 + MapleCipher.GetPacketLength(buffer.Slice(0, 4).ToSpan())
     : 2 + BitConverter.ToUInt16(buffer.Slice(0, 2).ToSpan());
예제 #19
0
 protected override TextPackageInfo DecodePackage(ReadOnlySequence <byte> buffer)
 {
     return(new TextPackageInfo {
         Text = buffer.Slice(4).GetString(Encoding.UTF8)
     });
 }
예제 #20
0
파일: KcpIO.cs 프로젝트: coding2233/KCP
        public int Send(ReadOnlySequence <byte> span, object option = null)
        {
            if (CheckDispose())
            {
                //检查释放
                return(-4);
            }

            if (mss <= 0)
            {
                throw new InvalidOperationException($" mss <= 0 ");
            }


            if (span.Length == 0)
            {
                return(-1);
            }
            var offset = 0;
            int count;

            #region append to previous segment in streaming mode (if possible)
            /// 基于线程安全和数据结构的等原因,移除了追加数据到最后一个包行为。
            #endregion

            #region fragment

            if (span.Length <= mss)
            {
                count = 1;
            }
            else
            {
                count = (int)(span.Length + mss - 1) / (int)mss;
            }

            if (count > IKCP_WND_RCV)
            {
                return(-2);
            }

            if (count == 0)
            {
                count = 1;
            }

            for (var i = 0; i < count; i++)
            {
                int size;
                if (span.Length - offset > mss)
                {
                    size = (int)mss;
                }
                else
                {
                    size = (int)span.Length - offset;
                }

                var seg = SegmentManager.Alloc(size);
                span.Slice(offset, size).CopyTo(seg.data);
                offset += size;
                seg.frg = (byte)(count - i - 1);
                snd_queue.Enqueue(seg);
            }

            #endregion

            return(0);
        }
        private static void ReadValueCore(JsonSerializerOptions options, ref Utf8JsonReader reader, ref ReadStack readStack)
        {
            JsonReaderState state = reader.CurrentState;

            CheckSupportedOptions(state.Options, nameof(reader));

            // Value copy to overwrite the ref on an exception and undo the destructive reads.
            Utf8JsonReader restore = reader;

            ReadOnlySpan <byte>     valueSpan     = default;
            ReadOnlySequence <byte> valueSequence = default;

            try
            {
                switch (reader.TokenType)
                {
                // A new reader was created and has never been read,
                // so we need to move to the first token.
                // (or a reader has terminated and we're about to throw)
                case JsonTokenType.None:
                // Using a reader loop the caller has identified a property they wish to
                // hydrate into a JsonDocument. Move to the value first.
                case JsonTokenType.PropertyName:
                {
                    if (!reader.Read())
                    {
                        ThrowHelper.ThrowJsonReaderException(ref reader, ExceptionResource.ExpectedOneCompleteToken);
                    }
                    break;
                }
                }

                switch (reader.TokenType)
                {
                // Any of the "value start" states are acceptable.
                case JsonTokenType.StartObject:
                case JsonTokenType.StartArray:
                {
                    long startingOffset = reader.TokenStartIndex;

                    if (!reader.TrySkip())
                    {
                        ThrowHelper.ThrowJsonReaderException(ref reader, ExceptionResource.NotEnoughData);
                    }

                    long totalLength = reader.BytesConsumed - startingOffset;
                    ReadOnlySequence <byte> sequence = reader.OriginalSequence;

                    if (sequence.IsEmpty)
                    {
                        valueSpan = reader.OriginalSpan.Slice(
                            checked ((int)startingOffset),
                            checked ((int)totalLength));
                    }
                    else
                    {
                        valueSequence = sequence.Slice(startingOffset, totalLength);
                    }

                    Debug.Assert(
                        reader.TokenType == JsonTokenType.EndObject ||
                        reader.TokenType == JsonTokenType.EndArray);

                    break;
                }

                // Single-token values
                case JsonTokenType.Number:
                case JsonTokenType.True:
                case JsonTokenType.False:
                case JsonTokenType.Null:
                {
                    if (reader.HasValueSequence)
                    {
                        valueSequence = reader.ValueSequence;
                    }
                    else
                    {
                        valueSpan = reader.ValueSpan;
                    }

                    break;
                }

                // String's ValueSequence/ValueSpan omits the quotes, we need them back.
                case JsonTokenType.String:
                {
                    ReadOnlySequence <byte> sequence = reader.OriginalSequence;

                    if (sequence.IsEmpty)
                    {
                        // Since the quoted string fit in a ReadOnlySpan originally
                        // the contents length plus the two quotes can't overflow.
                        int payloadLength = reader.ValueSpan.Length + 2;
                        Debug.Assert(payloadLength > 1);

                        ReadOnlySpan <byte> readerSpan = reader.OriginalSpan;

                        Debug.Assert(
                            readerSpan[(int)reader.TokenStartIndex] == (byte)'"',
                            $"Calculated span starts with {readerSpan[(int)reader.TokenStartIndex]}");

                        Debug.Assert(
                            readerSpan[(int)reader.TokenStartIndex + payloadLength - 1] == (byte)'"',
                            $"Calculated span ends with {readerSpan[(int)reader.TokenStartIndex + payloadLength - 1]}");

                        valueSpan = readerSpan.Slice((int)reader.TokenStartIndex, payloadLength);
                    }
                    else
                    {
                        long payloadLength = 2;

                        if (reader.HasValueSequence)
                        {
                            payloadLength += reader.ValueSequence.Length;
                        }
                        else
                        {
                            payloadLength += reader.ValueSpan.Length;
                        }

                        valueSequence = sequence.Slice(reader.TokenStartIndex, payloadLength);
                        Debug.Assert(
                            valueSequence.First.Span[0] == (byte)'"',
                            $"Calculated sequence starts with {valueSequence.First.Span[0]}");

                        Debug.Assert(
                            valueSequence.ToArray()[payloadLength - 1] == (byte)'"',
                            $"Calculated sequence ends with {valueSequence.ToArray()[payloadLength - 1]}");
                    }

                    break;
                }

                default:
                {
                    byte displayByte;

                    if (reader.HasValueSequence)
                    {
                        displayByte = reader.ValueSequence.First.Span[0];
                    }
                    else
                    {
                        displayByte = reader.ValueSpan[0];
                    }

                    ThrowHelper.ThrowJsonReaderException(
                        ref reader,
                        ExceptionResource.ExpectedStartOfValueNotFound,
                        displayByte);

                    break;
                }
                }
            }
            catch (JsonReaderException ex)
            {
                reader = restore;
                // Re-throw with Path information.
                ThrowHelper.ReThrowWithPath(readStack, ex);
            }

            int length = valueSpan.IsEmpty ? checked ((int)valueSequence.Length) : valueSpan.Length;

            byte[] rented = ArrayPool <byte> .Shared.Rent(length);

            Span <byte> rentedSpan = rented.AsSpan(0, length);

            try
            {
                if (valueSpan.IsEmpty)
                {
                    valueSequence.CopyTo(rentedSpan);
                }
                else
                {
                    valueSpan.CopyTo(rentedSpan);
                }

                JsonReaderOptions originalReaderOptions = state.Options;

                var newReader = new Utf8JsonReader(rentedSpan, originalReaderOptions);

                ReadCore(options, ref newReader, ref readStack);

                // The reader should have thrown if we have remaining bytes.
                Debug.Assert(newReader.BytesConsumed == length);
            }
            catch (JsonException)
            {
                reader = restore;
                throw;
            }
            finally
            {
                rentedSpan.Clear();
                ArrayPool <byte> .Shared.Return(rented);
            }
        }
예제 #22
0
 private TResult Read <TResult, TParser>(TParser parser)
     where TParser : struct, IBufferReader <TResult>
 {
     parser.Append <TResult, TParser>(sequence.Slice(position), out position);
     return(parser.RemainingBytes == 0 ? parser.Complete() : throw new EndOfStreamException());
 }
 private static bool HasValidChecksum(ReadOnlySequence <byte> input)
 => input.ReadUInt32(Constants.MagicNumber.Length, true) == Crc32C.Calculate(input.Slice(Constants.MetadataSizeOffset));
예제 #24
0
        public OnlinePackageInfo Decode(ref ReadOnlySequence <byte> buffer, object context)
        {
            if (buffer.Length < HEADER_LENGTH)
            {
                throw new Exception($"proto error:head lenth less than { HEADER_LENGTH }");
            }

            try
            {
                var reader = new SequenceReader <byte>(buffer);

                var packgae = new OnlinePackageInfo();
                reader.Advance(1);

                if (reader.TryReadBigEndian(out short key))
                {
                    packgae.Key = key;
                }

                reader.Advance(1);

                if (reader.TryRead(out byte version))
                {
                    packgae.Version = version;
                }

                packgae.RequestID = new Guid(reader.CurrentSpan.Slice(6, 16));
                reader.Advance(16);

                if (reader.TryReadLittleEndian(out int crcCode))
                {
                    packgae.CrcCode = crcCode;
                }

                if (reader.TryReadLittleEndian(out int bodyLength))
                {
                    packgae.BodyLength = bodyLength;
                }

                if (buffer.Length != packgae.BodyLength + HEADER_LENGTH)
                {
                    throw new Exception($"Package error:length{ packgae.BodyLength },active length{ buffer.Length - HEADER_LENGTH } ");
                }

                if (packgae.BodyLength > 0)
                {
                    if (OnlinePackageDecoderFactory.GetFactory(packgae.Key, out IDecoderFactory onlinePackageFactory))
                    {
                        var sclie = buffer.Slice(HEADER_LENGTH, packgae.BodyLength);
                        packgae.Object = onlinePackageFactory.Create(ref sclie);
                    }
                    else
                    {
                        _logger.LogError("Not find the command");
                    }
                }

                return(packgae);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return(default);
        protected bool Read(ReadOnlySequence <byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
        {
            consumed = default;
            examined = default;

            while (_mode < Mode.Trailer)
            {
                if (_mode == Mode.Prefix)
                {
                    ParseChunkedPrefix(readableBuffer, out consumed, out examined);

                    if (_mode == Mode.Prefix)
                    {
                        return(false);
                    }

                    readableBuffer = readableBuffer.Slice(consumed);
                }

                if (_mode == Mode.Extension)
                {
                    ParseExtension(readableBuffer, out consumed, out examined);

                    if (_mode == Mode.Extension)
                    {
                        return(false);
                    }

                    readableBuffer = readableBuffer.Slice(consumed);
                }

                if (_mode == Mode.Data)
                {
                    ReadChunkedData(readableBuffer, writableBuffer, out consumed, out examined);

                    if (_mode == Mode.Data)
                    {
                        return(false);
                    }

                    readableBuffer = readableBuffer.Slice(consumed);
                }

                if (_mode == Mode.Suffix)
                {
                    ParseChunkedSuffix(readableBuffer, out consumed, out examined);

                    if (_mode == Mode.Suffix)
                    {
                        return(false);
                    }

                    readableBuffer = readableBuffer.Slice(consumed);
                }
            }

            // Chunks finished, parse trailers
            if (_mode == Mode.Trailer)
            {
                ParseChunkedTrailer(readableBuffer, out consumed, out examined);

                if (_mode == Mode.Trailer)
                {
                    return(false);
                }

                readableBuffer = readableBuffer.Slice(consumed);
            }

            // _consumedBytes aren't tracked for trailer headers, since headers have separate limits.
            if (_mode == Mode.TrailerHeaders)
            {
                if (_context.TakeMessageHeaders(readableBuffer, out consumed, out examined))
                {
                    _mode = Mode.Complete;
                }
            }

            return(_mode == Mode.Complete);
        }
예제 #26
0
            private static (int keySize, int keyCount, int bytesRead)? TryReadHeader(ReadOnlySequence <byte> sequence)
            {
                Span <ulong> headerValues = stackalloc ulong[3];
                var          headerBytes  = MemoryMarshal.AsBytes(headerValues);

                if (sequence.Length < headerBytes.Length)
                {
                    return(null);
                }

                sequence.Slice(0, headerBytes.Length).CopyTo(headerBytes);

                // https://github.com/ClickHouse/ClickHouse/blob/master/src/DataTypes/DataTypeLowCardinality.cpp
                // Dictionary is written as number N and N keys after them.
                // Dictionary can be shared for continuous range of granules, so some marks may point to the same position.
                // Shared dictionary is stored in state and is read once.
                //
                // SharedDictionariesWithAdditionalKeys = 1,

                if (headerValues[0] != 1)
                {
                    throw new ClickHouseException(ClickHouseErrorCodes.DataReaderError, $"Internal error. Unexpected dictionary version: {headerBytes[0]}.");
                }

                var keySizeCode = unchecked ((byte)headerValues[1]);
                int keySize;

                switch (keySizeCode)
                {
                case 0:
                    keySize = 1;
                    break;

                case 1:
                    keySize = 2;
                    break;

                case 3:
                    keySize = 4;
                    break;

                case 4:
                    throw new NotSupportedException("64-bit keys are not supported.");

                default:
                    throw new ClickHouseException(ClickHouseErrorCodes.DataReaderError, $"Internal error. Unexpected size of a key: {keySizeCode}.");
                }

                // There are several control flags, but the client always receives 0x2|0x4
                //
                // https://github.com/ClickHouse/ClickHouse/blob/master/src/DataTypes/DataTypeLowCardinality.cpp
                // 0x1 Need to read dictionary if it wasn't.
                // 0x2 Need to read additional keys. Additional keys are stored before indexes as value N and N keys after them.
                // 0x4 Need to update dictionary. It means that previous granule has different dictionary.

                var flags = headerValues[1] >> 8;

                if (flags != (0x2 | 0x4))
                {
                    throw new NotSupportedException("Received combination of flags is not supported.");
                }

                var keyCount = (int)headerValues[2];

                return(keySize, keyCount, headerBytes.Length);
            }