Exemplo n.º 1
0
    private HttpContext GetContext(ClusterState cluster, int selectedDestination, IForwarderErrorFeature error)
    {
        var context = new DefaultHttpContext();

        context.Features.Set(GetProxyFeature(cluster, cluster.DestinationsState.AllDestinations[selectedDestination]));
        context.Features.Set(error);
        return(context);
    }
Exemplo n.º 2
0
        public async Task ProxyAsync_ResponseWithEncodedHeaderValue(string headerValue, string encodingName)
        {
            var encoding = Encoding.GetEncoding(encodingName);

            var tcpListener = new TcpListener(IPAddress.Loopback, 0);

            tcpListener.Start();
            var destinationTask = Task.Run(async() =>
            {
                using var tcpClient    = await tcpListener.AcceptTcpClientAsync();
                await using var stream = tcpClient.GetStream();
                var buffer             = new byte[4096];
                var requestBuilder     = new StringBuilder();
                while (true)
                {
                    var count = await stream.ReadAsync(buffer);
                    if (count == 0)
                    {
                        break;
                    }

                    requestBuilder.Append(encoding.GetString(buffer, 0, count));

                    // End of the request
                    if (requestBuilder.Length >= 4 &&
                        requestBuilder[^ 4] == '\r' && requestBuilder[^ 3] == '\n' &&
                        requestBuilder[^ 2] == '\r' && requestBuilder[^ 1] == '\n')
                    {
                        break;
                    }
                }

                await stream.WriteAsync(Encoding.ASCII.GetBytes($"HTTP/1.1 200 OK\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Content-Length: 0\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Connection: close\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Test-Extra: pingu\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Location: "));
                await stream.WriteAsync(encoding.GetBytes(headerValue));
                await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
            });

            IForwarderErrorFeature proxyError = null;
            Exception unhandledError          = null;

            using var proxy = TestEnvironment.CreateProxy(HttpProtocols.Http1, false, false, encoding, "cluster1", $"http://{tcpListener.LocalEndpoint}",
                                                          proxyServices => { },
                                                          proxyBuilder => { },
                                                          proxyApp =>
            {
                proxyApp.Use(async(context, next) =>
                {
                    try
                    {
                        await next();
                        proxyError = context.Features.Get <IForwarderErrorFeature>();
                    }
                    catch (Exception ex)
                    {
                        unhandledError = ex;
                        throw;
                    }
                });
            },
                                                          (c, r) => (c, r));

            await proxy.StartAsync();

            try
            {
                using var httpClient = new HttpClient();
                using var response   = await httpClient.GetAsync(proxy.GetAddress());

                Assert.NotNull(proxyError);
                Assert.Equal(ForwarderError.ResponseHeaders, proxyError.Error);
                var ioe = Assert.IsType <InvalidOperationException>(proxyError.Exception);
                Assert.StartsWith("Invalid non-ASCII or control character in header: ", ioe.Message);
                Assert.Null(unhandledError);

                Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode);

                Assert.False(response.Headers.TryGetValues(HeaderNames.Location, out _));
                Assert.False(response.Headers.TryGetValues("Test-Extra", out _));

                Assert.True(destinationTask.IsCompleted);
                await destinationTask;
            }
            finally
            {
                await proxy.StopAsync();

                tcpListener.Stop();
            }
        }
