Beispiel #1
0
        public async Task DoesNotHangOnConnectionCloseRequest()
        {
            var builder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls("http://127.0.0.1:0")
                .Configure(app =>
                {
                    app.Run(async context =>
                    {
                        await context.Response.WriteAsync("hello, world");
                    });
                });
            })
                          .ConfigureServices(AddTestLogging);

            using (var host = builder.Build())
                using (var client = new HttpClient())
                {
                    await host.StartAsync();

                    client.DefaultRequestHeaders.Connection.Clear();
                    client.DefaultRequestHeaders.Connection.Add("close");

                    var response = await client.GetAsync($"http://127.0.0.1:{host.GetPort()}/");

                    response.EnsureSuccessStatusCode();

                    await host.StopAsync();
                }
        }
Beispiel #2
0
    private async Task ListenLocalhost_Success(string[] testUrls, int testPort = 0)
    {
        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                options.ListenLocalhost(testPort);
            })
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            foreach (var testUrl in testUrls.Select(testUrl => $"{testUrl}:{(testPort == 0 ? host.GetPort() : testPort)}"))
            {
                var response = await HttpClientSlim.GetStringAsync(testUrl, validateCertificate : false);

                // Compare the response with Uri.ToString(), rather than testUrl directly.
                // Required to handle IPv6 addresses with zone index, like "fe80::3%1"
                Assert.Equal(new Uri(testUrl).ToString(), response);
            }

            await host.StopAsync();
        }
    }
Beispiel #3
0
    private async Task RegisterDefaultServerAddresses_Success(IEnumerable <string> addresses, bool mockHttps = false)
    {
        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                if (mockHttps)
                {
                    options.DefaultCertificate = TestResources.GetTestCertificate();
                }
            })
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            Assert.Equal(5000, host.GetPort());

            Assert.Single(LogMessages, log => log.LogLevel == LogLevel.Debug &&
                          (string.Equals(CoreStrings.FormatBindingToDefaultAddress(Constants.DefaultServerAddress), log.Message, StringComparison.Ordinal) ||
                           string.Equals(CoreStrings.FormatBindingToDefaultAddress(Constants.DefaultServerAddress), log.Message, StringComparison.Ordinal)));

            foreach (var address in addresses)
            {
                Assert.Equal(new Uri(address).ToString(), await HttpClientSlim.GetStringAsync(address, validateCertificate: false));
            }

            await host.StopAsync();
        }
    }
Beispiel #4
0
    public async Task EndpointDefaultsConfig_CanSetProtocolForUrlsConfig(string input, HttpProtocols expected)
    {
        KestrelServerOptions capturedOptions = null;
        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
                {
                    new KeyValuePair <string, string>("EndpointDefaults:Protocols", input),
                }).Build();
                options.Configure(config);

                capturedOptions = options;
            })
            .UseUrls("http://127.0.0.1:0")
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            Assert.Single(capturedOptions.OptionsInUse);
            Assert.Equal(expected, capturedOptions.OptionsInUse[0].Protocols);
            await host.StopAsync();
        }
    }
Beispiel #5
0
        public async Task AbortingTheConnectionSendsFIN()
        {
            var builder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls("http://127.0.0.1:0")
                .Configure(app => app.Run(context =>
                {
                    context.Abort();
                    return(Task.CompletedTask);
                }));
            })
                          .ConfigureServices(AddTestLogging);

            using (var host = builder.Build())
            {
                await host.StartAsync();

                using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort()));
                    socket.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n"));
                    int result = socket.Receive(new byte[32]);
                    Assert.Equal(0, result);
                }

                await host.StopAsync();
            }
        }
Beispiel #6
0
    public async Task DoesNotOverrideDirectConfigurationWithIServerAddressesFeature_IfAddressesEmpty()
    {
        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
                {
                    listenOptions.UseHttps(TestResources.GetTestCertificate());
                });
            })
            .PreferHostingUrls(true)
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            var port = host.GetPort();

            // If this isn't working properly, we'll not get the HTTPS endpoint defined in UseKestrel.
            var serverAddresses = host.Services.GetRequiredService <IServer>().Features.Get <IServerAddressesFeature>().Addresses;
            Assert.Equal(1, serverAddresses.Count);
            var endPointAddress = $"https://127.0.0.1:{port}";
            Assert.Equal(serverAddresses.First(), endPointAddress);

            Assert.Equal(new Uri(endPointAddress).ToString(), await HttpClientSlim.GetStringAsync(endPointAddress, validateCertificate: false));

            await host.StopAsync();
        }
    }
