예제 #1
0
        private void FindResponses(TcpConnection conn, int direction)
        {
            Int64 totalReplyLength = conn.Stream(direction).Data.Length;

            RpyStateType state = RpyStateType.RpyStateStartHttp;

            Byte[]       data   = conn.Stream(direction).Data.ToArray();
            int          cur    = 0;
            int          reqIdx = 0;
            HttpResponse rpy    = null;

            while (cur < data.Length)
            {
                switch (state)
                {
                // Start state: Find "HTTP/" that begins a response
                case RpyStateType.RpyStateStartHttp:
                    if (strncasecmp(data, cur, 5, "HTTP/"))
                    {
                        // Found start of a response
                        state = RpyStateType.RpyStateFinishHttp;

                        cur += 5;
                        rpy  = new HttpResponse();
                    }
                    else
                    {
                        cur++;
                    }
                    break;

                // Finish off HTTP string (version number) by looking for whitespace
                case RpyStateType.RpyStateFinishHttp:
                    if (data[cur] == 0x20) // data[cur] == <space>
                    {
                        state = RpyStateType.RpyStateFindResponse;
                    }
                    else
                    {
                        cur++;
                    }
                    break;

                // Look for response code by finding non-whitespace.
                case RpyStateType.RpyStateFindResponse:
                    if (data[cur] != 0x20) // data[cur] == <space>
                    {
                        cur  += rpy.ParseResponseCode(data, cur);
                        state = RpyStateType.RpyStateFindContentLength;
                    }
                    else
                    {
                        cur++;
                    }
                    break;

                // this state is now misnamed since we pull out other
                // headers than just content-length now.
                case RpyStateType.RpyStateFindContentLength:
                    if (strncasecmp(data, cur, 17, "\r\nContent-Length:"))
                    {
                        cur += 17;
                        // skip leading spaces
                        while (data[cur] == 0x20) // data[cur] == '<space>'
                        {
                            cur++;
                        }

                        cur += rpy.ParseContentLength(data, cur);
                    }
                    else if (strncasecmp(data, cur, 15, "\r\nContent-Type:"))
                    {
                        cur += 15;
                        // skip leading spaces
                        while (data[cur] == 0x20) // data[cur] == '<space>'
                        {
                            cur++;
                        }

                        cur += rpy.ParseContentType(data, cur);
                    }
                    else if (strncasecmp(data, cur, 20, "\r\nTransfer-Encoding:"))
                    {
                        cur += 20;
                        // skip leading spaces
                        while (data[cur] == 0x20) // data[cur] == '<space>'
                        {
                            cur++;
                        }

                        cur += rpy.ParseTransferEncoding(data, cur);
                    }
                    else if (strncasecmp(data, cur, 4, "\r\n\r\n"))
                    {
                        // No increment for cur here, effectively fall through
                        state = RpyStateType.RpyStateFinishHeader;
                    }
                    else if (strncasecmp(data, cur, 2, "\r\n"))
                    {
                        cur += 2;
                        // Try to fatch other possible headers
                        int pos = cur;
                        while (data[pos] != 0x0D && // data[pos] != '\n'
                               data[pos] != 0x0A) // data[pos] != '\r'
                        {
                            pos++;
                        }

                        string str = Encoding.ASCII.GetString(data, cur, pos - cur);
                        int    idx = str.IndexOf(":");
                        if (idx != -1)
                        {
                            string field = str.Substring(0, idx).Trim();
                            string value = str.Substring(idx + 1).Trim();
                            rpy.OtherHeaders[field] = value;
                        }
                        else
                        {
                            // This should not happen during a specific compatate connection.
                            // But if it happened, only we can do is to ignore it.
                        }

                        cur = pos;
                    }
                    else
                    {
                        cur++;
                    }
                    break;

                // Skip over the rest of the header
                case RpyStateType.RpyStateFinishHeader:
                    if (strncasecmp(data, cur, 4, "\r\n\r\n"))
                    {
                        // Found end of header
                        cur += 4;

                        // We are sure to have found a response now,
                        // so match it to a request.
                        // Should always match in a complete connection,
                        // however, there are rare circumstences when responses
                        // are more than requests.
                        if (reqIdx < RequestList.Count)
                        {
                            rpy.Request = RequestList[reqIdx];
                            RequestList[reqIdx++].Response = rpy;
                        }

                        // At this point, we need to find the end of the
                        // response body.  There's a variety of ways to
                        // do this, but in any case, we need to make sure
                        // that ryp.ContentLength, cur are all set appropriately.

                        // See if we can ignore the body.
                        // We can do this
                        // for the reply to HEAD
                        // for a 1xx
                        // for a 204 (no content), 205 (reset content), or 304 (not modified).
                        if ((rpy.Request != null && rpy.Request.Method == HttpMethod.Head) ||
                            rpy.ResponseCode < 200 ||
                            rpy.ResponseCode == 204 ||
                            rpy.ResponseCode == 205 ||
                            rpy.ResponseCode == 304)
                        {
                            rpy.ContentLength = 0;
                            rpy.Body          = null;
                        }
                        else if (rpy.TransferEncoding != "")
                        {
                            // According to RFC 2616, when both TransferEncoding and ContentLength
                            // present, latter is ignored.
                            if (rpy.TransferEncoding.Contains("chunked"))
                            {
                                int pos = cur;
                                while (pos < data.Length)
                                {
                                    int t;
                                    int w;
                                    if ((w = Parses.ParseHex(data, pos, out t)) > 0)
                                    {
                                        if (t == 0)
                                        {
                                            pos += 2;
                                            break;
                                        }
                                        // skip to next chunk
                                        pos += w + 2 + t + 2;
                                    }
                                    else
                                    {
                                        pos++;
                                    }
                                }

                                rpy.ContentLength = pos - cur + 1;
                                rpy.Body          = new Byte[rpy.ContentLength];
                                // We should check in case we didn't captured complete stream.
                                if (rpy.ContentLength + cur > data.Length)
                                {
                                    Array.Copy(data, cur, rpy.Body, 0, data.Length - cur);
                                }
                                else
                                {
                                    Array.Copy(data, cur, rpy.Body, 0, rpy.ContentLength);
                                }
                                cur += rpy.ContentLength;

                                // TODO: There may also tailors to deal with
                            }
                            else
                            {
                                // Use content-length header if one was present.
                                rpy.Body = new Byte[rpy.ContentLength];
                                if (rpy.ContentLength + cur > data.Length)
                                {
                                    Array.Copy(data, cur, rpy.Body, 0, data.Length - cur);
                                }
                                else
                                {
                                    Array.Copy(data, cur, rpy.Body, 0, rpy.ContentLength);
                                }
                                cur += rpy.ContentLength;
                            }
                        }
                        else if (rpy.ContentLength != -1)
                        {
                            // Use content-length header if one was present.
                            rpy.Body = new Byte[rpy.ContentLength];
                            if (rpy.ContentLength + cur > data.Length)
                            {
                                Array.Copy(data, cur, rpy.Body, 0, data.Length - cur);
                            }
                            else
                            {
                                Array.Copy(data, cur, rpy.Body, 0, rpy.ContentLength);
                            }
                            cur += rpy.ContentLength;
                        }
                        else
                        {
                            // No content-length header found,
                            // so delimit response by end of stream.
                            // But make sure we do not have a "\r\n\r\n" string
                            // in the response, which may indicate the begining
                            // of a following response.
                            int start = cur;
                            while (cur < data.Length)
                            {
                                if (strncasecmp(data, cur, 4, "\r\n\r\n"))
                                {
                                    cur  += 4;
                                    state = RpyStateType.RpyStateStartHttp;
                                    break;
                                }
                                else
                                {
                                    cur++;
                                }
                            }

                            if (state == RpyStateType.RpyStateStartHttp)
                            {
                                rpy.ContentLength = cur - start;
                            }
                            else
                            {
                                rpy.ContentLength = data.Length - start;
                                cur = data.Length;
                            }

                            rpy.Body = new Byte[rpy.ContentLength];
                            Array.Copy(data, start, rpy.Body, 0, rpy.ContentLength);
                        }

                        // Set next state
                        state = RpyStateType.RpyStateStartHttp;

                        // Fill in other infos
                        rpy.Source       = conn.Pair.EndPoint(direction);
                        rpy.Destination  = conn.Pair.EndPoint(1 - direction);
                        rpy.ConnectionID = conn.ConnectionID;
                        // Add reply to list
                        ResponseList.Add(rpy);
                    }
                    else
                    {
                        cur++;
                    }
                    break;
                }
            }
        }