Exemplo n.º 3
0
        public async Task ProxyAsync_EmptyRequestHeader_Proxied()
        {
            var refererReceived = new TaskCompletionSource <StringValues>(TaskCreationOptions.RunContinuationsAsynchronously);
            var customReceived  = new TaskCompletionSource <StringValues>(TaskCreationOptions.RunContinuationsAsynchronously);

            IForwarderErrorFeature proxyError = null;
            Exception unhandledError          = null;

            var test = new TestEnvironment(
                context =>
            {
                if (context.Request.Headers.TryGetValue(HeaderNames.Referer, out var header))
                {
                    refererReceived.SetResult(header);
                }
                else
                {
                    refererReceived.SetException(new Exception($"Missing '{HeaderNames.Referer}' header in request"));
                }

                if (context.Request.Headers.TryGetValue("custom", out header))
                {
                    customReceived.SetResult(header);
                }
                else
                {
                    customReceived.SetException(new Exception($"Missing 'custom' header in request"));
                }


                return(Task.CompletedTask);
            },
                proxyBuilder => { },
                proxyApp =>
            {
                proxyApp.Use(async(context, next) =>
                {
                    try
                    {
                        Assert.True(context.Request.Headers.TryGetValue(HeaderNames.Referer, out var header));
                        var value = Assert.Single(header);
                        Assert.True(StringValues.IsNullOrEmpty(value));

                        Assert.True(context.Request.Headers.TryGetValue("custom", out header));
                        value = Assert.Single(header);
                        Assert.True(StringValues.IsNullOrEmpty(value));

                        await next();
                        proxyError = context.Features.Get <IForwarderErrorFeature>();
                    }
                    catch (Exception ex)
                    {
                        unhandledError = ex;
                        throw;
                    }
                });
            },
                proxyProtocol: HttpProtocols.Http1);

            await test.Invoke(async proxyUri =>
            {
                var proxyHostUri = new Uri(proxyUri);

                using var tcpClient    = new TcpClient(proxyHostUri.Host, proxyHostUri.Port);
                await using var stream = tcpClient.GetStream();
                await stream.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Host: {proxyHostUri.Host}:{proxyHostUri.Port}\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Content-Length: 0\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Connection: close\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Referer: \r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"custom: \r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
                var buffer          = new byte[4096];
                var responseBuilder = new StringBuilder();
                while (true)
                {
                    var count = await stream.ReadAsync(buffer);
                    if (count == 0)
                    {
                        break;
                    }
                    responseBuilder.Append(Encoding.ASCII.GetString(buffer, 0, count));
                }
                var response = responseBuilder.ToString();

                Assert.Null(proxyError);
                Assert.Null(unhandledError);

                Assert.StartsWith("HTTP/1.1 200 OK", response);

                Assert.True(refererReceived.Task.IsCompleted);
                var refererHeader = await refererReceived.Task;
                var referer       = Assert.Single(refererHeader);
                Assert.True(StringValues.IsNullOrEmpty(referer));

                Assert.True(customReceived.Task.IsCompleted);
                var customHeader = await customReceived.Task;
                var custom       = Assert.Single(customHeader);
                Assert.True(StringValues.IsNullOrEmpty(custom));
            });
        }