Beispiel #7
0
    public async Task ThrowsWhenBindingToIPv6AddressInUse()
    {
        ThrowOnCriticalErrors = false;

        using (var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
        {
            socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, 0));
            socket.Listen(0);
            var port = ((IPEndPoint)socket.LocalEndPoint).Port;

            var hostBuilder = TransportSelector.GetHostBuilder()
                              .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls($"http://[::1]:{port}")
                .Configure(ConfigureEchoAddress);
            })
                              .ConfigureServices(AddTestLogging);

            using (var host = hostBuilder.Build())
            {
                var exception       = Assert.Throws <IOException>(() => host.Start());
                var expectedMessage = CoreStrings.FormatEndpointAlreadyInUse($"http://[::1]:{port}");
                Assert.Equal(expectedMessage, exception.Message);
                Assert.Equal(0, LogMessages.Count(log => log.LogLevel == LogLevel.Critical &&
                                                  log.Exception is null &&
                                                  log.Message.EndsWith(expectedMessage, StringComparison.Ordinal)));

                await host.StopAsync();
            }
        }
    }
Beispiel #8
0
        public async Task LargeDownload()
        {
            var hostBuilder = TransportSelector.GetHostBuilder()
                              .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls("http://127.0.0.1:0/")
                .Configure(app =>
                {
                    app.Run(async context =>
                    {
                        var bytes = new byte[1024];
                        for (int i = 0; i < bytes.Length; i++)
                        {
                            bytes[i] = (byte)i;
                        }

                        context.Response.ContentLength = bytes.Length * 1024;

                        for (int i = 0; i < 1024; i++)
                        {
                            await context.Response.BodyWriter.WriteAsync(new Memory <byte>(bytes, 0, bytes.Length));
                        }
                    });
                });
            })
                              .ConfigureServices(AddTestLogging);

            using (var host = hostBuilder.Build())
            {
                await host.StartAsync();

                using (var client = new HttpClient())
                {
                    var response = await client.GetAsync($"http://127.0.0.1:{host.GetPort()}/");

                    response.EnsureSuccessStatusCode();
                    var responseBody = await response.Content.ReadAsStreamAsync();

                    // Read the full response body
                    var total = 0;
                    var bytes = new byte[1024];
                    var count = await responseBody.ReadAsync(bytes, 0, bytes.Length);

                    while (count > 0)
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Assert.Equal(total % 256, bytes[i]);
                            total++;
                        }
                        count = await responseBody.ReadAsync(bytes, 0, bytes.Length);
                    }
                }
                await host.StopAsync();
            }
        }
Beispiel #9
0
        public async Task ThrowsOnReadAfterConnectionError()
        {
            var requestStarted          = new SemaphoreSlim(0);
            var connectionReset         = new SemaphoreSlim(0);
            var appDone                 = new SemaphoreSlim(0);
            var expectedExceptionThrown = false;

            var builder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls("http://127.0.0.1:0")
                .Configure(app => app.Run(async context =>
                {
                    requestStarted.Release();
                    Assert.True(await connectionReset.WaitAsync(_semaphoreWaitTimeout));

                    try
                    {
                        await context.Request.Body.ReadAsync(new byte[1], 0, 1);
                    }
                    catch (ConnectionResetException)
                    {
                        expectedExceptionThrown = true;
                    }

                    appDone.Release();
                }));
            })
                          .ConfigureServices(AddTestLogging);

            using (var host = builder.Build())
            {
                await host.StartAsync();

                using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort()));
                    socket.LingerState = new LingerOption(true, 0);
                    socket.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\nContent-Length: 1\r\n\r\n"));
                    Assert.True(await requestStarted.WaitAsync(_semaphoreWaitTimeout));
                }

                connectionReset.Release();

                Assert.True(await appDone.WaitAsync(_semaphoreWaitTimeout));
                Assert.True(expectedExceptionThrown);

                await host.StopAsync();
            }
        }
