public void ParsesRequestLine( string requestLine, string expectedMethod, string expectedRawTarget, string expectedRawPath, // This warns that theory methods should use all of their parameters, // but this method is using a shared data collection with Http1ConnectionTests.TakeStartLineSetsHttpProtocolProperties and others. #pragma warning disable xUnit1026 string expectedDecodedPath, string expectedQueryString, #pragma warning restore xUnit1026 string expectedVersion) { var parser = CreateParser(Mock.Of <IKestrelTrace>()); var buffer = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); Assert.True(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); Assert.Equal(requestHandler.Method, expectedMethod); Assert.Equal(requestHandler.Version, expectedVersion); Assert.Equal(requestHandler.RawTarget, expectedRawTarget); Assert.Equal(requestHandler.RawPath, expectedRawPath); Assert.Equal(requestHandler.Version, expectedVersion); Assert.True(buffer.Slice(consumed).IsEmpty); Assert.True(buffer.Slice(examined).IsEmpty); }
/// <summary> /// Searches for a span of bytes in the <see cref="ReadOnlyBuffer"/> and returns a sliced <see cref="ReadOnlyBuffer"/> that /// contains all data up to and excluding the first byte of the span, and a <see cref="SequencePosition"/> that points to the last byte of the span. /// </summary> /// <param name="span">The <see cref="Span{Byte}"/> byte to search for</param> /// <param name="slice">A <see cref="ReadOnlyBuffer"/> that matches 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, Span <byte> span, out ReadOnlyBuffer <byte> slice, out SequencePosition cursor) { var result = false; var subBuffer = buffer; do { // Find the first byte if (!subBuffer.TrySliceTo(span[0], out slice, out cursor)) { break; } // Move the buffer to where you fonud the first byte then search for the next byte subBuffer = buffer.Slice(cursor); if (subBuffer.StartsWith(span)) { slice = buffer.Slice(buffer.Start, cursor); result = true; break; } // REVIEW: We need to check the performance of Slice in a loop like this // Not a match so skip(1) subBuffer = subBuffer.Slice(1); } while (!subBuffer.IsEmpty); return(result); }
static bool FullRequest() { ReadOnlyBuffer <byte> buffer = new ReadOnlyBuffer <byte>(s_plaintextTechEmpowerRequestBytes); var parser = new HttpParser(); var request = new Request(); int consumedBytes = 0; Position examined; Position consumed = buffer.Start; bool success = true; foreach (var iteration in Benchmark.Iterations) { using (iteration.StartMeasurement()) { for (int i = 0; i < Benchmark.InnerIterationCount; i++) { success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); } } } return(success); }
public static bool TryParseMessage(ref ReadOnlyBuffer <byte> buffer, out ReadOnlyBuffer <byte> payload) { long length = 0; payload = default(ReadOnlyBuffer <byte>); if (buffer.Length < sizeof(long)) { return(false); } // Read the length length = buffer.Span.Slice(0, sizeof(long)).ReadBigEndian <long>(); if (length > Int32.MaxValue) { throw new FormatException("Messages over 2GB in size are not supported"); } // We don't have enough data if (buffer.Length < (int)length + sizeof(long)) { return(false); } // Get the payload payload = buffer.Slice(sizeof(long), (int)length); // Skip the payload buffer = buffer.Slice((int)length + sizeof(long)); return(true); }
protected virtual void ProcessRequest(TcpConnection socket) { Log.LogVerbose("Processing Request"); using (BufferSequence rootBuffer = new BufferSequence(RequestBufferSize)) { BufferSequence requestBuffer = rootBuffer; int totalWritten = 0; while (true) { Span <byte> requestSpan = requestBuffer.Free; int requestBytesRead = socket.Receive(requestSpan); if (requestBytesRead == 0) { socket.Close(); return; } requestBuffer.Advance(requestBytesRead); totalWritten += requestBytesRead; if (requestBytesRead == requestSpan.Length) { requestBuffer = requestBuffer.Append(RequestBufferSize); } else { break; } } var requestBytes = new ReadOnlyBuffer <byte>(rootBuffer, 0, requestBuffer, requestBuffer.Memory.Length); var request = new HttpRequest(); if (!s_parser.ParseRequestLine(ref request, requestBytes, out int consumed)) { throw new Exception(); } requestBytes = requestBytes.Slice(consumed); if (!s_parser.ParseHeaders(ref request, requestBytes, out consumed)) { throw new Exception(); } var requestBody = requestBytes.Slice(consumed); Log.LogRequest(request, requestBody); using (var response = new TcpConnectionFormatter(socket, ResponseBufferSize)) { WriteResponse(ref request, requestBody, response); } socket.Close(); } if (Log.IsVerbose) { Log.LogMessage(Log.Level.Verbose, "Request Processed and Response Sent", DateTime.UtcNow.Ticks); } }
public static bool TryParseMessage(ref ReadOnlyBuffer <byte> buffer, out ReadOnlyBuffer <byte> payload) { payload = default; if (buffer.IsEmpty) { 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.Span.Slice(0, Math.Min(MaxLengthPrefixSize, buffer.Length)); byte byteRead; do { byteRead = lengthPrefixBuffer[numBytes]; length = length | (((uint)(byteRead & 0x7f)) << _numBitsToShift[numBytes]); numBytes++; }while (numBytes < lengthPrefixBuffer.Length && ((byteRead & 0x80) != 0)); // size bytes are missing if ((byteRead & 0x80) != 0 && (numBytes < MaxLengthPrefixSize)) { return(false); } if ((byteRead & 0x80) != 0 || (numBytes == MaxLengthPrefixSize && byteRead > 7)) { throw new FormatException("Messages over 2GB in size are not supported."); } // We don't have enough data if (buffer.Length < length + numBytes) { return(false); } // Get the payload payload = buffer.Slice(numBytes, (int)length); // Skip the payload buffer = buffer.Slice(numBytes + (int)length); return(true); }
public async Task ReaderShouldNotGetUnflushedBytesWithAppend() { // Write 10 and flush PipeWriter buffer = _pipe.Writer; buffer.Write(new byte[] { 0, 0, 0, 10 }); await buffer.FlushAsync(); // Write Hello to another pipeline and get the buffer byte[] bytes = Encoding.ASCII.GetBytes("Hello"); var c2 = new Pipe(new PipeOptions(_pool)); await c2.Writer.WriteAsync(bytes); ReadResult result = await c2.Reader.ReadAsync(); ReadOnlyBuffer <byte> c2Buffer = result.Buffer; Assert.Equal(bytes.Length, c2Buffer.Length); // Write 9 to the buffer buffer = _pipe.Writer; buffer.Write(new byte[] { 0, 0, 0, 9 }); // Append the data from the other pipeline foreach (ReadOnlyMemory <byte> memory in c2Buffer) { buffer.Write(memory.Span); } // Mark it as consumed c2.Reader.AdvanceTo(c2Buffer.End); // Now read and make sure we only see the comitted data result = await _pipe.Reader.ReadAsync(); ReadOnlyBuffer <byte> reader = result.Buffer; Assert.Equal(4, reader.Length); Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray()); // Consume nothing _pipe.Reader.AdvanceTo(reader.Start); // Flush the second set of writes await buffer.FlushAsync(); reader = (await _pipe.Reader.ReadAsync()).Buffer; // int, int, "Hello" Assert.Equal(13, reader.Length); Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray()); Assert.Equal(new byte[] { 0, 0, 0, 9 }, reader.Slice(4, 4).ToArray()); Assert.Equal("Hello", Encoding.ASCII.GetString(reader.Slice(8).ToArray())); _pipe.Reader.AdvanceTo(reader.Start, reader.Start); }
public void SequencePositionOfMultiSegment() { var(first, last) = BufferList.Create( new byte[] { 1, 2 }, new byte[] { 3, 4 } ); var bytes = new ReadOnlyBuffer <byte>(first, 0, last, last.Memory.Length); Assert.Equal(4, bytes.Length); // Static method call to avoid calling instance methods Assert.False(Sequence.PositionOf(bytes, 0).HasValue); for (int i = 0; i < bytes.Length; i++) { var value = (byte)(i + 1); var listPosition = MemoryListExtensions.PositionOf(first, value).GetValueOrDefault(); var(node, index) = listPosition.Get <IMemoryList <byte> >(); if (listPosition != default) { Assert.Equal(value, node.Memory.Span[index]); } var robPosition = ReadOnlyBufferExtensions.PositionOf(bytes, value); var robSequencePosition = Sequence.PositionOf(bytes, value); Assert.Equal(listPosition, robPosition); Assert.Equal(listPosition, robSequencePosition); var robSlice = bytes.Slice(1); robPosition = ReadOnlyBufferExtensions.PositionOf(robSlice, value); robSequencePosition = Sequence.PositionOf(robSlice, value); if (i > 0) { Assert.Equal(listPosition, robPosition); Assert.Equal(listPosition, robSequencePosition); } else { Assert.False(robPosition.HasValue); Assert.False(robSequencePosition.HasValue); } if (listPosition != default) { robSlice = bytes.Slice(listPosition); Assert.Equal(value, robSlice.First.Span[0]); } } }
private void ParseExtension(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { // Chunk-extensions not currently parsed // Just drain the data consumed = buffer.Start; examined = buffer.Start; do { SequencePosition?extensionCursorPosition = buffer.PositionOf(ByteCR); if (extensionCursorPosition == null) { // End marker not found yet consumed = buffer.End; examined = buffer.End; AddAndCheckConsumedBytes(buffer.Length); return; } ; var extensionCursor = extensionCursorPosition.Value; var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length; var sufixBuffer = buffer.Slice(extensionCursor); if (sufixBuffer.Length < 2) { consumed = extensionCursor; examined = buffer.End; AddAndCheckConsumedBytes(charsToByteCRExclusive); return; } sufixBuffer = sufixBuffer.Slice(0, 2); var sufixSpan = sufixBuffer.ToSpan(); if (sufixSpan[1] == '\n') { // We consumed the \r\n at the end of the extension, so switch modes. _mode = _inputLength > 0 ? Mode.Data : Mode.Trailer; consumed = sufixBuffer.End; examined = sufixBuffer.End; AddAndCheckConsumedBytes(charsToByteCRExclusive + 2); } else { // Don't consume suffixSpan[1] in case it is also a \r. buffer = buffer.Slice(charsToByteCRExclusive + 1); consumed = extensionCursor; AddAndCheckConsumedBytes(charsToByteCRExclusive + 1); } } while (_mode == Mode.Extension); }
public void ParseRequestLineSplitBufferWithoutNewLineDoesNotUpdateConsumed() { HttpParser parser = new HttpParser(); ReadOnlyBuffer <byte> buffer = BufferUtilities.CreateBuffer("GET ", "/"); RequestHandler requestHandler = new RequestHandler(); bool result = parser.ParseRequestLine(requestHandler, buffer, out SequencePosition consumed, out SequencePosition examined); Assert.False(result); Assert.Equal(buffer.Slice(consumed).Length, buffer.Length); Assert.True(buffer.Slice(examined).IsEmpty); }
public void ParseHeadersDoesNotConsumeIncompleteHeader(string rawHeaders) { var parser = CreateParser(Mock.Of <IKestrelTrace>()); var buffer = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); Assert.Equal(buffer.Length, buffer.Slice(consumed).Length); Assert.True(buffer.Slice(examined).IsEmpty); Assert.Equal(0, consumedBytes); }
private void ParseChunkedSuffix(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; if (buffer.Length < 2) { examined = buffer.End; return; } var suffixBuffer = buffer.Slice(0, 2); var suffixSpan = suffixBuffer.ToSpan(); if (suffixSpan[0] == '\r' && suffixSpan[1] == '\n') { consumed = suffixBuffer.End; examined = suffixBuffer.End; AddAndCheckConsumedBytes(2); _mode = Mode.Prefix; } else { _context.ThrowRequestRejected(RequestRejectionReason.BadChunkSuffix); } }
private static T ReadMultiLittle <[Primitive] T>(ReadOnlyBuffer <byte> buffer, int len) where T : struct { Span <byte> localSpan = stackalloc byte[len]; buffer.Slice(0, len).CopyTo(localSpan); return(((ReadOnlySpan <byte>)localSpan).ReadLittleEndian <T>()); }
public void TestSeekByteLimitWithinSameBlock(string input, char seek, int limit, int expectedBytesScanned, int expectedReturnValue) { // Arrange ReadOnlyBuffer <byte> originalBuffer = Factory.CreateWithContent(input); // Act ReadOnlyBuffer <byte> buffer = limit > input.Length ? originalBuffer : originalBuffer.Slice(0, limit); SequencePosition?result = buffer.PositionOf((byte)seek); // Assert if (expectedReturnValue == -1) { Assert.Null(result); } else { Assert.NotNull(result); } if (expectedReturnValue != -1) { Assert.Equal(Encoding.ASCII.GetBytes(input.Substring(expectedBytesScanned - 1)), originalBuffer.Slice(result.Value).ToArray()); } }
/// <summary> /// Trim whitespace starting from the specified <see cref="ReadOnlyBuffer"/>. /// </summary> /// <param name="buffer">The <see cref="ReadOnlyBuffer"/> to trim</param> /// <returns>A new <see cref="ReadOnlyBuffer"/> with the starting whitespace trimmed.</returns> public static ReadOnlyBuffer TrimEnd(this ReadOnlyBuffer buffer) { var end = -1; var i = 0; foreach (var memory in buffer) { var span = memory.Span; for (int j = 0; j < span.Length; j++) { i++; if (IsWhitespaceChar(span[j])) { if (end == -1) { end = i; } } else { end = -1; } } } return(end != -1 ? buffer.Slice(0, end - 1) : buffer); }
private void ParseChunkedTrailer(ReadOnlyBuffer <byte> buffer, out SequencePosition consumed, out SequencePosition examined) { consumed = buffer.Start; examined = buffer.Start; if (buffer.Length < 2) { examined = buffer.End; return; } var trailerBuffer = buffer.Slice(0, 2); var trailerSpan = trailerBuffer.ToSpan(); if (trailerSpan[0] == '\r' && trailerSpan[1] == '\n') { consumed = trailerBuffer.End; examined = trailerBuffer.End; AddAndCheckConsumedBytes(2); _mode = Mode.Complete; } else { _mode = Mode.TrailerHeaders; } }
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 TechEmpowerRob() { var parser = new HttpParser(); var request = new Request(); ReadOnlyBuffer <byte> buffer = new ReadOnlyBuffer <byte>(_plaintextTechEmpowerRequestBytes); Assert.True(parser.ParseRequestLine(ref request, buffer, out var consumed)); Assert.Equal(25, consumed); Assert.True(parser.ParseHeaders(ref request, buffer.Slice(consumed), out consumed)); Assert.Equal(139, consumed); // request line Assert.Equal(Http.Method.Get, request.Method); Assert.Equal(Http.Version.Http11, request.Version); Assert.Equal("/plaintext", request.Path); // headers Assert.Equal(3, request.Headers.Count); Assert.True(request.Headers.ContainsKey("Host")); Assert.True(request.Headers.ContainsKey("Accept")); Assert.True(request.Headers.ContainsKey("Connection")); Assert.Equal("localhost", request.Headers["Host"]); Assert.Equal("text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7", request.Headers["Accept"]); Assert.Equal("keep-alive", request.Headers["Connection"]); }
public void TryParseInt32Multisegment(int expected) { byte[] array = new byte[32]; Utf8Formatter.TryFormat(expected, array, out var written); array[written] = (byte)'#'; var memory = new Memory <byte>(array, 0, written + 1); for (int pivot = 0; pivot < written; pivot++) { var front = memory.Slice(0, pivot); var back = memory.Slice(pivot); var first = new BufferList(front); var last = first.Append(back); var bytes = new ReadOnlyBuffer <byte>(first, 0, last, last.Memory.Length); Assert.True(Sequence.TryParse(bytes, out int value, out int consumed)); Assert.Equal(expected, value); Assert.True(Sequence.TryParse(bytes, out value, out SequencePosition consumedPosition)); Assert.Equal(expected, value); var afterValue = bytes.Slice(consumedPosition); Assert.Equal((byte)'#', afterValue.First.Span[0]); } }
public bool TakeMessageHeaders(ReadOnlyBuffer buffer, out Position consumed, out Position examined) { // Make sure the buffer is limited bool overLength = false; if (buffer.Length >= _remainingRequestHeadersBytesAllowed) { buffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed); // If we sliced it means the current buffer bigger than what we're // allowed to look at overLength = true; } var result = _parser.ParseHeaders(new Http1ParsingHandler(this), buffer, out consumed, out examined, out var consumedBytes); _remainingRequestHeadersBytesAllowed -= consumedBytes; if (!result && overLength) { ThrowRequestRejected(RequestRejectionReason.HeadersExceedMaxTotalSize); } if (result) { TimeoutControl.CancelTimeout(); } return(result); }
public void MemorySeek(string raw, char searchFor, int expectIndex) { ReadOnlyBuffer <byte> cursors = Factory.CreateWithContent(raw); SequencePosition? result = cursors.PositionOf((byte)searchFor); Assert.NotNull(result); Assert.Equal(cursors.Slice(result.Value).ToArray(), Encoding.ASCII.GetBytes(raw.Substring(expectIndex))); }
public async Task ReaderShouldNotGetUnflushedBytesWhenOverflowingSegments() { // Fill the block with stuff leaving 5 bytes at the end Memory <byte> buffer = _pipe.Writer.GetMemory(); int len = buffer.Length; // Fill the buffer with garbage // block 1 -> block2 // [padding..hello] -> [ world ] byte[] paddingBytes = Enumerable.Repeat((byte)'a', len - 5).ToArray(); _pipe.Writer.Write(paddingBytes); await _pipe.Writer.FlushAsync(); // Write 10 and flush _pipe.Writer.Write(new byte[] { 0, 0, 0, 10 }); // Write 9 _pipe.Writer.Write(new byte[] { 0, 0, 0, 9 }); // Write 8 _pipe.Writer.Write(new byte[] { 0, 0, 0, 8 }); // Make sure we don't see it yet ReadResult result = await _pipe.Reader.ReadAsync(); ReadOnlyBuffer <byte> reader = result.Buffer; Assert.Equal(len - 5, reader.Length); // Don't move _pipe.Reader.AdvanceTo(reader.End); // Now flush await _pipe.Writer.FlushAsync(); reader = (await _pipe.Reader.ReadAsync()).Buffer; Assert.Equal(12, reader.Length); Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray()); Assert.Equal(new byte[] { 0, 0, 0, 9 }, reader.Slice(4, 4).ToArray()); Assert.Equal(new byte[] { 0, 0, 0, 8 }, reader.Slice(8, 4).ToArray()); _pipe.Reader.AdvanceTo(reader.Start, reader.Start); }
public static bool TryParseMessage(ref ReadOnlyBuffer <byte> buffer, out ReadOnlyBuffer <byte> payload) { payload = default(ReadOnlyBuffer <byte>); var index = buffer.Span.IndexOf(TextMessageFormatter.RecordSeparator); if (index == -1) { return(false); } payload = buffer.Slice(0, index); // Skip record separator buffer = buffer.Slice(index + 1); return(true); }
/// <summary> /// Checks to see if the <see cref="ReadOnlyBuffer"/> starts with the specified <see cref="Span{Byte}"/>. /// </summary> /// <param name="value">The <see cref="Span{Byte}"/> to compare to</param> /// <returns>True if the bytes StartsWith, false if not</returns> public static bool StartsWith(this ReadOnlyBuffer <byte> buffer, Span <byte> value) { if (buffer.Length < value.Length) { // just nope return(false); } return(buffer.Slice(0, value.Length).EqualsTo(value)); }
private void VerifyRawHeaders(string rawHeaders, IEnumerable <string> expectedHeaderNames, IEnumerable <string> expectedHeaderValues) { Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match"); var parser = new HttpParser(); var buffer = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); var parsedHeaders = requestHandler.Headers.ToArray(); Assert.Equal(expectedHeaderNames.Count(), parsedHeaders.Length); Assert.Equal(expectedHeaderNames, parsedHeaders.Select(t => t.Key)); Assert.Equal(expectedHeaderValues, parsedHeaders.Select(t => t.Value)); Assert.True(buffer.Slice(consumed).IsEmpty); Assert.True(buffer.Slice(examined).IsEmpty); }
//[Fact] //public void ExceptionDetailNotIncludedWhenLogLevelInformationNotEnabled() //{ // var mockTrace = new HttpParser(); // mockTrace // .Setup(trace => trace.IsEnabled(LogLevel.Information)) // .Returns(false); // var parser = new HttpParser(); // // Invalid request line // var buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes("GET % HTTP/1.1\r\n")); // var requestHandler = new RequestHandler(); // var exception = Assert.Throws<BadHttpRequestException>(() => // parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); // Assert.Equal("Invalid request line: ''", exception.Message); // Assert.Equal(StatusCodes.Status400BadRequest, (exception as BadHttpRequestException).StatusCode); // // Unrecognized HTTP version // buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes("GET / HTTP/1.2\r\n")); // exception = Assert.Throws<BadHttpRequestException>(() => // parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); // Assert.Equal("Unrecognized HTTP version: ''", exception.Message); // Assert.Equal(StatusCodes.Status505HttpVersionNotsupported, (exception as BadHttpRequestException).StatusCode); // // Invalid request header // buffer = ReadableBuffer.Create(Encoding.ASCII.GetBytes("Header: value\n\r\n")); // exception = Assert.Throws<BadHttpRequestException>(() => // parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes)); // Assert.Equal("Invalid request header: ''", exception.Message); // Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode); //} private void VerifyHeader( string headerName, string rawHeaderValue, string expectedHeaderValue) { var parser = new HttpParser(); var buffer = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n")); var requestHandler = new RequestHandler(); parser.ParseHeaders(requestHandler, buffer, out var consumed, out var examined, out var consumedBytes); var pairs = requestHandler.Headers.ToArray(); Assert.Equal(1, pairs.Length); Assert.Equal(headerName, pairs[0].Key); Assert.Equal(expectedHeaderValue, pairs[0].Value); Assert.True(buffer.Slice(consumed).IsEmpty); Assert.True(buffer.Slice(examined).IsEmpty); }
public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine) { var parser = CreateParser(Mock.Of <IKestrelTrace>()); var buffer = new ReadOnlyBuffer <byte>(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); Assert.False(parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined)); Assert.Equal(buffer.Start, consumed); Assert.True(buffer.Slice(examined).IsEmpty); }
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 override TPackageInfo Filter(ref ReadOnlyBuffer <byte> buffer) { ReadOnlyBuffer <byte> slice; Position cursor; if (!buffer.TrySliceTo(new Span <byte>(_terminator), out slice, out cursor)) { return(null); } buffer = buffer.Slice(cursor).Slice(_terminator.Length); return(ResolvePackage(slice)); }
private static void FindAllNewLines(ReadOnlyBuffer buffer) { while (true) { var position = buffer.PositionOf((byte)'\n'); if (position == null) { break; } buffer = buffer.Slice(position.Value).Slice(1); } }