private static State ParseBodyPart( byte[] buffer, int bytesReady, ref int bytesConsumed, ref BodyPartState bodyPartState, long maximumMessageLength, ref long totalBytesConsumed, CurrentBodyPartStore currentBodyPart) { Contract.Assert((bytesReady - bytesConsumed) >= 0, "ParseBodyPart()|(bytesReady - bytesConsumed) < 0"); Contract.Assert(maximumMessageLength <= 0 || totalBytesConsumed <= maximumMessageLength, "ParseBodyPart()|Message already read exceeds limit."); // Remember where we started. int segmentStart; int initialBytesParsed = bytesConsumed; // Set up parsing status with what will happen if we exceed the buffer. State parseStatus = State.DataTooBig; long effectiveMax = maximumMessageLength <= 0 ? Int64.MaxValue : (maximumMessageLength - totalBytesConsumed + bytesConsumed); if (bytesReady < effectiveMax) { parseStatus = State.NeedMoreData; effectiveMax = bytesReady; } currentBodyPart.ResetBoundaryOffset(); Contract.Assert(bytesConsumed < effectiveMax, "We have already consumed more than the max header length."); switch (bodyPartState) { case BodyPartState.BodyPart: while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { goto quit; } } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; case BodyPartState.AfterFirstCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.LF); // Move past the CR bodyPartState = BodyPartState.AfterFirstLineFeed; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstLineFeed; case BodyPartState.AfterFirstLineFeed: if (buffer[bytesConsumed] == MimeMultipartParser.CR) { // Remember potential boundary currentBodyPart.ResetBoundary(); currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; } if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.AfterFirstDash; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstDash; case BodyPartState.AfterFirstDash: if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.Boundary; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.Boundary; case BodyPartState.Boundary: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart); goto quit; } } if (bytesConsumed > segmentStart) { currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart); } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterSecondCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterSecondCarriageReturn; case BodyPartState.AfterSecondCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.LF); // Move past the LF bytesConsumed++; bodyPartState = BodyPartState.BodyPart; if (currentBodyPart.IsBoundaryValid()) { parseStatus = State.BodyPartCompleted; } else { currentBodyPart.ResetBoundary(); if (bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } goto quit; } quit: if (initialBytesParsed < bytesConsumed) { int boundaryLength = currentBodyPart.BoundaryDelta; if (boundaryLength > 0 && parseStatus != State.BodyPartCompleted) { currentBodyPart.HasPotentialBoundaryLeftOver = true; } int bodyPartEnd = bytesConsumed - initialBytesParsed - boundaryLength; currentBodyPart.BodyPart = new ArraySegment <byte>(buffer, initialBytesParsed, bodyPartEnd); } totalBytesConsumed += bytesConsumed - initialBytesParsed; return(parseStatus); }
private static State ParseBodyPart( byte[] buffer, int bytesReady, ref int bytesConsumed, ref BodyPartState bodyPartState, long maximumMessageLength, ref long totalBytesConsumed, CurrentBodyPartStore currentBodyPart) { Contract.Assert((bytesReady - bytesConsumed) >= 0, "ParseBodyPart()|(bytesReady - bytesConsumed) < 0"); Contract.Assert(maximumMessageLength <= 0 || totalBytesConsumed <= maximumMessageLength, "ParseBodyPart()|Message already read exceeds limit."); // Remember where we started. int segmentStart; int initialBytesParsed = bytesConsumed; // Set up parsing status with what will happen if we exceed the buffer. State parseStatus = State.DataTooBig; long effectiveMax = maximumMessageLength <= 0 ? Int64.MaxValue : (maximumMessageLength - totalBytesConsumed + bytesConsumed); if (bytesReady < effectiveMax) { parseStatus = State.NeedMoreData; effectiveMax = bytesReady; } currentBodyPart.ResetBoundaryOffset(); Contract.Assert(bytesConsumed < effectiveMax, "We have already consumed more than the max header length."); switch (bodyPartState) { case BodyPartState.BodyPart: while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { goto quit; } } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; case BodyPartState.AfterFirstCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.LF); // Move past the CR bodyPartState = BodyPartState.AfterFirstLineFeed; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstLineFeed; case BodyPartState.AfterFirstLineFeed: if (buffer[bytesConsumed] == MimeMultipartParser.CR) { // Remember potential boundary currentBodyPart.ResetBoundary(); currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; } if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.AfterFirstDash; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstDash; case BodyPartState.AfterFirstDash: if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.Boundary; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.Boundary; case BodyPartState.Boundary: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart); goto quit; } } if (bytesConsumed > segmentStart) { currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart); } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterSecondCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterSecondCarriageReturn; case BodyPartState.AfterSecondCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.LF); // Move past the LF bytesConsumed++; bodyPartState = BodyPartState.BodyPart; if (currentBodyPart.IsBoundaryValid()) { parseStatus = State.BodyPartCompleted; } else { currentBodyPart.ResetBoundary(); if (bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } goto quit; } quit: if (initialBytesParsed < bytesConsumed) { int boundaryLength = currentBodyPart.BoundaryDelta; if (boundaryLength > 0 && parseStatus != State.BodyPartCompleted) { currentBodyPart.HasPotentialBoundaryLeftOver = true; } int bodyPartEnd = bytesConsumed - initialBytesParsed - boundaryLength; currentBodyPart.BodyPart = new ArraySegment<byte>(buffer, initialBytesParsed, bodyPartEnd); } totalBytesConsumed += bytesConsumed - initialBytesParsed; return parseStatus; }
private static State ParseBodyPart( byte[] buffer, int bytesReady, ref int bytesConsumed, ref BodyPartState bodyPartState, long maximumMessageLength, ref long totalBytesConsumed, CurrentBodyPartStore currentBodyPart) { Contract.Assert((bytesReady - bytesConsumed) >= 0, "ParseBodyPart()|(bytesReady - bytesConsumed) < 0"); Contract.Assert(maximumMessageLength <= 0 || totalBytesConsumed <= maximumMessageLength, "ParseBodyPart()|Message already read exceeds limit."); // Remember where we started. int segmentStart; int initialBytesParsed = bytesConsumed; if (bytesReady == 0 && bodyPartState == BodyPartState.AfterBoundary && currentBodyPart.IsFinal) { // We've seen the end of the stream - the final body part has no trailing CRLF return(State.BodyPartCompleted); } // Set up parsing status with what will happen if we exceed the buffer. State parseStatus = State.DataTooBig; long effectiveMax = maximumMessageLength <= 0 ? Int64.MaxValue : (maximumMessageLength - totalBytesConsumed + bytesConsumed); if (effectiveMax == 0) { // effectiveMax is based on our max message size - if we've arrrived at the max size, then we need // to stop parsing. return(State.DataTooBig); } if (bytesReady <= effectiveMax) { parseStatus = State.NeedMoreData; effectiveMax = bytesReady; } currentBodyPart.ResetBoundaryOffset(); Contract.Assert(bytesConsumed < effectiveMax, "We have already consumed more than the max header length."); switch (bodyPartState) { case BodyPartState.BodyPart: while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { goto quit; } } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; case BodyPartState.AfterFirstCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.LF); // Move past the CR bodyPartState = BodyPartState.AfterFirstLineFeed; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstLineFeed; case BodyPartState.AfterFirstLineFeed: if (buffer[bytesConsumed] == MimeMultipartParser.CR) { // Remember potential boundary currentBodyPart.ResetBoundary(); currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; } if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.AfterFirstDash; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstDash; case BodyPartState.AfterFirstDash: if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.Boundary; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.Boundary; case BodyPartState.Boundary: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { if (currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { if (currentBodyPart.IsBoundaryComplete()) { // At this point we've seen the end of a boundary segment that is aligned at the end // of the buffer - this might be because we have another segment coming or it might // truly be the end of the message. bodyPartState = BodyPartState.AfterBoundary; } } else { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; } goto quit; } } if (bytesConsumed > segmentStart) { if (!currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } } goto case BodyPartState.AfterBoundary; case BodyPartState.AfterBoundary: // This state means that we just saw the end of a boundary. It might by a 'normal' boundary, in which // case it's followed by optional whitespace and a CRLF. Or it might be the 'final' boundary and will // be followed by '--', optional whitespace and an optional CRLF. if (buffer[bytesConsumed] == MimeMultipartParser.Dash && !currentBodyPart.IsFinal) { currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); if (++bytesConsumed == effectiveMax) { bodyPartState = BodyPartState.AfterSecondDash; goto quit; } goto case BodyPartState.AfterSecondDash; } // Capture optional whitespace segmentStart = bytesConsumed; while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { if (!currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { // It's an unexpected character currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; } goto quit; } } if (bytesConsumed > segmentStart) { if (!currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } } if (buffer[bytesConsumed] == MimeMultipartParser.CR) { currentBodyPart.AppendBoundary(MimeMultipartParser.CR); if (++bytesConsumed == effectiveMax) { bodyPartState = BodyPartState.AfterSecondCarriageReturn; goto quit; } goto case BodyPartState.AfterSecondCarriageReturn; } else { // It's an unexpected character currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } case BodyPartState.AfterSecondDash: if (buffer[bytesConsumed] == MimeMultipartParser.Dash) { currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); bytesConsumed++; if (currentBodyPart.IsBoundaryComplete()) { Debug.Assert(currentBodyPart.IsFinal); // If we get in here, it means we've see the trailing '--' of the last boundary - in order to consume all of the // remaining bytes, we don't mark the parse as complete again - wait until this method is called again with the // empty buffer to do that. bodyPartState = BodyPartState.AfterBoundary; parseStatus = State.NeedMoreData; goto quit; } else { currentBodyPart.ResetBoundary(); if (bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } } else { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } case BodyPartState.AfterSecondCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } currentBodyPart.AppendBoundary(MimeMultipartParser.LF); bytesConsumed++; bodyPartState = BodyPartState.BodyPart; if (currentBodyPart.IsBoundaryComplete()) { parseStatus = State.BodyPartCompleted; goto quit; } else { currentBodyPart.ResetBoundary(); if (bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } } quit: if (initialBytesParsed < bytesConsumed) { int boundaryLength = currentBodyPart.BoundaryDelta; if (boundaryLength > 0 && parseStatus != State.BodyPartCompleted) { currentBodyPart.HasPotentialBoundaryLeftOver = true; } int bodyPartEnd = bytesConsumed - initialBytesParsed - boundaryLength; currentBodyPart.BodyPart = new ArraySegment <byte>(buffer, initialBytesParsed, bodyPartEnd); } totalBytesConsumed += bytesConsumed - initialBytesParsed; return(parseStatus); }
private static State ParseBodyPart( byte[] buffer, int bytesReady, ref int bytesConsumed, ref BodyPartState bodyPartState, long maximumMessageLength, ref long totalBytesConsumed, CurrentBodyPartStore currentBodyPart) { Contract.Assert((bytesReady - bytesConsumed) >= 0, "ParseBodyPart()|(bytesReady - bytesConsumed) < 0"); Contract.Assert(maximumMessageLength <= 0 || totalBytesConsumed <= maximumMessageLength, "ParseBodyPart()|Message already read exceeds limit."); // Remember where we started. int segmentStart; int initialBytesParsed = bytesConsumed; if (bytesReady == 0 && bodyPartState == BodyPartState.AfterBoundary && currentBodyPart.IsFinal) { // We've seen the end of the stream - the final body part has no trailing CRLF return State.BodyPartCompleted; } // Set up parsing status with what will happen if we exceed the buffer. State parseStatus = State.DataTooBig; long effectiveMax = maximumMessageLength <= 0 ? Int64.MaxValue : (maximumMessageLength - totalBytesConsumed + bytesConsumed); if (effectiveMax == 0) { // effectiveMax is based on our max message size - if we've arrrived at the max size, then we need // to stop parsing. return State.DataTooBig; } if (bytesReady <= effectiveMax) { parseStatus = State.NeedMoreData; effectiveMax = bytesReady; } currentBodyPart.ResetBoundaryOffset(); Contract.Assert(bytesConsumed < effectiveMax, "We have already consumed more than the max header length."); switch (bodyPartState) { case BodyPartState.BodyPart: while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { goto quit; } } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; case BodyPartState.AfterFirstCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.LF); // Move past the CR bodyPartState = BodyPartState.AfterFirstLineFeed; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstLineFeed; case BodyPartState.AfterFirstLineFeed: if (buffer[bytesConsumed] == MimeMultipartParser.CR) { // Remember potential boundary currentBodyPart.ResetBoundary(); currentBodyPart.AppendBoundary(MimeMultipartParser.CR); // Move past the CR bodyPartState = BodyPartState.AfterFirstCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstCarriageReturn; } if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.AfterFirstDash; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.AfterFirstDash; case BodyPartState.AfterFirstDash: if (buffer[bytesConsumed] != MimeMultipartParser.Dash) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } // Remember potential boundary currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); // Move past the Dash bodyPartState = BodyPartState.Boundary; if (++bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.Boundary; case BodyPartState.Boundary: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { if (currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { if (currentBodyPart.IsBoundaryComplete()) { // At this point we've seen the end of a boundary segment that is aligned at the end // of the buffer - this might be because we have another segment coming or it might // truly be the end of the message. bodyPartState = BodyPartState.AfterBoundary; } } else { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; } goto quit; } } if (bytesConsumed > segmentStart) { if (!currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } } goto case BodyPartState.AfterBoundary; case BodyPartState.AfterBoundary: // This state means that we just saw the end of a boundary. It might by a 'normal' boundary, in which // case it's followed by optional whitespace and a CRLF. Or it might be the 'final' boundary and will // be followed by '--', optional whitespace and an optional CRLF. if (buffer[bytesConsumed] == MimeMultipartParser.Dash && !currentBodyPart.IsFinal) { currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); if (++bytesConsumed == effectiveMax) { bodyPartState = BodyPartState.AfterSecondDash; goto quit; } goto case BodyPartState.AfterSecondDash; } // Capture optional whitespace segmentStart = bytesConsumed; while (buffer[bytesConsumed] != MimeMultipartParser.CR) { if (++bytesConsumed == effectiveMax) { if (!currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { // It's an unexpected character currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; } goto quit; } } if (bytesConsumed > segmentStart) { if (!currentBodyPart.AppendBoundary(buffer, segmentStart, bytesConsumed - segmentStart)) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } } if (buffer[bytesConsumed] == MimeMultipartParser.CR) { currentBodyPart.AppendBoundary(MimeMultipartParser.CR); if (++bytesConsumed == effectiveMax) { bodyPartState = BodyPartState.AfterSecondCarriageReturn; goto quit; } goto case BodyPartState.AfterSecondCarriageReturn; } else { // It's an unexpected character currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } case BodyPartState.AfterSecondDash: if (buffer[bytesConsumed] == MimeMultipartParser.Dash) { currentBodyPart.AppendBoundary(MimeMultipartParser.Dash); bytesConsumed++; if (currentBodyPart.IsBoundaryComplete()) { Debug.Assert(currentBodyPart.IsFinal); // If we get in here, it means we've see the trailing '--' of the last boundary - in order to consume all of the // remaining bytes, we don't mark the parse as complete again - wait until this method is called again with the // empty buffer to do that. bodyPartState = BodyPartState.AfterBoundary; parseStatus = State.NeedMoreData; goto quit; } else { currentBodyPart.ResetBoundary(); if (bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } } else { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } case BodyPartState.AfterSecondCarriageReturn: if (buffer[bytesConsumed] != MimeMultipartParser.LF) { currentBodyPart.ResetBoundary(); bodyPartState = BodyPartState.BodyPart; goto case BodyPartState.BodyPart; } currentBodyPart.AppendBoundary(MimeMultipartParser.LF); bytesConsumed++; bodyPartState = BodyPartState.BodyPart; if (currentBodyPart.IsBoundaryComplete()) { parseStatus = State.BodyPartCompleted; goto quit; } else { currentBodyPart.ResetBoundary(); if (bytesConsumed == effectiveMax) { goto quit; } goto case BodyPartState.BodyPart; } } quit: if (initialBytesParsed < bytesConsumed) { int boundaryLength = currentBodyPart.BoundaryDelta; if (boundaryLength > 0 && parseStatus != State.BodyPartCompleted) { currentBodyPart.HasPotentialBoundaryLeftOver = true; } int bodyPartEnd = bytesConsumed - initialBytesParsed - boundaryLength; currentBodyPart.BodyPart = new ArraySegment<byte>(buffer, initialBytesParsed, bodyPartEnd); } totalBytesConsumed += bytesConsumed - initialBytesParsed; return parseStatus; }