Beispiel #10
0
    public async Task CanRebindToMultipleEndPoints()
    {
        var port = GetNextPort();
        var ipv4endPointAddress = $"http://127.0.0.1:{port}/";
        var ipv6endPointAddress = $"http://[::1]:{port}/";

        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                options.Listen(IPAddress.Loopback, port);
                options.Listen(IPAddress.IPv6Loopback, port);
            })
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            Assert.Equal(ipv4endPointAddress, await HttpClientSlim.GetStringAsync(ipv4endPointAddress));
            Assert.Equal(ipv6endPointAddress, await HttpClientSlim.GetStringAsync(ipv6endPointAddress));

            await host.StopAsync();
        }

        hostBuilder = TransportSelector.GetHostBuilder()
                      .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                options.Listen(IPAddress.Loopback, port);
                options.Listen(IPAddress.IPv6Loopback, port);
            })
            .Configure(ConfigureEchoAddress);
        });

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            Assert.Equal(ipv4endPointAddress, await HttpClientSlim.GetStringAsync(ipv4endPointAddress));
            Assert.Equal(ipv6endPointAddress, await HttpClientSlim.GetStringAsync(ipv6endPointAddress));

            await host.StopAsync();
        }
    }
Beispiel #11
0
    public TestServer(RequestDelegate app, TestServiceContext context, Action <KestrelServerOptions> configureKestrel, Action <IServiceCollection> configureServices)
    {
        _app    = app;
        Context = context;

        _host = TransportSelector.GetHostBuilder(context.MemoryPoolFactory, context.ServerOptions.Limits.MaxRequestBufferSize)
                .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                configureKestrel(options);
                _listenOptions = options.ListenOptions.First();
            })
            .ConfigureServices(services =>
            {
                services.AddSingleton <IStartup>(this);
                services.AddSingleton(context.LoggerFactory);
                services.AddSingleton <IServer>(sp =>
                {
                    // Manually configure options on the TestServiceContext.
                    // We're doing this so we can use the same instance that was passed in
                    var configureOptions = sp.GetServices <IConfigureOptions <KestrelServerOptions> >();
                    foreach (var c in configureOptions)
                    {
                        c.Configure(context.ServerOptions);
                    }

                    return(new KestrelServerImpl(sp.GetRequiredService <IConnectionListenerFactory>(), context));
                });
                configureServices(services);
            })
            .UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).Assembly.FullName)
            .UseSetting(WebHostDefaults.ShutdownTimeoutKey, TestConstants.DefaultTimeout.TotalSeconds.ToString(CultureInfo.InvariantCulture))
            .Configure(app => { app.Run(_app); });
        })
                .ConfigureServices(services =>
        {
            services.Configure <HostOptions>(option =>
            {
                option.ShutdownTimeout = TestConstants.DefaultTimeout;
            });
        })
                .Build();

        _host.Start();

        Context.Log.LogDebug($"TestServer is listening on port {Port}");
    }
 private IHost CreateWebHost(EndPoint endpoint, Action <SocketTransportOptions> configureSocketOptions) =>
 TransportSelector.GetHostBuilder()
 .ConfigureWebHost(
     webHostBuilder =>
 {
     webHostBuilder
     .UseSockets(configureSocketOptions)
     .UseKestrel(options => options.Listen(endpoint))
     .Configure(
         app => app.Run(ctx => ctx.Response.WriteAsync("Hello World"))
         );
 }
     )
 .ConfigureServices(AddTestLogging)
 .Build();
Beispiel #13
0
        private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress)
        {
            var builder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls($"http://{registerAddress}:0")
                .Configure(app =>
                {
                    app.Run(async context =>
                    {
                        var connection = context.Connection;
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(new
                        {
                            RemoteIPAddress = connection.RemoteIpAddress?.ToString(),
                            RemotePort      = connection.RemotePort,
                            LocalIPAddress  = connection.LocalIpAddress?.ToString(),
                            LocalPort       = connection.LocalPort
                        }));
                    });
                });
            })
                          .ConfigureServices(AddTestLogging);

            using (var host = builder.Build())
                using (var client = new HttpClient())
                {
                    await host.StartAsync();

                    var response = await client.GetAsync($"http://{requestAddress}:{host.GetPort()}/");

                    response.EnsureSuccessStatusCode();

                    var connectionFacts = await response.Content.ReadAsStringAsync();

                    Assert.NotEmpty(connectionFacts);

                    var facts = JsonConvert.DeserializeObject <JObject>(connectionFacts);
                    Assert.Equal(expectAddress, facts["RemoteIPAddress"].Value <string>());
                    Assert.NotEmpty(facts["RemotePort"].Value <string>());

                    await host.StopAsync();
                }
        }
