protected override int ProcessData(byte[] data, bool writeExcess) { ThrowIfEnded(); bool run = true; int i = 0; for (; i < data.Length && run; i++) { char c = (char)data[i]; switch (State) { case RequestParserState.Method: if (c != WHITESPACE) { StringQueue.Append(c); } else { Incoming.Method = StringQueue.Next(); StringQueue.New(); State = RequestParserState.Query; } break; case RequestParserState.Query: if (c != WHITESPACE) { StringQueue.Append(c); } else { if (!Query.TryParse(StringQueue.Next(), out Query result)) { End(); return(-1); } Incoming.Query = result; StringQueue.New(); State = RequestParserState.Version; } break; case RequestParserState.Version: if (c != CR) { StringQueue.Append(c); } else { if (!HttpVersion.TryParse(StringQueue.Next(), out HttpVersion result)) { End(); return(-1); } Incoming.Version = result; StringQueue.New(); State = RequestParserState.FirstLf; } break; case RequestParserState.FirstLf: if (c != LF) { End(); return(-1); } State = RequestParserState.HeaderName; break; case RequestParserState.HeaderName: if (c == CR) { State = RequestParserState.Lf; } else if (c != COLON) { StringQueue.Append(c); } else { StringQueue.New(); State = RequestParserState.HeaderValue; } break; case RequestParserState.HeaderValue: if (c != CR) { StringQueue.Append(c); } else { Incoming.Headers.Set(StringQueue.Next(), StringQueue.Next().Trim()); State = RequestParserState.HeaderLf; } break; case RequestParserState.HeaderLf: if (c != LF) { End(); return(-1); } else { StringQueue.New(); State = RequestParserState.HeaderName; } break; case RequestParserState.Lf: if (c != LF) { End(); return(-1); } run = false; PushIncoming(); State = RequestParserState.Method; break; } } if (writeExcess) { int len = data.Length - i; byte[] sliced = new byte[len]; System.Buffer.BlockCopy(data, i, sliced, 0, len); Bwrite(sliced); } return(i); }
private int ProcessData(byte[] data, bool writeExcess) { ThrowIfEnded(); if (!IsSet) { throw new InvalidOperationException("Not set"); } int i = 0, len; char c; byte[] sliced; for (; i < data.Length;) { switch (State) { case BodyParserState.RawRead: len = ContentLength == -1 ? data.Length - i : Math.Min(data.Length - i, ContentLength - CurrentReadBytes); sliced = new byte[len]; Buffer.BlockCopy(data, i, sliced, 0, len); i += len; CurrentReadBytes += len; ContentTransform.Write(data); if (ContentTransform.Buffered > 0) { Readable.Write(ContentTransform.Read()); } if (CurrentReadBytes == ContentLength) { State = BodyParserState.Dormant; OnEnd?.Invoke(); break; } break; case BodyParserState.Chunked_Length: c = (char)data[i++]; if (c != CR) { StringQueue.Append(c); } else { if (!int.TryParse(StringQueue.Next(), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out int result)) { End(); return(-1); } chunkLen = result; State = BodyParserState.Chunked_LenLf; } break; case BodyParserState.Chunked_LenLf: c = (char)data[i++]; if (c != LF) { End(); return(-1); } if (chunkLen == 0) { State = BodyParserState.Chunked_Trailer; } else { State = BodyParserState.Chunked_ChunkData; } break; case BodyParserState.Chunked_ChunkData: len = Math.Min(data.Length - i, chunkLen - chunkIndex); sliced = new byte[len]; Buffer.BlockCopy(data, i, sliced, 0, len); i += len; CurrentReadBytes += len; chunkIndex += len; ContentTransform.Write(sliced); Readable.Write(ContentTransform.Read()); if (chunkLen == chunkIndex) { State = BodyParserState.Chunked_ChunkCr; } break; case BodyParserState.Chunked_ChunkCr: c = (char)data[i++]; if (c != CR) { End(); return(-1); } State = BodyParserState.Chunked_ChunkLf; break; case BodyParserState.Chunked_ChunkLf: c = (char)data[i++]; if (c != LF) { End(); return(-1); } State = BodyParserState.Chunked_Length; chunkLen = chunkIndex = 0; StringQueue.New(); break; case BodyParserState.Chunked_Trailer: c = (char)data[i++]; if (c != CR) { chunkIndex++; } else { if (chunkIndex == 0) { State = BodyParserState.Chunked_Lf; } else { chunkIndex = -1; // LF will be added } } break; case BodyParserState.Chunked_Lf: c = (char)data[i++]; if (c != LF) { End(); return(-1); } State = BodyParserState.Dormant; OnEnd?.Invoke(); ContentLength = CurrentReadBytes; break; default: throw new InvalidOperationException("ProcessData cannot execute on Dormant state"); } } if (writeExcess) { len = data.Length - i; sliced = new byte[len]; Buffer.BlockCopy(data, i, sliced, 0, len); Writable.Write(sliced); } return(i); }