public async Task AdvanceWithGetPositionCrossingIntoWriteHeadWorks() { // Create two blocks Memory <byte> memory = _pipe.Writer.GetMemory(1); _pipe.Writer.Advance(memory.Length); memory = _pipe.Writer.GetMemory(1); _pipe.Writer.Advance(memory.Length); await _pipe.Writer.FlushAsync(); // Read single block ReadResult readResult = await _pipe.Reader.ReadAsync(); // Allocate more memory memory = _pipe.Writer.GetMemory(1); // Create position that would cross into write head ReadOnlyBuffer <byte> buffer = readResult.Buffer; SequencePosition position = buffer.GetPosition(buffer.Start, buffer.Length); // Return everything _pipe.Reader.AdvanceTo(position); // Advance writer _pipe.Writer.Advance(memory.Length); _pipe.Writer.Commit(); }
private bool ParsePreface(ReadOnlyBuffer<byte> readableBuffer, out SequencePosition consumed, out SequencePosition examined) { consumed = readableBuffer.Start; examined = readableBuffer.End; if (readableBuffer.Length < ClientPreface.Length) { return false; } var span = readableBuffer.IsSingleSegment ? readableBuffer.First.Span : readableBuffer.ToSpan(); for (var i = 0; i < ClientPreface.Length; i++) { if (ClientPreface[i] != span[i]) { throw new Exception("Invalid HTTP/2 connection preface."); } } consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, ClientPreface.Length); return true; }
public void TestSeekIteratorLimitWithinSameBlock(string input, char seek, char limitAfter, int expectedReturnValue) { ReadOnlyBuffer <byte> originalBuffer = Factory.CreateWithContent(input); SequencePosition scan1 = originalBuffer.Start; ReadOnlyBuffer <byte> buffer = originalBuffer; // Act SequencePosition?end = originalBuffer.PositionOf((byte)limitAfter); if (end.HasValue) { buffer = originalBuffer.Slice(buffer.Start, buffer.GetPosition(end.Value, 1)); } SequencePosition?returnValue1 = buffer.PositionOf((byte)seek); // Assert Assert.Equal(input.Contains(limitAfter), end.HasValue); if (expectedReturnValue != -1) { int expectedEndIndex = input.IndexOf(seek); Assert.NotNull(returnValue1); Assert.Equal(Encoding.ASCII.GetBytes(input.Substring(expectedEndIndex)), originalBuffer.Slice(returnValue1.Value).ToArray()); } }
public void SegmentStartIsConsideredInBoundsCheck() { // 0 50 100 0 50 100 // [ ##############] -> [############## ] // ^c1 ^c2 var bufferSegment1 = new BufferSegment(); bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 50, 99); var bufferSegment2 = new BufferSegment(); bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 50); bufferSegment1.SetNext(bufferSegment2); var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 50); var c1 = readableBuffer.GetPosition(readableBuffer.Start, 25); // segment 1 index 75 var c2 = readableBuffer.GetPosition(readableBuffer.Start, 55); // segment 2 index 5 var sliced = readableBuffer.Slice(c1, c2); Assert.Equal(30, sliced.Length); }
public static SequencePosition?PositionOf <T>(this ReadOnlyBuffer <T> buffer, T value) where T : IEquatable <T> { SequencePosition position = buffer.Start; SequencePosition result = position; while (buffer.TryGet(ref position, out var memory)) { var index = memory.Span.IndexOf(value); if (index != -1) { return(buffer.GetPosition(result, index)); } result = position; } return(null); }
private void ReadChunkedData(ReadOnlyBuffer <byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { var actual = Math.Min(buffer.Length, _inputLength); consumed = buffer.GetPosition(buffer.Start, actual); examined = consumed; Copy(buffer.Slice(0, actual), writableBuffer); _inputLength -= actual; AddAndCheckConsumedBytes(actual); if (_inputLength == 0) { _mode = Mode.Suffix; } }
protected override bool Read(ReadOnlyBuffer <byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { if (_inputLength == 0) { throw new InvalidOperationException("Attempted to read from completed Content-Length request body."); } var actual = (int)Math.Min(readableBuffer.Length, _inputLength); _inputLength -= actual; consumed = readableBuffer.GetPosition(readableBuffer.Start, actual); examined = consumed; Copy(readableBuffer.Slice(0, actual), writableBuffer); return(_inputLength == 0); }
public void MovePrefersNextSegment() { var bufferSegment1 = new BufferSegment(); bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 49, 99); var bufferSegment2 = new BufferSegment(); bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 0); bufferSegment1.SetNext(bufferSegment2); var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 0); var c1 = readableBuffer.GetPosition(readableBuffer.Start, 50); Assert.Equal(0, c1.Index); Assert.Equal(bufferSegment2, c1.Segment); }
public void ParseHeadersConsumesBytesCorrectlyAtEnd() { var parser = CreateParser(Mock.Of <IKestrelTrace>()); const string headerLine = "Header: value\r\n\r"; var buffer1 = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(headerLine)); var requestHandler = new RequestHandler(); Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes)); Assert.Equal(buffer1.GetPosition(buffer1.Start, headerLine.Length - 1), consumed); Assert.Equal(buffer1.End, examined); Assert.Equal(headerLine.Length - 1, consumedBytes); var buffer2 = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes("\r\n")); Assert.True(parser.ParseHeaders(requestHandler, buffer2, out consumed, out examined, out consumedBytes)); Assert.True(buffer2.Slice(consumed).IsEmpty); Assert.True(buffer2.Slice(examined).IsEmpty); Assert.Equal(2, consumedBytes); }
public static bool TryParseMessage(ReadOnlyBuffer <byte> buffer, out NegotiationMessage negotiationMessage, out SequencePosition consumed, out SequencePosition examined) { var separator = buffer.PositionOf(TextMessageFormatter.RecordSeparator); if (separator == null) { // Haven't seen the entire negotiate message so bail consumed = buffer.Start; examined = buffer.End; negotiationMessage = null; return(false); } else { consumed = buffer.GetPosition(separator.Value, 1); examined = consumed; } var memory = buffer.IsSingleSegment ? buffer.First : buffer.ToArray(); return(TryParseMessage(memory.Span, out negotiationMessage)); }
public unsafe bool ParseRequestLine(TRequestHandler handler, ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.End; // Prepare the first span var span = buffer.First.Span; var lineIndex = span.IndexOf(ByteLF); if (lineIndex >= 0) { consumed = buffer.GetPosition(consumed, lineIndex + 1); span = span.Slice(0, lineIndex + 1); } else if (buffer.IsSingleSegment) { // No request line end return(false); } else if (TryGetNewLine(ref buffer, out var found)) { span = buffer.Slice(consumed, found).ToSpan(); consumed = found; }
public void GetPositionDoesNotCrossOutsideBuffer() { var bufferSegment1 = new BufferSegment(); bufferSegment1.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 100); var bufferSegment2 = new BufferSegment(); bufferSegment2.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 100); var bufferSegment3 = new BufferSegment(); bufferSegment3.SetMemory(new OwnedArray <byte>(new byte[100]), 0, 0); bufferSegment1.SetNext(bufferSegment2); bufferSegment2.SetNext(bufferSegment3); var readableBuffer = new ReadOnlyBuffer <byte>(bufferSegment1, 0, bufferSegment2, 100); var c1 = readableBuffer.GetPosition(readableBuffer.Start, 200); Assert.Equal(100, c1.Index); Assert.Equal(bufferSegment2, c1.Segment); }
public static bool ReadFrame(ReadOnlyBuffer <byte> readableBuffer, Http2Frame frame, out SequencePosition consumed, out SequencePosition examined) { consumed = readableBuffer.Start; examined = readableBuffer.End; if (readableBuffer.Length < Http2Frame.HeaderLength) { return(false); } var headerSlice = readableBuffer.Slice(0, Http2Frame.HeaderLength); headerSlice.CopyTo(frame.Raw); if (readableBuffer.Length < Http2Frame.HeaderLength + frame.Length) { return(false); } readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload); consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length); return(true); }
/// <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 ReadOnlyBuffer <byte> buffer, byte b1, out ReadOnlyBuffer <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 = ReadMachineEndian <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(buffer.Start, seek); slice = buffer.Slice(buffer.Start, cursor); return(true); } } slice = default; cursor = default; return(false); }
public Position GetPosition(Position origin, long offset) => _buffer.GetPosition(origin, offset);
public ParseResult ParseMessage(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined, out byte[] message) { consumed = buffer.Start; examined = buffer.End; message = null; var start = consumed; var end = examined; while (buffer.Length > 0) { if (!(buffer.PositionOf(ByteLF) is SequencePosition lineEnd)) { // For the case of data: Foo\r\n\r\<Anytine 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(lineEnd, 1); 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); }
public SequencePosition GetPosition(SequencePosition origin, long offset) => _buffer.GetPosition(origin, offset);