Beispiel #14
0
        public async Task IgnoreNullHeaderValues(string headerName, StringValues headerValue, string expectedValue)
        {
            var hostBuilder = TransportSelector.GetHostBuilder()
                              .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls("http://127.0.0.1:0/")
                .Configure(app =>
                {
                    app.Run(async context =>
                    {
                        context.Response.Headers.Add(headerName, headerValue);

                        await context.Response.WriteAsync("");
                    });
                });
            })
                              .ConfigureServices(AddTestLogging);

            using (var host = hostBuilder.Build())
            {
                await host.StartAsync();

                using (var client = new HttpClient())
                {
                    var response = await client.GetAsync($"http://127.0.0.1:{host.GetPort()}/");

                    response.EnsureSuccessStatusCode();

                    var headers = response.Headers;

                    if (expectedValue == null)
                    {
                        Assert.False(headers.Contains(headerName));
                    }
                    else
                    {
                        Assert.True(headers.Contains(headerName));
                        Assert.Equal(headers.GetValues(headerName).Single(), expectedValue);
                    }
                }
                await host.StopAsync();
            }
        }
Beispiel #15
0
    public async Task DoesNotOverrideDirectConfigurationWithIServerAddressesFeature_IfPreferHostingUrlsFalse()
    {
        var useUrlsAddress = $"http://127.0.0.1:0";

        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
                {
                    listenOptions.UseHttps(TestResources.TestCertificatePath, "testPassword");
                });
            })
            .UseUrls($"http://127.0.0.1:0")
            .PreferHostingUrls(false)
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            var port = host.GetPort();

            // If this isn't working properly, we'll get the HTTP endpoint defined in UseUrls
            // instead of the HTTPS endpoint defined in UseKestrel.
            var serverAddresses = host.Services.GetRequiredService <IServer>().Features.Get <IServerAddressesFeature>().Addresses;
            Assert.Equal(1, serverAddresses.Count);
            var endPointAddress = $"https://127.0.0.1:{port}";
            Assert.Equal(serverAddresses.First(), endPointAddress);

            Assert.Single(LogMessages, log => log.LogLevel == LogLevel.Warning &&
                          string.Equals(CoreStrings.FormatOverridingWithKestrelOptions(useUrlsAddress),
                                        log.Message, StringComparison.Ordinal));

            Assert.Equal(new Uri(endPointAddress).ToString(), await HttpClientSlim.GetStringAsync(endPointAddress, validateCertificate: false));
            await host.StopAsync();
        }
    }
Beispiel #16
0
    private async Task RegisterAddresses_Success(string addressInput, string[] testUrls, int testPort = 0)
    {
        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(serverOptions =>
            {
                serverOptions.ConfigureHttpsDefaults(httpsOptions =>
                {
                    httpsOptions.ServerCertificate = TestResources.GetTestCertificate();
                });
            })
            .UseUrls(addressInput)
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            host.Start();

            foreach (var testUrl in testUrls.Select(testUrl => $"{testUrl}:{(testPort == 0 ? host.GetPort() : testPort)}"))
            {
                var response = await HttpClientSlim.GetStringAsync(testUrl, validateCertificate : false);

                // Filter out the scope id for IPv6, that's not sent over the wire. "fe80::3%1"
                // See https://github.com/aspnet/Common/pull/369
                var uri = new Uri(testUrl);
                if (uri.HostNameType == UriHostNameType.IPv6)
                {
                    var builder = new UriBuilder(uri);
                    var ip      = IPAddress.Parse(builder.Host);
                    builder.Host = new IPAddress(ip.GetAddressBytes()).ToString(); // Without the scope id.
                    uri          = builder.Uri;
                }
                Assert.Equal(uri.ToString(), response);
            }

            await host.StopAsync();
        }
    }
