internal static async Task <Match> MatchLineAsync(this IAsyncEnumerator <byte> enumerator, Regex regex) { // Validate parameters. if (enumerator == null) { throw new ArgumentNullException(nameof(enumerator)); } if (regex == null) { throw new ArgumentNullException(nameof(regex)); } // The line. string line = await enumerator.ReadLineAsync().ConfigureAwait(false); // Match. Match match = regex.Match(line); // If not successful, throw an exception. if (!match.Success) { throw new InvalidOperationException($"The regular expression did not match the line. (regex: { regex }, line: { line }"); } // Return the match. return(match); }
internal static async Task SetHeaderFieldsAsync(this HttpResponseMessage response, IAsyncEnumerator <byte> enumerator, CancellationToken cancellationToken) { // Validate parameters. if (response == null) { throw new ArgumentNullException(nameof(response)); } if (enumerator == null) { throw new ArgumentNullException(nameof(enumerator)); } // The line. string line; // The field and value. string field = null; string value = null; // While the line is not null or empty. while (!string.IsNullOrEmpty(line = await enumerator.ReadLineAsync(cancellationToken).ConfigureAwait(false))) { // The match. Match match; // Does this match a folded value? If so, add to the previous value. if ((match = FoldedHeaderFieldRegex.Match(line)).Success) { // Add to the previous value. value += " " + match.GetGroupValue("value"); } else if ((match = HeaderFieldRegex.Match(line)).Success) { // If the field and value are set, then set them now. if (field != null && value != null) { response.Headers.TryAddWithoutValidation(field, value); } // Set the field and the value. field = match.GetGroupValue("fieldName"); value = match.GetGroupValue("fieldValue"); } } // If the field and value are set, then set them now. if (field != null && value != null) { response.Headers.TryAddWithoutValidation(field, value); } }
internal static async Task <HttpContent> ReadHttpContentFromChunkedTransferEncoding(this IAsyncEnumerator <byte> enumerator, HttpResponseMessage response, CancellationToken cancellationToken) { // Validate parameters. if (enumerator == null) { throw new ArgumentNullException(nameof(enumerator)); } if (response == null) { throw new ArgumentNullException(nameof(response)); } // The memory stream. var ms = new MemoryStream(); // Continue forever. while (true) { // Read the array buffer as a string. string chunkSize = await enumerator.ReadLineAsync(cancellationToken).ConfigureAwait(false); // Match. Match match = ChunkSizeRegex.Match(chunkSize); // Convert to a length. int length = int.Parse(match.GetGroupValue("chunkSize"), NumberStyles.HexNumber); // If 0, get out. if (length == 0 && !match.Groups["chunkExtension"].Success) { // Get out. break; } // While there are bytes to read. while (length-- > 0 && await enumerator.MoveNext(cancellationToken).ConfigureAwait(false)) { ms.WriteByte(enumerator.Current); } // Read the bytes. var line = await enumerator.ReadLineBytesAsync(cancellationToken).ConfigureAwait(false); // If not empty, throw. if (line.Count > 0) { throw new InvalidOperationException("An unexpected byte sequence was encountered after processing chunked encoding data."); } } // Set the header fields again. This is for extra headers that // may be passed down. await response.SetHeaderFieldsAsync(enumerator, cancellationToken).ConfigureAwait(false); // Reset the memory stream. ms.Seek(0, SeekOrigin.Begin); // Return the content. return(new StreamContent(ms)); }