Exemple #1
0
        public async Task ProxyAsync_RequetsWithBodies_HasHttpContent(string method, string protocol, string headers)
        {
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Method   = method;
            httpContext.Request.Protocol = protocol;
            foreach (var header in headers.Split(';', StringSplitOptions.RemoveEmptyEntries))
            {
                var parts = header.Split(':');
                var key   = parts[0];
                var value = parts[1];
                httpContext.Request.Headers[key] = value;
            }

            var destinationPrefix = "https://localhost/";
            var sut    = Create <HttpProxy>();
            var client = MockHttpHandler.CreateClient(
                async(HttpRequestMessage request, CancellationToken cancellationToken) =>
            {
                Assert.Equal(new Version(2, 0), request.Version);
                Assert.Equal(method, request.Method.Method, StringComparer.OrdinalIgnoreCase);

                Assert.NotNull(request.Content);

                // Must consume the body
                await request.Content.CopyToAsync(Stream.Null);

                return(new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new ByteArrayContent(Array.Empty <byte>())
                });
            });
            var factoryMock = new Mock <IProxyHttpClientFactory>();

            factoryMock.Setup(f => f.CreateClient()).Returns(client);

            var proxyTelemetryContext = new ProxyTelemetryContext(
                clusterId: "be1",
                routeId: "rt1",
                destinationId: "d1");

            await sut.ProxyAsync(httpContext, destinationPrefix, Transforms.Empty, factoryMock.Object, proxyTelemetryContext, CancellationToken.None, CancellationToken.None);

            Assert.Equal(StatusCodes.Status200OK, httpContext.Response.StatusCode);
        }
Exemple #2
0
        public async Task ProxyAsync_NormalRequest_Works()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Method      = "POST";
            httpContext.Request.Scheme      = "https";
            httpContext.Request.Host        = new HostString("example.com");
            httpContext.Request.Path        = "/api/test";
            httpContext.Request.QueryString = new QueryString("?a=b&c=d");
            httpContext.Request.Headers.Add(":host", "example.com");
            httpContext.Request.Headers.Add("x-ms-request-test", "request");
            httpContext.Request.Headers.Add("Content-Language", "requestLanguage");
            httpContext.Request.Body = StringToStream("request content");

            var proxyResponseStream = new MemoryStream();

            httpContext.Response.Body = proxyResponseStream;

            var targetUri = new Uri("https://localhost:123/a/b/api/test");
            var sut       = Create <HttpProxy>();
            var client    = MockHttpHandler.CreateClient(
                async(HttpRequestMessage request, CancellationToken cancellationToken) =>
            {
                await Task.Yield();

                request.Version.Should().BeEquivalentTo(new Version(2, 0));
                request.Method.Should().Be(HttpMethod.Post);
                request.RequestUri.Should().Be(targetUri);
                request.Headers.GetValues("x-ms-request-test").Should().BeEquivalentTo("request");

                request.Content.Should().NotBeNull();
                request.Content.Headers.GetValues("Content-Language").Should().BeEquivalentTo("requestLanguage");

                var capturedRequestContent = new MemoryStream();

                // Use CopyToAsync as this is what HttpClient and friends use internally
                await request.Content.CopyToAsync(capturedRequestContent);
                capturedRequestContent.Position = 0;
                var capturedContentText         = StreamToString(capturedRequestContent);
                capturedContentText.Should().Be("request content");

                var response          = new HttpResponseMessage((HttpStatusCode)234);
                response.ReasonPhrase = "Test Reason Phrase";
                response.Headers.TryAddWithoutValidation("x-ms-response-test", "response");
                response.Content = new StreamContent(StringToStream("response content"));
                response.Content.Headers.TryAddWithoutValidation("Content-Language", "responseLanguage");
                return(response);
            });
            var factoryMock = new Mock <IProxyHttpClientFactory>();

            factoryMock.Setup(f => f.CreateNormalClient()).Returns(client);

            var proxyTelemetryContext = new ProxyTelemetryContext(
                backendId: "be1",
                routeId: "rt1",
                endpointId: "ep1");

            // Act
            await sut.ProxyAsync(httpContext, targetUri, factoryMock.Object, proxyTelemetryContext, CancellationToken.None, CancellationToken.None);

            // Assert
            httpContext.Response.StatusCode.Should().Be(234);
            var reasonPhrase = httpContext.Features.Get <IHttpResponseFeature>().ReasonPhrase;

            reasonPhrase.Should().Be("Test Reason Phrase");
            httpContext.Response.Headers["x-ms-response-test"].Should().BeEquivalentTo("response");
            httpContext.Response.Headers["Content-Language"].Should().BeEquivalentTo("responseLanguage");

            proxyResponseStream.Position = 0;
            var proxyResponseText = StreamToString(proxyResponseStream);

            proxyResponseText.Should().Be("response content");
        }