Beispiel #17
0
        public async Task CanReadAndWriteFromSocketFeatureInConnectionMiddleware()
        {
            var builder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel(options =>
                {
                    options.ListenAnyIP(0, lo =>
                    {
                        lo.Use(next =>
                        {
                            return(async connection =>
                            {
                                var socket = connection.Features.Get <IConnectionSocketFeature>().Socket;
                                Assert.NotNull(socket);

                                var buffer = new byte[4096];

                                var read = await socket.ReceiveAsync(buffer, SocketFlags.None);

                                static void ParseHttp(ReadOnlySequence <byte> data)
                                {
                                    var parser = new HttpParser <ParserHandler>();
                                    var handler = new ParserHandler();

                                    var reader = new SequenceReader <byte>(data);

                                    // Assume we can parse the HTTP request in a single buffer
                                    Assert.True(parser.ParseRequestLine(handler, ref reader));
                                    Assert.True(parser.ParseHeaders(handler, ref reader));

                                    Assert.Equal(KestrelHttpMethod.Get, handler.HttpMethod);
                                    Assert.Equal(KestrelHttpVersion.Http11, handler.HttpVersion);
                                }

                                ParseHttp(new ReadOnlySequence <byte>(buffer[0..read]));

                                await socket.SendAsync(Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n"), SocketFlags.None);
                            });
                        });
                    });
Beispiel #18
0
    public async Task ThrowsForUnsupportedAddressFromHosting(string address)
    {
        IgnoredCriticalLogExceptions.Add(typeof(InvalidOperationException));

        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel()
            .UseUrls(address)
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            Assert.Throws <InvalidOperationException>(() => host.Start());

            await host.StopAsync();
        }
    }
Beispiel #19
0
    public async Task ThrowsWhenBindingLocalhostToDynamicPort()
    {
        IgnoredCriticalLogExceptions.Add(typeof(InvalidOperationException));

        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel()
            .UseUrls("http://localhost:0")
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            Assert.Throws <InvalidOperationException>(() => host.Start());

            await host.StopAsync();
        }
    }
Beispiel #20
0
    public async Task RegisterHttpAddress_UpgradedToHttpsByConfigureEndpointDefaults()
    {
        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(serverOptions =>
            {
                serverOptions.ConfigureEndpointDefaults(listenOptions =>
                {
                    listenOptions.UseHttps(TestResources.GetTestCertificate());
                });
            })
            .UseUrls("http://127.0.0.1:0")
            .Configure(app =>
            {
                var serverAddresses = app.ServerFeatures.Get <IServerAddressesFeature>();
                app.Run(context =>
                {
                    Assert.Single(serverAddresses.Addresses);
                    return(context.Response.WriteAsync(serverAddresses.Addresses.First()));
                });
            });
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            host.Start();

            var expectedUrl = $"https://127.0.0.1:{host.GetPort()}";
            var response    = await HttpClientSlim.GetStringAsync(expectedUrl, validateCertificate : false);

            Assert.Equal(expectedUrl, response);

            await host.StopAsync();
        }
    }
Beispiel #21
0
    private async Task RegisterIPEndPoint_Success(IPEndPoint endPoint, string testUrl, int testPort = 0)
    {
        var hostBuilder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                options.Listen(endPoint, listenOptions =>
                {
                    if (testUrl.StartsWith("https", StringComparison.Ordinal))
                    {
                        listenOptions.UseHttps(TestResources.GetTestCertificate());
                    }
                });
            })
            .Configure(ConfigureEchoAddress);
        })
                          .ConfigureServices(AddTestLogging);

        using (var host = hostBuilder.Build())
        {
            await host.StartAsync();

            var testUrlWithPort = $"{testUrl}:{(testPort == 0 ? host.GetPort() : testPort)}";

            var options = ((IOptions <KestrelServerOptions>)host.Services.GetService(typeof(IOptions <KestrelServerOptions>))).Value;
            Assert.Single(options.ListenOptions);

            var response = await HttpClientSlim.GetStringAsync(testUrlWithPort, validateCertificate : false);

            // Compare the response with Uri.ToString(), rather than testUrl directly.
            // Required to handle IPv6 addresses with zone index, like "fe80::3%1"
            Assert.Equal(new Uri(testUrlWithPort).ToString(), response);

            await host.StopAsync();
        }
    }
Beispiel #22
0
        public async Task RequestAbortedTokenFiredOnClientFIN()
        {
            var appStarted     = new SemaphoreSlim(0);
            var requestAborted = new SemaphoreSlim(0);
            var builder        = TransportSelector.GetHostBuilder()
                                 .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls("http://127.0.0.1:0")
                .Configure(app => app.Run(async context =>
                {
                    appStarted.Release();

                    var token = context.RequestAborted;
                    token.Register(() => requestAborted.Release(2));
                    await requestAborted.WaitAsync().DefaultTimeout();
                }));
            })
                                 .ConfigureServices(AddTestLogging);

            using (var host = builder.Build())
            {
                await host.StartAsync();

                using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort()));
                    socket.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n"));
                    await appStarted.WaitAsync();

                    socket.Shutdown(SocketShutdown.Send);
                    await requestAborted.WaitAsync().DefaultTimeout();
                }

                await host.StopAsync();
            }
        }
