protected virtual async Task ProcessRequest(HttpListenerContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var url = TargetUrl.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped); using (var msg = new HttpRequestMessage(new HttpMethod(context.Request.HttpMethod), url + context.Request.RawUrl)) { msg.Version = context.Request.ProtocolVersion; if (context.Request.HasEntityBody) { msg.Content = new StreamContent(context.Request.InputStream); // disposed with msg } string host = null; foreach (string headerName in context.Request.Headers) { var headerValue = context.Request.Headers[headerName]; if (headerName == "Content-Length" && headerValue == "0") // useless plus don't send if we have no entity body { continue; } bool contentHeader = false; switch (headerName) { // some headers go to content... case "Allow": case "Content-Disposition": case "Content-Encoding": case "Content-Language": case "Content-Length": case "Content-Location": case "Content-MD5": case "Content-Range": case "Content-Type": case "Expires": case "Last-Modified": contentHeader = true; break; case "Referer": if (RewriteReferer && Uri.TryCreate(headerValue, UriKind.Absolute, out var referer)) // if relative, don't handle { var builder = new UriBuilder(referer); builder.Host = TargetUrl.Host; builder.Port = TargetUrl.Port; headerValue = builder.ToString(); } break; case "Host": host = headerValue; if (RewriteHost) { headerValue = TargetUrl.Host + ":" + TargetUrl.Port; } break; } if (contentHeader) { msg.Content.Headers.Add(headerName, headerValue); } else { msg.Headers.Add(headerName, headerValue); } } using (var response = await _client.SendAsync(msg).ConfigureAwait(false)) { using (var os = context.Response.OutputStream) { context.Response.ProtocolVersion = response.Version; context.Response.StatusCode = (int)response.StatusCode; context.Response.StatusDescription = response.ReasonPhrase; foreach (var header in response.Headers) { context.Response.Headers.Add(header.Key, string.Join(", ", header.Value)); } foreach (var header in response.Content.Headers) { if (header.Key == "Content-Length") // this will be set automatically at dispose time { continue; } context.Response.Headers.Add(header.Key, string.Join(", ", header.Value)); } var ct = context.Response.ContentType; if (RewriteTargetInText && host != null && ct != null && (ct.IndexOf("text/html", StringComparison.OrdinalIgnoreCase) >= 0 || ct.IndexOf("application/json", StringComparison.OrdinalIgnoreCase) >= 0)) { using (var ms = new MemoryStream()) { using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) { await stream.CopyToAsync(ms).ConfigureAwait(false); var enc = context.Response.ContentEncoding ?? Encoding.UTF8; var html = enc.GetString(ms.ToArray()); if (TryReplace(html, "//" + _targetHost + ":" + _targetPort + "/", "//" + host + "/", out var replaced)) { var bytes = enc.GetBytes(replaced); using (var ms2 = new MemoryStream(bytes)) { ms2.Position = 0; await ms2.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); } } else { ms.Position = 0; await ms.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); } } } } else { using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) { await stream.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); } } } } } }
protected virtual async Task ProcessRequestAsync(HttpListenerContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var url = TargetUrl.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped); using (var msg = new HttpRequestMessage(new HttpMethod(context.Request.HttpMethod), url + context.Request.RawUrl)) { msg.Version = context.Request.ProtocolVersion; if (context.Request.HasEntityBody) { var stream = context.Request.InputStream; msg.Content = new StreamContent(stream); // disposed with msg } foreach (string headerName in context.Request.Headers) { var contentHeader = false; var headerValue = context.Request.Headers[headerName]; switch (headerName) { // these headers go to content... case "Allow": case "Content-Disposition": case "Content-Encoding": case "Content-Language": case "Content-Length": case "Content-Location": case "Content-MD5": case "Content-Range": case "Content-Type": case "Expires": case "Last-Modified": contentHeader = true; break; // rewrite referer case "Referer": if (Uri.TryCreate(headerValue, UriKind.Absolute, out var referer)) // if relative, don't handle { var builder = new UriBuilder(referer); builder.Host = TargetUrl.Host; builder.Port = TargetUrl.Port; headerValue = builder.ToString(); } break; // rewrite host case "Host": headerValue = TargetUrl.Host + ":" + TargetUrl.Port; break; } if (contentHeader) { msg.Content.Headers.Add(headerName, headerValue); } else { msg.Headers.Add(headerName, headerValue); } } using (var response = await _client.SendAsync(msg).ConfigureAwait(false)) { using (var os = context.Response.OutputStream) { context.Response.StatusCode = (int)response.StatusCode; context.Response.StatusDescription = response.ReasonPhrase; context.Response.ProtocolVersion = response.Version; foreach (var header in response.Headers) { context.Response.Headers.Add(header.Key, string.Join(", ", header.Value)); } foreach (var header in response.Content.Headers) { if (header.Key == "Content-Length") // this will be set automatically at dispose time { continue; } context.Response.Headers.Add(header.Key, string.Join(", ", header.Value)); } using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) { await stream.CopyToAsync(context.Response.OutputStream).ConfigureAwait(false); } } } } }