예제 #1
0
    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);
                    }
                }
            }
        }
    }