Beispiel #23
0
        public async Task SocketTransportExposesSocketsFeature()
        {
            var builder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel()
                .UseUrls("http://127.0.0.1:0")
                .Configure(app =>
                {
                    app.Run(context =>
                    {
                        var socket = context.Features.Get <IConnectionSocketFeature>().Socket;
                        Assert.NotNull(socket);
                        Assert.Equal(ProtocolType.Tcp, socket.ProtocolType);
                        var ip = (IPEndPoint)socket.RemoteEndPoint;
                        Assert.Equal(ip.Address, context.Connection.RemoteIpAddress);
                        Assert.Equal(ip.Port, context.Connection.RemotePort);

                        return(Task.CompletedTask);
                    });
                });
            })
                          .ConfigureServices(AddTestLogging);

            using var host   = builder.Build();
            using var client = new HttpClient();

            await host.StartAsync();

            var response = await client.GetAsync($"http://127.0.0.1:{host.GetPort()}/");

            response.EnsureSuccessStatusCode();

            await host.StopAsync();
        }
Beispiel #24
0
        public async Task TestUnixDomainSocket()
        {
            var path = Path.GetTempFileName();

            Delete(path);

            try
            {
                var serverConnectionCompletedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

                async Task EchoServer(ConnectionContext connection)
                {
                    // For graceful shutdown
                    var notificationFeature = connection.Features.Get <IConnectionLifetimeNotificationFeature>();

                    try
                    {
                        while (true)
                        {
                            var result = await connection.Transport.Input.ReadAsync(notificationFeature.ConnectionClosedRequested);

                            if (result.IsCompleted)
                            {
                                Logger.LogDebug("Application receive loop ending for connection {connectionId}.", connection.ConnectionId);
                                break;
                            }

                            await connection.Transport.Output.WriteAsync(result.Buffer.ToArray());

                            connection.Transport.Input.AdvanceTo(result.Buffer.End);
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        Logger.LogDebug("Graceful shutdown triggered for {connectionId}.", connection.ConnectionId);
                    }
                    finally
                    {
                        serverConnectionCompletedTcs.TrySetResult();
                    }
                }

                var hostBuilder = TransportSelector.GetHostBuilder()
                                  .ConfigureWebHost(webHostBuilder =>
                {
                    webHostBuilder
                    .UseKestrel(o =>
                    {
                        o.ListenUnixSocket(path, builder =>
                        {
                            builder.Run(EchoServer);
                        });
                    })
                    .Configure(c => { });
                })
                                  .ConfigureServices(AddTestLogging);

                using (var host = hostBuilder.Build())
                {
                    await host.StartAsync().DefaultTimeout();

                    using (var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
                    {
                        await socket.ConnectAsync(new UnixDomainSocketEndPoint(path)).DefaultTimeout();

                        var data = Encoding.ASCII.GetBytes("Hello World");
                        await socket.SendAsync(data, SocketFlags.None).DefaultTimeout();

                        var buffer = new byte[data.Length];
                        var read   = 0;
                        while (read < data.Length)
                        {
                            var bytesReceived = await socket.ReceiveAsync(buffer.AsMemory(read, buffer.Length - read), SocketFlags.None).DefaultTimeout();

                            read += bytesReceived;
                            if (bytesReceived <= 0)
                            {
                                break;
                            }
                        }

                        Assert.Equal(data, buffer);
                    }

                    // Wait for the server to complete the loop because of the FIN
                    await serverConnectionCompletedTcs.Task.DefaultTimeout();

                    await host.StopAsync().DefaultTimeout();
                }
            }
            finally
            {
                Delete(path);
            }
        }
Beispiel #25
0
        public async Task TestUnixDomainSocketWithUrl()
        {
            var path = Path.GetTempFileName();
            var url  = $"http://unix:/{path}";

            Delete(path);

            try
            {
                var hostBuilder = TransportSelector.GetHostBuilder()
                                  .ConfigureWebHost(webHostBuilder =>
                {
                    webHostBuilder
                    .UseUrls(url)
                    .UseKestrel()
                    .Configure(app =>
                    {
                        app.Run(async context =>
                        {
                            await context.Response.WriteAsync("Hello World");
                        });
                    });
                })
                                  .ConfigureServices(AddTestLogging);

                using (var host = hostBuilder.Build())
                {
                    await host.StartAsync().DefaultTimeout();

                    // https://github.com/dotnet/corefx/issues/5999
                    // .NET Core HttpClient does not support unix sockets, it's difficult to parse raw response data. below is a little hacky way.
                    using (var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
                    {
                        await socket.ConnectAsync(new UnixDomainSocketEndPoint(path)).DefaultTimeout();

                        var httpRequest = Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\nConnection: close\r\n\r\n");
                        await socket.SendAsync(httpRequest, SocketFlags.None).DefaultTimeout();

                        var readBuffer = new byte[512];
                        var read       = 0;
                        while (true)
                        {
                            var bytesReceived = await socket.ReceiveAsync(readBuffer.AsMemory(read), SocketFlags.None).DefaultTimeout();

                            read += bytesReceived;
                            if (bytesReceived <= 0)
                            {
                                break;
                            }
                        }

                        var httpResponse    = Encoding.ASCII.GetString(readBuffer, 0, read);
                        int httpStatusStart = httpResponse.IndexOf(' ') + 1;
                        Assert.False(httpStatusStart == 0, $"Space not found in '{httpResponse}'.");
                        int httpStatusEnd = httpResponse.IndexOf(' ', httpStatusStart);
                        Assert.False(httpStatusEnd == -1, $"Second space not found in '{httpResponse}'.");

                        var httpStatus = int.Parse(httpResponse.Substring(httpStatusStart, httpStatusEnd - httpStatusStart), CultureInfo.InvariantCulture);
                        Assert.Equal(httpStatus, StatusCodes.Status200OK);
                    }
                    await host.StopAsync().DefaultTimeout();
                }
            }
            finally
            {
                Delete(path);
            }
        }
Beispiel #26
0
        public async Task LargeUpload(long contentLength, bool checkBytes)
        {
            const int bufferLength = 1024 * 1024;

            Assert.True(contentLength % bufferLength == 0, $"{nameof(contentLength)} sent must be evenly divisible by {bufferLength}.");
            Assert.True(bufferLength % 256 == 0, $"{nameof(bufferLength)} must be evenly divisible by 256");

            var builder = TransportSelector.GetHostBuilder()
                          .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                .UseKestrel(options =>
                {
                    options.Limits.MaxRequestBodySize     = contentLength;
                    options.Limits.MinRequestBodyDataRate = null;
                })
                .UseUrls("http://127.0.0.1:0/")
                .Configure(app =>
                {
                    app.Run(async context =>
                    {
                        // Read the full request body
                        long total        = 0;
                        var receivedBytes = new byte[bufferLength];
                        var received      = 0;
                        while ((received = await context.Request.Body.ReadAsync(receivedBytes, 0, receivedBytes.Length)) > 0)
                        {
                            if (checkBytes)
                            {
                                for (var i = 0; i < received; i++)
                                {
                                    // Do not use Assert.Equal here, it is to slow for this hot path
                                    Assert.True((byte)((total + i) % 256) == receivedBytes[i], "Data received is incorrect");
                                }
                            }

                            total += received;
                        }

                        await context.Response.WriteAsync($"bytesRead: {total}");
                    });
                });
            })
                          .ConfigureServices(AddTestLogging);

            using (var host = builder.Build())
            {
                await host.StartAsync();

                using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                {
                    socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort()));
                    socket.Send(Encoding.ASCII.GetBytes("POST / HTTP/1.1\r\nHost: \r\n"));
                    socket.Send(Encoding.ASCII.GetBytes($"Content-Length: {contentLength}\r\n\r\n"));

                    var contentBytes = new byte[bufferLength];

                    if (checkBytes)
                    {
                        for (var i = 0; i < contentBytes.Length; i++)
                        {
                            contentBytes[i] = (byte)i;
                        }
                    }

                    for (var i = 0; i < contentLength / contentBytes.Length; i++)
                    {
                        socket.Send(contentBytes);
                    }

                    using (var stream = new NetworkStream(socket))
                    {
                        await AssertStreamContains(stream, $"bytesRead: {contentLength}");
                    }
                }

                await host.StopAsync();
            }
        }