Exemple #3
0
        public async Task ProxyAsync_UpgradableRequestFailsToUpgrade_ProxiesResponse()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Method      = "GET";
            httpContext.Request.Scheme      = "https";
            httpContext.Request.Host        = new HostString("example.com");
            httpContext.Request.Path        = "/api/test";
            httpContext.Request.QueryString = new QueryString("?a=b&c=d");
            httpContext.Request.Headers.Add(":host", "example.com");
            httpContext.Request.Headers.Add("x-ms-request-test", "request");

            var proxyResponseStream = new MemoryStream();

            httpContext.Response.Body = proxyResponseStream;

            var upgradeFeatureMock = new Mock <IHttpUpgradeFeature>(MockBehavior.Strict);

            upgradeFeatureMock.SetupGet(u => u.IsUpgradableRequest).Returns(true);
            httpContext.Features.Set(upgradeFeatureMock.Object);

            var targetUri = new Uri("https://localhost:123/a/b/api/test?a=b&c=d");
            var sut       = Create <HttpProxy>();
            var client    = MockHttpHandler.CreateClient(
                async(HttpRequestMessage request, CancellationToken cancellationToken) =>
            {
                await Task.Yield();

                request.Version.Should().BeEquivalentTo(new Version(1, 1));
                request.Method.Should().Be(HttpMethod.Get);
                request.RequestUri.Should().Be(targetUri);
                request.Headers.GetValues("x-ms-request-test").Should().BeEquivalentTo("request");

                request.Content.Should().BeNull();

                var response          = new HttpResponseMessage((HttpStatusCode)234);
                response.ReasonPhrase = "Test Reason Phrase";
                response.Headers.TryAddWithoutValidation("x-ms-response-test", "response");
                response.Content = new StreamContent(StringToStream("response content"));
                response.Content.Headers.TryAddWithoutValidation("Content-Language", "responseLanguage");
                return(response);
            });
            var factoryMock = new Mock <IProxyHttpClientFactory>();

            factoryMock.Setup(f => f.CreateUpgradableClient()).Returns(client);

            var proxyTelemetryContext = new ProxyTelemetryContext(
                backendId: "be1",
                routeId: "rt1",
                endpointId: "ep1");

            // Act
            await sut.ProxyAsync(httpContext, targetUri, factoryMock.Object, proxyTelemetryContext, CancellationToken.None, CancellationToken.None);

            // Assert
            httpContext.Response.StatusCode.Should().Be(234);
            var reasonPhrase = httpContext.Features.Get <IHttpResponseFeature>().ReasonPhrase;

            reasonPhrase.Should().Be("Test Reason Phrase");
            httpContext.Response.Headers["x-ms-response-test"].Should().BeEquivalentTo("response");
            httpContext.Response.Headers["Content-Language"].Should().BeEquivalentTo("responseLanguage");

            proxyResponseStream.Position = 0;
            var proxyResponseText = StreamToString(proxyResponseStream);

            proxyResponseText.Should().Be("response content");
        }
Exemple #4
0
        public async Task ProxyAsync_UpgradableRequest_Works()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Method      = "GET";
            httpContext.Request.Scheme      = "https";
            httpContext.Request.Host        = new HostString("example.com");
            httpContext.Request.Path        = "/api/test";
            httpContext.Request.QueryString = new QueryString("?a=b&c=d");
            httpContext.Request.Headers.Add(":host", "example.com");
            httpContext.Request.Headers.Add("x-ms-request-test", "request");

            var downstreamStream = new DuplexStream(
                readStream: StringToStream("request content"),
                writeStream: new MemoryStream());
            DuplexStream upstreamStream = null;

            var upgradeFeatureMock = new Mock <IHttpUpgradeFeature>();

            upgradeFeatureMock.SetupGet(u => u.IsUpgradableRequest).Returns(true);
            upgradeFeatureMock.Setup(u => u.UpgradeAsync()).ReturnsAsync(downstreamStream);
            httpContext.Features.Set(upgradeFeatureMock.Object);

            var targetUri = new Uri("https://localhost:123/a/b/api/test?a=b&c=d");
            var sut       = Create <HttpProxy>();
            var client    = MockHttpHandler.CreateClient(
                async(HttpRequestMessage request, CancellationToken cancellationToken) =>
            {
                await Task.Yield();

                request.Version.Should().BeEquivalentTo(new Version(1, 1));
                request.Method.Should().Be(HttpMethod.Get);
                request.RequestUri.Should().Be(targetUri);
                request.Headers.GetValues("x-ms-request-test").Should().BeEquivalentTo("request");

                request.Content.Should().BeNull();

                var response = new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
                response.Headers.TryAddWithoutValidation("x-ms-response-test", "response");
                upstreamStream = new DuplexStream(
                    readStream: StringToStream("response content"),
                    writeStream: new MemoryStream());
                response.Content = new RawStreamContent(upstreamStream);
                return(response);
            });
            var factoryMock = new Mock <IProxyHttpClientFactory>();

            factoryMock.Setup(f => f.CreateUpgradableClient()).Returns(client);

            var proxyTelemetryContext = new ProxyTelemetryContext(
                backendId: "be1",
                routeId: "rt1",
                endpointId: "ep1");

            // Act
            await sut.ProxyAsync(httpContext, targetUri, factoryMock.Object, proxyTelemetryContext, CancellationToken.None, CancellationToken.None);

            // Assert
            httpContext.Response.StatusCode.Should().Be(StatusCodes.Status101SwitchingProtocols);
            httpContext.Response.Headers["x-ms-response-test"].Should().BeEquivalentTo("response");

            downstreamStream.WriteStream.Position = 0;
            var returnedToDownstream = StreamToString(downstreamStream.WriteStream);

            returnedToDownstream.Should().Be("response content");

            upstreamStream.Should().NotBeNull();
            upstreamStream.WriteStream.Position = 0;
            var sentToUpstream = StreamToString(upstreamStream.WriteStream);

            sentToUpstream.Should().Be("request content");
        }
