private void SendRequest()
        {
            // Record when we first started the download
            headerLength = 0;
            startTime    = DateTime.Now;

            // Create a HTTP request using the Deusty.Net.HTTP.HTTPHeader class.
            // The HTTP protocol is fairly straightforward, but this class helps hide protocol
            // specific information that we're not really concerned with for this AsyncSocket sameple.

            HTTPHeader request = HTTPHeader.CreateRequest("GET", FETCH_REQUEST);

            request.SetHeaderFieldValue("Host", FETCH_HOST);

            String requestStr = request.ToString();

            LogInfo("Sending Request:");
            LogMessage(requestStr);

            // Convert HTTPHeader object to a byte array.

            byte[] requestData = Encoding.UTF8.GetBytes(requestStr);
            Console.WriteLine(Data.ToHexString(requestData));

            // Now write the data over the socket.
            // This call is asynchronous, and returns immediately.
            // When finished writing, the asyncSocket_DidWrite method is called.

            asyncSocket.Write(requestData, WRITE_TIMEOUT, HTTP_HEADERS);

            // Setup http response
            response = HTTPHeader.CreateEmptyResponse();

            // And start reading in the response
            asyncSocket.Read(AsyncSocket.CRLFData, READ_HEADER_TIMEOUT, HTTP_HEADERS);

            // Reset progress bar
            progressBar.Value = 0;
        }
        private void asyncSocket_DidRead(AsyncSocket sender, byte[] data, long tag)
        {
            //	LogInfo("DidRead: {0}", tag);

            if (tag == HTTP_HEADERS)
            {
                // We read in one line of the http header response
                // Do we have the full http header yet?

                headerLength += data.Length;

                response.AppendBytes(data);
                if (!response.IsHeaderComplete())
                {
                    // We don't have a complete header yet
                    asyncSocket.Read(AsyncSocket.CRLFData, READ_HEADER_TIMEOUT, HTTP_HEADERS);
                }
                else
                {
                    LogInfo("Received Response: ({0} bytes)", headerLength);
                    LogMessage(response.ToString());

                    // Check the http status code
                    if (response.GetStatusCode() != 200)
                    {
                        // We only support status code 200 in this overly simple http client

                        LogError("HTTP status code is not \"200 OK\"");
                        LogError("Disconnecting...");

                        asyncSocket.Close();
                        return;
                    }

                    // Extract the Content-Length
                    String contentLength = response.GetHeaderFieldValue("Content-Length");
                    Int32.TryParse(contentLength, out fileSizeInBytes);

                    // Extract Transfer-Encoding
                    String transferEncoding     = response.GetHeaderFieldValue("Transfer-Encoding");
                    bool   usingChunkedTransfer = String.Equals(transferEncoding, "chunked", StringComparison.OrdinalIgnoreCase);

                    if (fileSizeInBytes > 0)
                    {
                        // Using traditional transfer

                        totalBytesReceived = 0;
                        asyncSocket.Read(fileSizeInBytes, READ_BODY_TIMEOUT, HTTP_BODY);
                    }
                    else if (usingChunkedTransfer)
                    {
                        // Using chunked transfer
                        // For more information on chunked transfer, see the "HTTP Made Really Easy" website:
                        // http://www.jmarshall.com/easy/http/

                        LogInfo("Using chunked transfer - Unable to use progress bar");

                        chunkedTransferStage = CHUNKED_STAGE_SIZE;
                        asyncSocket.Read(AsyncSocket.CRLFData, READ_CHUNKSIZE_TIMEOUT, HTTP_BODY_CHUNKED);
                    }
                    else
                    {
                        LogError("Unable to extract content length, and not using chunked transfer encoding!");
                        LogError("Disconnecting...");

                        asyncSocket.Close();
                        return;
                    }
                }
            }
            else if (tag == HTTP_BODY)
            {
                // Write the data to log
                try
                {
                    LogMessage(Encoding.UTF8.GetString(data));
                }
                catch
                {
                    LogError("Cannot convert chunk to UTF-8 string");
                }

                LogInfo("\r\nDownload complete");
                progressBar.Value = 100;

                TimeSpan ellapsed = DateTime.Now - startTime;
                LogInfo("\r\nTotal Time = {0:N} milliseconds", ellapsed.TotalMilliseconds);

                LogInfo("Disconnecting...");
                asyncSocket.Close();
            }
            else if (tag == HTTP_BODY_CHUNKED)
            {
                if (chunkedTransferStage == CHUNKED_STAGE_SIZE)
                {
                    // We have just read in a line with the size of the chunk data, in hex,
                    // possibly followed by a semicolon and extra parameters that can be ignored,
                    // and ending with CRLF
                    String sizeLine = Encoding.UTF8.GetString(data);

                    Int32 chunkSizeInBytes;
                    Int32.TryParse(sizeLine, System.Globalization.NumberStyles.HexNumber, null, out chunkSizeInBytes);

                    if (chunkSizeInBytes > 0)
                    {
                        // Don't forget about the trailing CRLF when downloading the data
                        chunkSizeInBytes += 2;

                        chunkedTransferStage = CHUNKED_STAGE_DATA;
                        asyncSocket.Read(chunkSizeInBytes, READ_BODY_TIMEOUT, tag);
                    }
                    else
                    {
                        chunkedTransferStage = CHUNKED_STAGE_FOOTER;
                        asyncSocket.Read(AsyncSocket.CRLFData, READ_FOOTER_TIMEOUT, tag);
                    }
                }
                else if (chunkedTransferStage == CHUNKED_STAGE_DATA)
                {
                    // Write the data to log (excluding trailing CRLF)
                    try
                    {
                        String str = Encoding.UTF8.GetString(data, 0, data.Length - 2);
                        LogMessage(str);
                    }
                    catch
                    {
                        LogError("Cannot convert chunk to UTF-8 string");
                    }

                    chunkedTransferStage = CHUNKED_STAGE_SIZE;
                    asyncSocket.Read(AsyncSocket.CRLFData, READ_CHUNKSIZE_TIMEOUT, tag);
                }
                else if (chunkedTransferStage == CHUNKED_STAGE_FOOTER)
                {
                    // The data we just downloaded is either a footer, or an empty line (single CRLF)
                    if (data.Length > 2)
                    {
                        LogInfo("Received HTTP Footer:");
                        LogInfo(Encoding.UTF8.GetString(data));

                        asyncSocket.Read(AsyncSocket.CRLFData, READ_FOOTER_TIMEOUT, tag);
                    }
                    else
                    {
                        LogInfo("\r\nDownload complete");

                        TimeSpan ellapsed = DateTime.Now - startTime;
                        LogInfo("\r\nTotal Time = {0:N} milliseconds", ellapsed.TotalMilliseconds);

                        LogInfo("Disconnecting...");
                        asyncSocket.Close();
                    }
                }
            }
        }