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(); } } } }