Beispiel #27
0
    private void ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily addressFamily)
    {
        ThrowOnCriticalErrors = false;

        var addressInUseCount = 0;
        var wrongMessageCount = 0;

        var address            = addressFamily == AddressFamily.InterNetwork ? IPAddress.Loopback : IPAddress.IPv6Loopback;
        var otherAddressFamily = addressFamily == AddressFamily.InterNetwork ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;

        while (addressInUseCount < 10 && wrongMessageCount < 10)
        {
            int port;

            using (var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
            {
                // Bind first to IPv6Any to ensure both the IPv4 and IPv6 ports are available.
                socket.Bind(new IPEndPoint(IPAddress.IPv6Any, 0));
                socket.Listen(0);
                port = ((IPEndPoint)socket.LocalEndPoint).Port;
            }

            using (var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp))
            {
                try
                {
                    socket.Bind(new IPEndPoint(address, port));
                    socket.Listen(0);
                }
                catch (SocketException)
                {
                    addressInUseCount++;
                    continue;
                }

                var hostBuilder = TransportSelector.GetHostBuilder()
                                  .ConfigureWebHost(webHostBuilder =>
                {
                    webHostBuilder
                    .UseKestrel()
                    .UseUrls($"http://localhost:{port}")
                    .Configure(ConfigureEchoAddress);
                })
                                  .ConfigureServices(AddTestLogging);

                using (var host = hostBuilder.Build())
                {
                    var exception = Assert.Throws <IOException>(() => host.Start());

                    var thisAddressString  = $"http://{(addressFamily == AddressFamily.InterNetwork ? "127.0.0.1" : "[::1]")}:{port}";
                    var otherAddressString = $"http://{(addressFamily == AddressFamily.InterNetworkV6 ? "127.0.0.1" : "[::1]")}:{port}";

                    if (exception.Message == CoreStrings.FormatEndpointAlreadyInUse(otherAddressString))
                    {
                        // Don't fail immediately, because it's possible that something else really did bind to the
                        // same port for the other address family between the IPv6Any bind above and now.
                        wrongMessageCount++;
                        continue;
                    }

                    Assert.Equal(CoreStrings.FormatEndpointAlreadyInUse(thisAddressString), exception.Message);
                    Assert.Equal(0, LogMessages.Count(log => log.LogLevel == LogLevel.Critical &&
                                                      log.Exception is null &&
                                                      log.Message.EndsWith(CoreStrings.FormatEndpointAlreadyInUse(thisAddressString), StringComparison.Ordinal)));
                    break;
                }
            }
        }

        if (addressInUseCount >= 10)
        {
            Assert.True(false, $"The corresponding {otherAddressFamily} address was already in use 10 times.");
        }

        if (wrongMessageCount >= 10)
        {
            Assert.True(false, $"An error for a conflict with {otherAddressFamily} was thrown 10 times.");
        }
    }
