/// <summary> /// Read response from stream /// </summary> /// <param name="stream"></param> /// <param name="response"></param> /// <param name="rewrite"></param> /// <returns>redirected target</returns> protected async Task <string> ReadAsync(Stream stream, HttpResponse response, string host, Func <string, string> rewrite) { // Now read response back and write out to response var reader = new HttpResponseReader(stream); var isChunked = false; string contentEncoding = null; var headers = new HeaderDictionary(); // Parse headers and status code Console.WriteLine(); var s = await reader.ReadLineAsync().ConfigureAwait(false); // header if (string.IsNullOrEmpty(s)) { return(null); // throw } Console.WriteLine(s); var statusCode = int.Parse(s.Split(' ')[1]); string target = null; while (true) { s = await reader.ReadLineAsync().ConfigureAwait(false); if (string.IsNullOrEmpty(s)) { break; } Console.WriteLine(s); var index = s.IndexOf(':'); if (index < 0) { continue; } var key = s.Substring(0, index).Trim(); var val = s.Substring(index + 1).Trim(); /**/ if (key.Equals("Transfer-Encoding", StringComparison.CurrentCultureIgnoreCase)) { isChunked = val.Equals("chunked", StringComparison.CurrentCultureIgnoreCase); } else if (key.Equals("Content-Encoding", StringComparison.CurrentCultureIgnoreCase)) { contentEncoding = val.ToLowerInvariant(); } else if (key.Equals("Set-Cookie")) { // TODO: // continue; } else { if (key.Equals("Location", StringComparison.CurrentCultureIgnoreCase)) { target = val; } val = _urls.Replace(val, (f) => rewrite(f.Value)); } if (headers.ContainsKey(key)) { headers.Remove(key); } headers.Add(key, val); } if (statusCode >= StatusCodes.Status300MultipleChoices || statusCode < StatusCodes.Status400BadRequest) { if (!string.IsNullOrEmpty(target)) { // Redirect to new location return(target); } } // Copy headers to response response.StatusCode = statusCode; response.Headers.Clear(); foreach (var entry in headers) { response.Headers.Add(entry.Key, entry.Value); } if (response.StatusCode == StatusCodes.Status204NoContent || response.StatusCode == StatusCodes.Status205ResetContent || response.StatusCode == StatusCodes.Status304NotModified) { response.ContentLength = 0; await response.Body.FlushAsync(); } else if (IsTextContent(response.ContentType, out var encoder)) { // Remember host as fallback response.Cookies.Append("host", host); await reader.ReadBodyAsync(response, isChunked, (body, len) => { if (!string.IsNullOrWhiteSpace(contentEncoding)) { var mem = new MemoryStream(body, 0, len); /**/ if (contentEncoding.Equals("gzip")) { using (var gzip = new GZipStream(mem, CompressionMode.Decompress, false)) { s = gzip.ToString(encoder); } } else if (contentEncoding.Equals("deflate")) { using (var deflate = new DeflateStream(mem, CompressionMode.Decompress, false)) { s = deflate.ToString(encoder); } } else { throw new Exception("Unexpected content encoding"); } }