/// <summary> /// Determines whether the stream starts with the given string. /// </summary> /// <returns> /// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise /// </returns> private static async ValueTask <int> startsWith(IPeekStream httpReader, IBufferPool bufferPool, string expectedStart, CancellationToken cancellationToken = default) { const int lengthToCheck = 10; if (bufferPool.BufferSize < lengthToCheck) { throw new Exception($"Buffer is too small. Minimum size is {lengthToCheck} bytes"); } byte[] buffer = bufferPool.GetBuffer(bufferPool.BufferSize); try { bool isExpected = true; int i = 0; while (i < lengthToCheck) { int peeked = await httpReader.PeekBytesAsync(buffer, i, i, lengthToCheck - i, cancellationToken); if (peeked <= 0) { return(-1); } peeked += i; while (i < peeked) { int b = buffer[i]; if (b == ' ' && i > 2) { return(isExpected ? 1 : 0); } else { char ch = (char)b; if (ch < 'A' || ch > 'z' || (ch > 'Z' && ch < 'a')) // ASCII letter { return(-1); } else if (i >= expectedStart.Length || ch != expectedStart[i]) { isExpected = false; } } i++; } } // only letters return(0); } finally { bufferPool.ReturnBuffer(buffer); } }
/// <summary> /// Gets the HTTP method from the stream. /// </summary> public static async ValueTask <KnownMethod> GetMethod(IPeekStream httpReader, IBufferPool bufferPool, CancellationToken cancellationToken = default) { const int lengthToCheck = 20; if (bufferPool.BufferSize < lengthToCheck) { throw new Exception($"Buffer is too small. Minimum size is {lengthToCheck} bytes"); } byte[] buffer = bufferPool.GetBuffer(bufferPool.BufferSize); try { int i = 0; while (i < lengthToCheck) { int peeked = await httpReader.PeekBytesAsync(buffer, i, i, lengthToCheck - i, cancellationToken); if (peeked <= 0) { return(KnownMethod.Invalid); } peeked += i; while (i < peeked) { int b = buffer[i]; if (b == ' ' && i > 2) { return(getKnownMethod(buffer.AsSpan(0, i))); } char ch = (char)b; if ((ch < 'A' || ch > 'z' || (ch > 'Z' && ch < 'a')) && (ch != '-')) // ASCII letter { return(KnownMethod.Invalid); } i++; } } // only letters, but no space (or shorter than 3 characters) return(KnownMethod.Invalid); } finally { bufferPool.ReturnBuffer(buffer); } }