private void ParseRequestLine(TRequestHandler handler, ReadOnlySpan <byte> requestLine) { // Get Method and set the offset var method = requestLine.GetKnownMethod(out var methodEnd); if (method == HttpMethod.Custom) { methodEnd = GetUnknownMethodLength(requestLine); } var versionAndMethod = new HttpVersionAndMethod(method, methodEnd); // Use a new offset var as methodEnd needs to be on stack // as its passed by reference above so can't be in register. // Skip space var offset = methodEnd + 1; if ((uint)offset >= (uint)requestLine.Length) { // Start of path not found RejectRequestLine(requestLine); } var ch = requestLine[offset]; if (ch == ByteSpace || ch == ByteQuestionMark || ch == BytePercentage) { // Empty path is illegal, or path starting with percentage RejectRequestLine(requestLine); } // Target = Path and Query var targetStart = offset; var pathEncoded = false; // Skip first char (just checked) offset++; // Find end of path and if path is encoded for (; (uint)offset < (uint)requestLine.Length; offset++) { ch = requestLine[offset]; if (ch == ByteSpace || ch == ByteQuestionMark) { // End of path break; } else if (ch == BytePercentage) { pathEncoded = true; } } var path = new TargetOffsetPathLength(targetStart, length: offset - targetStart, pathEncoded); // Query string if (ch == ByteQuestionMark) { // We have a query string for (; (uint)offset < (uint)requestLine.Length; offset++) { ch = requestLine[offset]; if (ch == ByteSpace) { break; } } } var queryEnd = offset; // Consume space offset++; // Version + CR is 9 bytes which should take us to .Length // LF should have been dropped prior to method call if ((uint)offset + 9 != (uint)requestLine.Length || requestLine[offset + sizeof(ulong)] != ByteCR) { RejectRequestLine(requestLine); } // Version var remaining = requestLine.Slice(offset); var httpVersion = remaining.GetKnownVersion(); versionAndMethod.Version = httpVersion; if (httpVersion == HttpVersion.Unknown) { // HTTP version is unsupported. RejectUnknownVersion(remaining); } // We need to reinterpret from ReadOnlySpan into Span to allow path mutation for // in-place normalization and decoding to transform into a canonical path var startLine = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(requestLine), queryEnd); handler.OnStartLine(versionAndMethod, path, startLine); }
public void OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span <byte> startLine) { var targetStart = targetPath.Offset; // Slice out target var target = startLine[targetStart..];
public void OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span <byte> startLine) => Connection.OnStartLine(versionAndMethod, targetPath, startLine);