bool ParseBody(MultipartMimeParsingContex context)
        {
            bool result = this.FindBoundary(context);

            if (result)
            {
                byte[] body = new byte[context.ParsingIndex];
                Buffer.BlockCopy(this.buffer, this.offset, body, 0, context.ParsingIndex);
                context.Message.Body = new MemoryStream(body);
                this.ConsumeBytes(context.ParsingIndex + context.Boundary.Length);
                context.ParsingIndex = 0;
                context.State        = ParsingState.AfterBoundary;
            }

            return(result);
        }
        void ParseMultipartMime(int read, MultipartMimeParsingContex context)
        {
            this.count += read;
            bool continueParsing = true;

            while (continueParsing)
            {
                switch (context.State)
                {
                case ParsingState.FirstBoundary:
                    continueParsing = this.ParseFirstMimeBoundary(context);
                    break;

                case ParsingState.ContentTypeHeader:
                    continueParsing = this.ParseContentTypeHeader(context);
                    break;

                case ParsingState.ContentDescriptionHeader:
                    continueParsing = this.ParseContentDescriptionHeader(context);
                    break;

                case ParsingState.CRLF:
                    continueParsing = this.ParseCRLF(context);
                    break;

                case ParsingState.Body:
                    continueParsing = this.ParseBody(context);
                    if (continueParsing)
                    {
                        this.DispatchMessage(context.Message);
                        context.Message = null;
                    }
                    break;

                case ParsingState.AfterBoundary:
                    continueParsing = this.ParseAfterBoundary(context);
                    break;

                case ParsingState.Epilogue:
                    // ignore all data after the final MIME boundary
                    continueParsing = false;
                    this.ConsumeBytes(this.count);
                    break;
                }
                ;
            }
        }
        bool ParseCRLF(MultipartMimeParsingContex context)
        {
            bool result = this.FindCRLF(context);

            if (result)
            {
                if (context.ParsingIndex != 0)
                {
                    throw new InvalidOperationException("Malformed HTTP long poll response. Unexpected MIME part header.");
                }
                this.ConsumeBytes(2);
                context.ParsingIndex = 0;
                context.State        = ParsingState.Body;
            }

            return(result);
        }
        bool FindCRLF(MultipartMimeParsingContex context)
        {
            bool result = false;

            while (!result && context.ParsingIndex < (this.count - 1))
            {
                if (this.buffer[this.offset + context.ParsingIndex] == 0x0D &&
                    this.buffer[this.offset + context.ParsingIndex + 1] == 0x0A)
                {
                    result = true;
                }
                else
                {
                    context.ParsingIndex++;
                }
            }

            return(result);
        }
        bool FindBoundary(MultipartMimeParsingContex context)
        {
            bool result = false;

            while (!result && context.ParsingIndex <= (this.count - context.Boundary.Length))
            {
                result = true;
                int i = 0;
                while (result && i < context.Boundary.Length)
                {
                    result = this.buffer[this.offset + context.ParsingIndex + i] == context.Boundary[i];
                    i++;
                }
                if (!result)
                {
                    context.ParsingIndex++;
                }
            }

            return(result);
        }
        bool ParseContentDescriptionHeader(MultipartMimeParsingContex context)
        {
            bool result = this.FindCRLF(context);

            if (result)
            {
                string header = Encoding.UTF8.GetString(this.buffer, this.offset, context.ParsingIndex);
                Match  m      = contentDescriptionRegex.Match(header);
                if (!m.Success)
                {
                    throw new InvalidOperationException("Malformed HTTP long poll response. Connot determine topicId and messageId of the MIME part.");
                }
                context.Message.TopicId   = int.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture);
                context.Message.MessageId = int.Parse(m.Groups[2].Value, CultureInfo.InvariantCulture);
                this.ConsumeBytes(context.ParsingIndex + 2);
                context.ParsingIndex = 0;
                context.State        = ParsingState.CRLF;
            }

            return(result);
        }
        bool ParseContentTypeHeader(MultipartMimeParsingContex context)
        {
            bool result = this.FindCRLF(context);

            if (result)
            {
                string header = Encoding.UTF8.GetString(this.buffer, this.offset, context.ParsingIndex);
                Match  m      = contentTypeRegex.Match(header);
                if (!m.Success)
                {
                    throw new InvalidOperationException("Malformed HTTP long poll response. Cannot determine the content type of the MIME part.");
                }
                context.Message             = new PubsubMessage();
                context.Message.ContentType = m.Groups[1].Value;
                this.ConsumeBytes(context.ParsingIndex + 2);
                context.ParsingIndex = 0;
                context.State        = ParsingState.ContentDescriptionHeader;
            }

            return(result);
        }
        bool ParseFirstMimeBoundary(MultipartMimeParsingContex context)
        {
            bool result = this.FindCRLF(context);

            if (result)
            {
                if (context.ParsingIndex < 3 || this.buffer[this.offset] != 0x2D || this.buffer[this.offset + 1] != 0x2D)
                {
                    // boundary does not start with "--" or is shorter than 1 character
                    throw new InvalidOperationException("Malformed HTTP long poll response. Cannot determine multipart/mixed boundary.");
                }
                context.Boundary    = new byte[2 + context.ParsingIndex];
                context.Boundary[0] = 0x0D;
                context.Boundary[1] = 0x0A;
                Buffer.BlockCopy(this.buffer, this.offset, context.Boundary, 2, context.ParsingIndex);
                this.ConsumeBytes(context.ParsingIndex + 2);
                context.ParsingIndex = 0;
                context.State        = ParsingState.ContentTypeHeader;
            }

            return(result);
        }
        bool ParseAfterBoundary(MultipartMimeParsingContex context)
        {
            if (this.count >= 2)
            {
                if (this.buffer[this.offset] == 0x0D && this.buffer[this.offset + 1] == 0x0A)
                {
                    // another MIME part is expected
                    this.ConsumeBytes(2);
                    context.State = ParsingState.ContentTypeHeader;
                }
                else if (this.buffer[this.offset] == 0x2D && this.buffer[this.offset + 1] == 0x2D)
                {
                    // another MIME part is not expected
                    this.ConsumeBytes(2);
                    context.State = ParsingState.Epilogue;
                }
                else
                {
                    throw new InvalidOperationException("Malformed HTTP long poll response. Protocol violation after MIME boundary.");
                }
            }

            return(this.count > 0);
        }