Exemple #5
0
        public async Task ProxyAsync_UpgradableRequestFailsToUpgrade_ProxiesResponse()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Method      = "GET";
            httpContext.Request.Scheme      = "https";
            httpContext.Request.Host        = new HostString("example.com");
            httpContext.Request.Path        = "/api/test";
            httpContext.Request.QueryString = new QueryString("?a=b&c=d");
            httpContext.Request.Headers.Add(":host", "example.com");
            httpContext.Request.Headers.Add("x-ms-request-test", "request");

            // TODO: https://github.com/microsoft/reverse-proxy/issues/255
            httpContext.Request.Headers.Add("Upgrade", "WebSocket");

            var proxyResponseStream = new MemoryStream();

            httpContext.Response.Body = proxyResponseStream;

            var upgradeFeatureMock = new Mock <IHttpUpgradeFeature>(MockBehavior.Strict);

            upgradeFeatureMock.SetupGet(u => u.IsUpgradableRequest).Returns(true);
            httpContext.Features.Set(upgradeFeatureMock.Object);

            var destinationPrefix = "https://localhost:123/a/b/";
            var targetUri         = "https://localhost:123/a/b/api/test?a=b&c=d";
            var sut    = Create <HttpProxy>();
            var client = MockHttpHandler.CreateClient(
                async(HttpRequestMessage request, CancellationToken cancellationToken) =>
            {
                await Task.Yield();

                Assert.Equal(new Version(1, 1), request.Version);
                Assert.Equal(HttpMethod.Get, request.Method);
                Assert.Equal(targetUri, request.RequestUri.AbsoluteUri);
                Assert.Contains("request", request.Headers.GetValues("x-ms-request-test"));

                Assert.Null(request.Content);

                var response          = new HttpResponseMessage((HttpStatusCode)234);
                response.ReasonPhrase = "Test Reason Phrase";
                response.Headers.TryAddWithoutValidation("x-ms-response-test", "response");
                response.Content = new StreamContent(StringToStream("response content"));
                response.Content.Headers.TryAddWithoutValidation("Content-Language", "responseLanguage");
                return(response);
            });
            var factoryMock = new Mock <IProxyHttpClientFactory>();

            factoryMock.Setup(f => f.CreateClient()).Returns(client);

            var proxyTelemetryContext = new ProxyTelemetryContext(
                clusterId: "be1",
                routeId: "rt1",
                destinationId: "d1");

            // Act
            await sut.ProxyAsync(httpContext, destinationPrefix, Transforms.Empty, factoryMock.Object, proxyTelemetryContext, CancellationToken.None, CancellationToken.None);

            // Assert
            Assert.Equal(234, httpContext.Response.StatusCode);
            var reasonPhrase = httpContext.Features.Get <IHttpResponseFeature>().ReasonPhrase;

            Assert.Equal("Test Reason Phrase", reasonPhrase);
            Assert.Contains("response", httpContext.Response.Headers["x-ms-response-test"].ToArray());
            Assert.Contains("responseLanguage", httpContext.Response.Headers["Content-Language"].ToArray());

            proxyResponseStream.Position = 0;
            var proxyResponseText = StreamToString(proxyResponseStream);

            Assert.Equal("response content", proxyResponseText);
        }