Exemplo n.º 4
0
        public async Task ProxyAsync_EmptyResponseHeader_Proxied()
        {
            IForwarderErrorFeature proxyError = null;
            Exception unhandledError          = null;

            var test = new TestEnvironment(
                context =>
            {
                context.Response.Headers.Add(HeaderNames.Referer, "");
                context.Response.Headers.Add("custom", "");
                return(Task.CompletedTask);
            },
                proxyBuilder => { },
                proxyApp =>
            {
                proxyApp.Use(async(context, next) =>
                {
                    try
                    {
                        await next();

                        Assert.True(context.Response.Headers.TryGetValue(HeaderNames.Referer, out var header));
                        var value = Assert.Single(header);
                        Assert.True(StringValues.IsNullOrEmpty(value));

                        Assert.True(context.Response.Headers.TryGetValue("custom", out header));
                        value = Assert.Single(header);
                        Assert.True(StringValues.IsNullOrEmpty(value));

                        proxyError = context.Features.Get <IForwarderErrorFeature>();
                    }
                    catch (Exception ex)
                    {
                        unhandledError = ex;
                        throw;
                    }
                });
            },
                proxyProtocol: HttpProtocols.Http1);

            await test.Invoke(async proxyUri =>
            {
                var proxyHostUri = new Uri(proxyUri);

                using var tcpClient    = new TcpClient(proxyHostUri.Host, proxyHostUri.Port);
                await using var stream = tcpClient.GetStream();
                await stream.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Host: {proxyHostUri.Host}:{proxyHostUri.Port}\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Content-Length: 0\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes($"Connection: close\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
                await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
                var buffer          = new byte[4096];
                var responseBuilder = new StringBuilder();
                while (true)
                {
                    var count = await stream.ReadAsync(buffer);
                    if (count == 0)
                    {
                        break;
                    }
                    responseBuilder.Append(Encoding.ASCII.GetString(buffer, 0, count));
                }
                var response = responseBuilder.ToString();

                Assert.Null(proxyError);
                Assert.Null(unhandledError);

                var lines = response.Split("\r\n");
                Assert.Equal("HTTP/1.1 200 OK", lines[0]);
                // Order varies across vesions.
                // Assert.Equal("Content-Length: 0", lines[1]);
                // Assert.Equal("Connection: close", lines[2]);
                // Assert.StartsWith("Date: ", lines[3]);
                // Assert.Equal("Server: Kestrel", lines[4]);
                Assert.Equal("Referer: ", lines[5]);
                Assert.Equal("custom: ", lines[6]);
                Assert.Equal("", lines[7]);
            });
        }
Exemplo n.º 5
0
    public async Task MultiValueResponseHeaders(string headerName, string[] values, string[] expectedValues)
    {
        IForwarderErrorFeature proxyError = null;
        Exception unhandledError          = null;

        var test = new TestEnvironment(
            context =>
        {
            Assert.True(context.Response.Headers.TryAdd(headerName, values));
            return(Task.CompletedTask);
        },
            proxyBuilder => { },
            proxyApp =>
        {
            proxyApp.Use(async(context, next) =>
            {
                try
                {
                    await next();

                    Assert.True(context.Response.Headers.TryGetValue(headerName, out var header));
                    Assert.Equal(values.Length, header.Count);
                    for (var i = 0; i < values.Length; ++i)
                    {
                        Assert.Equal(values[i], header[i]);
                    }

                    proxyError = context.Features.Get <IForwarderErrorFeature>();
                }
                catch (Exception ex)
                {
                    unhandledError = ex;
                    throw;
                }
            });
        },
            proxyProtocol: HttpProtocols.Http1);

        await test.Invoke(async proxyUri =>
        {
            var proxyHostUri = new Uri(proxyUri);

            using var tcpClient    = new TcpClient(proxyHostUri.Host, proxyHostUri.Port);
            await using var stream = tcpClient.GetStream();
            await stream.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n"));
            await stream.WriteAsync(Encoding.ASCII.GetBytes($"Host: {proxyHostUri.Host}:{proxyHostUri.Port}\r\n"));
            await stream.WriteAsync(Encoding.ASCII.GetBytes($"Content-Length: 0\r\n"));
            await stream.WriteAsync(Encoding.ASCII.GetBytes($"Connection: close\r\n"));
            await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
            await stream.WriteAsync(Encoding.ASCII.GetBytes("\r\n"));
            var response = await new StreamReader(stream).ReadToEndAsync();

            Assert.Null(proxyError);
            Assert.Null(unhandledError);

            var lines = response.Split("\r\n");
            Assert.Equal("HTTP/1.1 200 OK", lines[0]);
            foreach (var expected in expectedValues)
            {
                Assert.Contains($"{headerName}: {expected}", lines);
            }
        });
    }
    public async Task RequestDelegated()
    {
        IHttpSysDelegator      delegator  = null;
        IForwarderErrorFeature proxyError = null;
        Exception unhandledError          = null;
        var       expectedRepsone         = "Hello World!";
        var       queueName = nameof(HttpSysDelegationTests) + Random.Shared.Next().ToString("x8");
        string    urlPrefix = null;

        var test = new HttpSysTestEnvironment(
            destinationServices => { },
            destinationHttpSysOptions => destinationHttpSysOptions.RequestQueueName = queueName,
            destinationApp => destinationApp.Run(context => context.Response.WriteAsync(expectedRepsone)),
            proxyServices => { },
            proxyBuilder => { },
            proxyApp =>
        {
            delegator = proxyApp.ApplicationServices.GetRequiredService <IHttpSysDelegator>();
            proxyApp.Use(async(context, next) =>
            {
                try
                {
                    await next();
                    proxyError = context.Features.Get <IForwarderErrorFeature>();
                }
                catch (Exception ex)
                {
                    unhandledError = ex;
                    throw;
                }
            });
        },
            proxyPipeline =>
        {
            proxyPipeline.UseHttpSysDelegation();
        },
            (cluster, route) =>
        {
            urlPrefix       = cluster.Destinations.First().Value.Address;
            var destination = new DestinationConfig()
            {
                Address  = urlPrefix,
                Metadata = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase)
                {
                    { DelegationExtensions.HttpSysDelegationQueueMetadataKey, queueName },
                },
            };

            cluster = new ClusterConfig
            {
                ClusterId    = cluster.ClusterId,
                Destinations = new Dictionary <string, DestinationConfig>(StringComparer.OrdinalIgnoreCase)
                {
                    { "destination1", destination },
                },
            };

            return(cluster, route);
        });

        await test.Invoke(async proxyUri =>
        {
            using var httpClient = new HttpClient();
            var response         = await httpClient.GetStringAsync(proxyUri);

            Assert.Null(proxyError);
            Assert.Null(unhandledError);
            Assert.Equal(expectedRepsone, response);

            Assert.NotNull(delegator);
            delegator.ResetQueue(queueName, urlPrefix);

            response = await httpClient.GetStringAsync(proxyUri);

            Assert.Null(proxyError);
            Assert.Null(unhandledError);
            Assert.Equal(expectedRepsone, response);
        });
    }