예제 #2
0
        private void FormatBody(HttpResponse rpy)
        {
            ContentType type = new ContentType(rpy.ContentType);

            // First we must deal chunked message
            if (rpy.TransferEncoding.Contains("chunked"))
            {
                using (MemoryStream ss = new MemoryStream())
                {
                    int pos = 0;
                    while (pos < rpy.Body.Length)
                    {
                        int t;
                        int w;
                        if ((w = Parses.ParseHex(rpy.Body, pos, out t)) > 0)
                        {
                            if (t == 0)
                            {
                                pos += 2;
                                break;
                            }
                            // skip length
                            pos += w + 2;
                            // save content
                            ss.Write(rpy.Body, pos, t);
                            // skip to next chunk
                            pos += t + 2;
                        }
                        else
                        {
                            pos++;
                        }
                    }

                    rpy.Body          = ss.ToArray();
                    rpy.ContentLength = rpy.Body.Length;
                }
            }

            // TODO: deal with multipart content type

            // Decompress if needed
            if (rpy.OtherHeaders.ContainsKey("Content-Encoding") &&
                rpy.OtherHeaders["Content-Encoding"].Contains("gzip"))
            {
                using (MemoryStream mstream = new MemoryStream(rpy.Body))
                {
                    using (MemoryStream tstream = new MemoryStream())
                    {
                        using (GZipStream gstream = new GZipStream(mstream, CompressionMode.Decompress))
                        {
                            using (BufferedStream buf = new BufferedStream(gstream))
                            {
                                buf.CopyTo(tstream);
                                rpy.Body = tstream.ToArray();
                            }
                        }
                    }
                }
            }
            else
            {
            }
        }