Beispiel #28
0
    private async Task <IHost> StartHost(long?maxRequestBufferSize,
                                         byte[] expectedBody,
                                         bool useConnectionAdapter,
                                         TaskCompletionSource startReadingRequestBody,
                                         TaskCompletionSource clientFinishedSendingRequestBody,
                                         Func <MemoryPool <byte> > memoryPoolFactory = null)
    {
        var host = TransportSelector.GetHostBuilder(memoryPoolFactory, maxRequestBufferSize)
                   .ConfigureWebHost(webHostBuilder =>
        {
            webHostBuilder
            .UseKestrel(options =>
            {
                options.Listen(new IPEndPoint(IPAddress.Loopback, 0), listenOptions =>
                {
                    if (useConnectionAdapter)
                    {
                        listenOptions.UsePassThrough();
                    }
                });

                options.Limits.MaxRequestBufferSize = maxRequestBufferSize;

                if (maxRequestBufferSize.HasValue &&
                    maxRequestBufferSize.Value < options.Limits.MaxRequestLineSize)
                {
                    options.Limits.MaxRequestLineSize = (int)maxRequestBufferSize;
                }

                if (maxRequestBufferSize.HasValue &&
                    maxRequestBufferSize.Value < options.Limits.MaxRequestHeadersTotalSize)
                {
                    options.Limits.MaxRequestHeadersTotalSize = (int)maxRequestBufferSize;
                }

                options.Limits.MinRequestBodyDataRate = null;

                options.Limits.MaxRequestBodySize = _dataLength;
            })
            .UseContentRoot(Directory.GetCurrentDirectory())
            .Configure(app => app.Run(async context =>
            {
                await startReadingRequestBody.Task.TimeoutAfter(TimeSpan.FromSeconds(120));

                var buffer    = new byte[expectedBody.Length];
                var bytesRead = 0;
                while (bytesRead < buffer.Length)
                {
                    bytesRead += await context.Request.Body.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead);
                }

                await clientFinishedSendingRequestBody.Task.TimeoutAfter(TimeSpan.FromSeconds(120));

                // Verify client didn't send extra bytes
                if (await context.Request.Body.ReadAsync(new byte[1], 0, 1) != 0)
                {
                    context.Response.StatusCode = StatusCodes.Status500InternalServerError;
                    await context.Response.WriteAsync("Client sent more bytes than expectedBody.Length");
                    return;
                }

                await context.Response.WriteAsync($"bytesRead: {bytesRead}");
            }));
        })
                   .ConfigureServices(AddTestLogging)
                   .Build();

        await host.StartAsync();

        return(host);
    }