public async Task ThrowsWhenBindingToIPv6AddressInUse()
        {
            IgnoredCriticalLogExceptions.Add(typeof(IOException));

            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());
                    Assert.Equal(CoreStrings.FormatEndpointAlreadyInUse($"http://[::1]:{port}"), exception.Message);

                    await host.StopAsync();
                }
            }
        }
        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();
            }
        }
Example #3
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();
            }
        }
Example #4
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();
                }
        }
        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();
            }
        }
        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();
            }
        }
Example #7
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();
            }
        }
Example #8
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();
            }
        }
Example #9
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 KestrelServer(new List <IConnectionListenerFactory>()
                        {
                            sp.GetRequiredService <IConnectionListenerFactory>()
                        }, context));
                    });
                    configureServices(services);
                })
                .UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).GetTypeInfo().Assembly.FullName)
                .UseSetting(WebHostDefaults.ShutdownTimeoutKey, TestConstants.DefaultTimeout.TotalSeconds.ToString())
                .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}");
        }
        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();
            }
        }
Example #11
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();
            }
        }
Example #12
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();
                }
        }
        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, "UseKestrel()"),
                                            log.Message, StringComparison.Ordinal));

                Assert.Equal(new Uri(endPointAddress).ToString(), await HttpClientSlim.GetStringAsync(endPointAddress, validateCertificate: false));
                await host.StopAsync();
            }
        }
Example #14
0
        public async Task OverrideDirectConfigurationWithIServerAddressesFeature_Succeeds()
        {
            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.GetTestCertificate());
                    });
                })
                .UseUrls(useUrlsAddress)
                .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 get the HTTPS endpoint defined in UseKestrel
                // instead of the HTTP endpoint defined in UseUrls.
                var serverAddresses = host.Services.GetRequiredService <IServer>().Features.Get <IServerAddressesFeature>().Addresses;
                Assert.Equal(1, serverAddresses.Count);
                var useUrlsAddressWithPort = $"http://127.0.0.1:{port}";
                Assert.Equal(serverAddresses.First(), useUrlsAddressWithPort);

                Assert.Single(TestApplicationErrorLogger.Messages, log => log.LogLevel == LogLevel.Information &&
                              string.Equals(CoreStrings.FormatOverridingWithPreferHostingUrls(nameof(IServerAddressesFeature.PreferHostingUrls), useUrlsAddress),
                                            log.Message, StringComparison.Ordinal));

                Assert.Equal(new Uri(useUrlsAddressWithPort).ToString(), await HttpClientSlim.GetStringAsync(useUrlsAddressWithPort));

                await host.StopAsync();
            }
        }
        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();
            }
        }
        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();
            }
        }
        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();
            }
        }
        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());

                if (mockHttps)
                {
                    Assert.Contains(5001, host.GetPorts());
                }

                Assert.Single(LogMessages, log => log.LogLevel == LogLevel.Debug &&
                              (string.Equals(CoreStrings.FormatBindingToDefaultAddresses(Constants.DefaultServerAddress, Constants.DefaultServerHttpsAddress), 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();
            }
        }
Example #19
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();
            }
        }
        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();
            }
        }
        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();
            }
        }
Example #22
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.ToString()}");
                }));
            })
                       .ConfigureServices(AddTestLogging)
                       .Build();

            await host.StartAsync();

            return(host);
        }
Example #23
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;
                        int httpStatusEnd   = httpResponse.IndexOf(' ', httpStatusStart);

                        var httpStatus = int.Parse(httpResponse.Substring(httpStatusStart, httpStatusEnd - httpStatusStart));
                        Assert.Equal(httpStatus, StatusCodes.Status200OK);
                    }
                    await host.StopAsync().DefaultTimeout();
                }
            }
            finally
            {
                Delete(path);
            }
        }
Example #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);
            }
        }
        private void ThrowsWhenBindingLocalhostToAddressInUse(AddressFamily addressFamily)
        {
            IgnoredCriticalLogExceptions.Add(typeof(IOException));

            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);
                        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.");
            }
        }
Example #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();
            }
        }