Example #1
0
 public void DefaultConfigSectionCanSetProtocols_MacAndWin7(string input, HttpProtocols expected)
 => DefaultConfigSectionCanSetProtocols(input, expected);
        internal static void ConfigureAlpn(SslServerAuthenticationOptions serverOptions, HttpProtocols httpProtocols)
        {
            serverOptions.ApplicationProtocols = new List <SslApplicationProtocol>();

            // This is order sensitive
            if ((httpProtocols & HttpProtocols.Http2) != 0)
            {
                serverOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http2);
                // https://tools.ietf.org/html/rfc7540#section-9.2.1
                serverOptions.AllowRenegotiation = false;
            }

            if ((httpProtocols & HttpProtocols.Http1) != 0)
            {
                serverOptions.ApplicationProtocols.Add(SslApplicationProtocol.Http11);
            }
        }
Example #3
0
 public abstract string GetUrl(HttpProtocols httpProtocol);
Example #4
0
        public static IMultiplexedConnectionBuilder UseHttp3Server <TContext>(this IMultiplexedConnectionBuilder builder, ServiceContext serviceContext, IHttpApplication <TContext> application, HttpProtocols protocols, bool addAltSvcHeader) where TContext : notnull
        {
            var middleware = new HttpMultiplexedConnectionMiddleware <TContext>(serviceContext, application, protocols, addAltSvcHeader);

            return(builder.Use(next =>
            {
                return middleware.OnConnectionAsync;
            }));
        }
        public HttpConnectionMiddleware(IList <IConnectionAdapter> adapters, ServiceContext serviceContext, IHttpApplication <TContext> application, HttpProtocols protocols)
        {
            _serviceContext = serviceContext;
            _application    = application;
            _protocols      = protocols;

            // Keeping these around for now so progress can be made without updating tests
            _connectionAdapters = adapters;
        }
Example #6
0
 public SniOptions(SslServerAuthenticationOptions sslOptions, HttpProtocols httpProtocols, ClientCertificateMode clientCertificateMode)
 {
     SslOptions            = sslOptions;
     HttpProtocols         = httpProtocols;
     ClientCertificateMode = clientCertificateMode;
 }
        public static IConnectionBuilder UseHttpServer <TContext>(this IConnectionBuilder builder, ServiceContext serviceContext, IHttpApplication <TContext> application, HttpProtocols protocols)
        {
            var middleware = new HttpConnectionMiddleware <TContext>(serviceContext, application, protocols);

            return(builder.Use(next =>
            {
                return middleware.OnConnectionAsync;
            }));
        }
Example #8
0
        public void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, RequestDelegate del, int port, HttpProtocols protocols)
        {
            _builder = new WebHostBuilder()
                       .UseUrls(baseUrl)
                       .UseKestrel()
                       .ConfigureKestrel(serverOptions =>
            {
                serverOptions.Listen(IPAddress.Loopback, port, listenOptions =>
                {
                    listenOptions.UseHttps("idsrv3test.pfx", "idsrv3test");
                    listenOptions.Protocols = protocols;
                });
            })
                       .UseContentRoot(Directory.GetCurrentDirectory())
                       .UseIISIntegration()
                       .Configure(app =>
            {
                app.UsePathBase(basePath);
                app.Run(del);
            })
                       .Build();

            _builder.Start();
        }
        public async Task UsesVersion(HttpProtocols protocols, bool tls, bool allowUnencryptedHttp2, string specified, string expectedVersion, string expectedResponse, bool failure = false)
        {
            // wheeee, macOS doesn't support ALPN so it can't do HTTP/2 over TLS
            // it also misbehaves when requesting HTTP/2 over non-TLS
            // so let's skip all those tests on macOS.
            Skip.If(
                RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && tls && (protocols == HttpProtocols.Http2 || protocols == HttpProtocols.Http1AndHttp2) && specified == "2.0",
                "HTTP/2 over TLS is not currently supported on MacOS"
                );

            bool oldMode = HttpSettings.GlobalAllowUnencryptedHttp2;

            try
            {
                HttpSettings.GlobalAllowUnencryptedHttp2 = allowUnencryptedHttp2;

                var uri = _server.GetUri(protocols, tls);
                Log($"Server is on {uri}; specifying: '{specified}'");
                var request = Http.Request(uri, new HttpSettings {
                    ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
                });
                if (specified is object)
                {
                    request = request.WithProtocolVersion(new Version(specified));
                }
                HttpCallResponse <string> result;
                try
                {
                    result = await request.ExpectString().GetAsync();
                }
                catch (Exception ex)
                {
                    if (failure)
                    {
                        Log(ex.ToString());
                        return;
                    }
                    else
                    {
                        throw;
                    }
                }

                Log($"As sent: {result?.RawRequest?.Version}, received: {result?.RawResponse?.Version}");

                if (failure)
                {
                    Assert.NotNull(result.Error);
                    Log(result.Error.ToString());
                }
                else
                {
                    Assert.Null(result.Error);
                    Assert.Equal(expectedVersion, result.RawResponse?.Version?.ToString());
                    Assert.Equal(expectedResponse, result.Data);
                }
            }
            finally
            {
                HttpSettings.GlobalAllowUnencryptedHttp2 = oldMode;
            }
        }
    public async Task PostExpect100_BodyNotUploadedIfFailed(HttpProtocols proxyProtocol, HttpProtocols destProtocol, bool useContentLength, int destResponseCode)
    {
        var headerTcs = new TaskCompletionSource <StringValues>(TaskCreationOptions.RunContinuationsAsynchronously);
        var bodyTcs   = new TaskCompletionSource <string>(TaskCreationOptions.RunContinuationsAsynchronously);

        var contentString = new string('a', 1024 * 1024 * 10);
        var test          = new TestEnvironment(
            async context =>
        {
            if ((context.Request.Protocol == "HTTP/1.1" && destProtocol != HttpProtocols.Http1) ||
                (context.Request.Protocol == "HTTP/2.0" && destProtocol != HttpProtocols.Http2))
            {
                headerTcs.SetException(new Exception($"Unexpected request protocol {context.Request.Protocol}"));
                return;
            }
            else if (context.Request.Headers.TryGetValue(HeaderNames.Expect, out var expectHeader))
            {
                headerTcs.SetResult(expectHeader);
            }
            else
            {
                headerTcs.SetException(new Exception("Missing 'Expect' header in request"));
                return;
            }

            if (destResponseCode == 200)
            {
                // 100 response code is sent automatically on reading Body.
                await ReadContent(context, bodyTcs, Encoding.UTF8.GetByteCount(contentString));
            }

            context.Response.StatusCode = destResponseCode;
        },
            proxyBuilder =>
        {
            proxyBuilder.Services.AddSingleton <IForwarderHttpClientFactory, TestForwarderHttpClientFactory>();
        },
            proxyApp => { },
            proxyProtocol: proxyProtocol,
            useHttpsOnDestination: true,
            useHttpsOnProxy: true,
            configTransformer: (c, r) =>
        {
            c = c with
            {
                HttpRequest = new ForwarderRequestConfig
                {
                    Version = destProtocol == HttpProtocols.Http2 ? HttpVersion.Version20 : HttpVersion.Version11,
                }
            };
            return(c, r);
        });

        await test.Invoke(async uri =>
        {
            await ProcessHttpRequest(new Uri(uri), proxyProtocol, contentString, useContentLength, destResponseCode, false, destResponseCode == 200);

            Assert.True(headerTcs.Task.IsCompleted);
            var expectHeader = await headerTcs.Task;
            var expectValue  = Assert.Single(expectHeader);
            Assert.Equal("100-continue", expectValue);

            if (destResponseCode == 200)
            {
                Assert.True(bodyTcs.Task.IsCompleted);
                var actualString = await bodyTcs.Task;
                Assert.Equal(contentString, actualString);
            }
            else
            {
                Assert.False(bodyTcs.Task.IsCompleted);
            }
        });
    }
 public static IConnectionBuilder UseHttpServer <TContext>(this IConnectionBuilder builder, ServiceContext serviceContext, IHttpApplication <TContext> application, HttpProtocols protocols)
 {
     return(builder.UseHttpServer(Array.Empty <IConnectionAdapter>(), serviceContext, application, protocols));
 }
    private async Task ProcessHttpRequest(
        Uri proxyHostUri,
        HttpProtocols protocol,
        string contentString,
        bool useContentLength,
        int expectedCode,
        bool cancelResponse,
        bool contentRead,
        Func <HttpResponseMessage, Task> responseAction = null)
    {
        using var handler = new SocketsHttpHandler()
              {
                  Expect100ContinueTimeout = TimeSpan.FromSeconds(60)
              };
        handler.UseProxy          = false;
        handler.AllowAutoRedirect = false;
        handler.SslOptions.RemoteCertificateValidationCallback = delegate { return(true); };
        using var client  = new HttpClient(handler);
        using var message = new HttpRequestMessage(HttpMethod.Post, proxyHostUri);
        message.Version   = protocol == HttpProtocols.Http2 ? HttpVersion.Version20 : HttpVersion.Version11;
        message.Headers.ExpectContinue = true;

        var content = Encoding.UTF8.GetBytes(contentString);

        using var contentStream = new MemoryStream(content);
        message.Content         = new StreamContent(contentStream);
        if (useContentLength)
        {
            message.Content.Headers.ContentLength = content.Length;
        }
        else
        {
            message.Headers.TransferEncodingChunked = true;
        }

        if (!cancelResponse)
        {
            using var response = await client.SendAsync(message);

            Assert.Equal(expectedCode, (int)response.StatusCode);
            if (contentRead)
            {
                Assert.Equal(content.Length, contentStream.Position);
            }
            else
            {
                Assert.Equal(0, contentStream.Position);
            }

            if (responseAction is not null)
            {
                await responseAction(response);
            }
        }
        else
        {
            var exception = await Assert.ThrowsAsync <HttpRequestException>(() => client.SendAsync(message));

            Assert.Equal(typeof(IOException), exception.InnerException.GetType());
            Assert.Equal(content.Length, contentStream.Position);
        }
    }
    public async Task PostExpect100_SkipRequestBodyWithUnsuccesfulResponseCode(HttpProtocols proxyProtocol, HttpProtocols destProtocol, bool useContentLength)
    {
        var requestBodyTcs = new TaskCompletionSource <string>(TaskCreationOptions.RunContinuationsAsynchronously);

        var contentString = new string('a', 1024 * 1024 * 10);
        var test          = new TestEnvironment(
            async context =>
        {
            context.Response.StatusCode = 400;

            var responseBody = Encoding.UTF8.GetBytes(contentString + "Response");
            if (useContentLength)
            {
                context.Response.Headers.ContentLength = responseBody.Length;
            }

            await context.Response.Body.WriteAsync(responseBody.AsMemory());
        },
            proxyBuilder => {
            proxyBuilder.Services.AddSingleton <IForwarderHttpClientFactory, TestForwarderHttpClientFactory>();
        },
            proxyApp => { },
            proxyProtocol: proxyProtocol,
            useHttpsOnDestination: true,
            useHttpsOnProxy: true,
            configTransformer: (c, r) =>
        {
            c = c with
            {
                HttpRequest = new ForwarderRequestConfig
                {
                    Version = destProtocol == HttpProtocols.Http2 ? HttpVersion.Version20 : HttpVersion.Version11,
                }
            };
            return(c, r);
        });

        await test.Invoke(async uri =>
        {
            await ProcessHttpRequest(new Uri(uri), proxyProtocol, contentString, useContentLength, 400, cancelResponse: false, contentRead: false, async response =>
            {
                Assert.Equal(400, (int)response.StatusCode);

                var actualResponse = await response.Content.ReadAsStringAsync();
                Assert.Equal(contentString + "Response", actualResponse);
            });
        });
    }
 public HttpConnectionMiddleware(ServiceContext serviceContext, IHttpApplication <TContext> application, HttpProtocols protocols)
 {
     _serviceContext = serviceContext;
     _application    = application;
     _protocols      = protocols;
 }
Example #15
0
 public void EndpointConfigSectionCanSetProtocols_NonMacAndWin7(string input, HttpProtocols expected) =>
 EndpointConfigSectionCanSetProtocols(input, expected);
Example #16
0
 public HttpProtocolsFeature(HttpProtocols httpProtocols)
 {
     HttpProtocols = httpProtocols;
 }
Example #17
0
 public HttpMultiplexedConnectionMiddleware(ServiceContext serviceContext, IHttpApplication <TContext> application, HttpProtocols protocols, bool addAltSvcHeader)
 {
     _serviceContext  = serviceContext;
     _application     = application;
     _protocols       = protocols;
     _addAltSvcHeader = addAltSvcHeader;
 }
Example #18
0
        private IHost BuildWebHost(
            IEnvelopeSerializer envelopeSerializer,
            X509Certificate2 tlsCertificate,
            int bufferSize,
            ITraceWriter traceWriter,
            HttpProtocols httpProtocols,
            SslProtocols sslProtocols,
            Func <X509Certificate2, X509Chain, SslPolicyErrors, bool> clientCertificateValidationCallback,
            TimeSpan?keepAliveInterval)
        {
            HttpConnectionDispatcherOptions httpConnectionDispatcherOptions = null;
            HubOptions hubOptions = null;

            return(Host.CreateDefaultBuilder()
                   .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseKestrel(serverOptions =>
                {
                    foreach (var listenerUri in ListenerUris)
                    {
                        if (!IPAddress.TryParse(listenerUri.Host, out var ipAddress))
                        {
                            ipAddress = IPAddress.Any;
                        }

                        var endPoint = new IPEndPoint(ipAddress, listenerUri.Port);
                        serverOptions.Listen(endPoint, listenOptions =>
                        {
                            listenOptions.Protocols = httpProtocols;

                            if (listenerUri.Scheme == Uri.UriSchemeHttps)
                            {
                                listenOptions.UseHttps(tlsCertificate, httpsOptions =>
                                {
                                    httpsOptions.SslProtocols = sslProtocols;
                                    httpsOptions.ClientCertificateValidation = clientCertificateValidationCallback;
                                });
                            }
                        });
                    }

                    serverOptions.AddServerHeader = false;
                })
                .SuppressStatusMessages(true)
                .ConfigureServices(services =>
                {
                    services
                    .AddLogging()
                    .AddSingleton(sp => _transportChannel)
                    .AddSingleton(sp => httpConnectionDispatcherOptions)
                    .AddSingleton(sp => hubOptions)
                    .AddSingleton(envelopeSerializer)
                    .AddSingleton(new EnvelopeHubOptions {
                        BoundedCapacity = _backpressureLimit
                    })
                    .AddSingleton(new ConcurrentDictionary <string, Channel <string> >())
                    .AddSignalR().AddHubOptions <EnvelopeHub>(options =>
                    {
                        hubOptions = options;
                        options.KeepAliveInterval = keepAliveInterval;
                    });

                    if (traceWriter != null)
                    {
                        services.AddSingleton(traceWriter);
                    }
                })
                .Configure(app =>
                {
                    app.UseRouting().UseEndpoints(endpoints =>
                    {
                        endpoints.MapHub <EnvelopeHub>("/envelope", options =>
                        {
                            httpConnectionDispatcherOptions = options;
                            options.TransportMaxBufferSize = bufferSize;
                        });
                    });
                });
            })
                   .Build());
        }
Example #19
0
        public SniOptionsSelector(
            string endpointName,
            Dictionary <string, SniConfig> sniDictionary,
            ICertificateConfigLoader certifcateConfigLoader,
            HttpsConnectionAdapterOptions fallbackHttpsOptions,
            HttpProtocols fallbackHttpProtocols,
            ILogger <HttpsConnectionMiddleware> logger)
        {
            _endpointName = endpointName;

            _fallbackServerCertificateSelector = fallbackHttpsOptions.ServerCertificateSelector;
            _onAuthenticateCallback            = fallbackHttpsOptions.OnAuthenticate;

            foreach (var(name, sniConfig) in sniDictionary)
            {
                var sslOptions = new SslServerAuthenticationOptions
                {
                    ServerCertificate              = certifcateConfigLoader.LoadCertificate(sniConfig.Certificate, $"{endpointName}:Sni:{name}"),
                    EnabledSslProtocols            = sniConfig.SslProtocols ?? fallbackHttpsOptions.SslProtocols,
                    CertificateRevocationCheckMode = fallbackHttpsOptions.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
                };

                if (sslOptions.ServerCertificate is null)
                {
                    if (fallbackHttpsOptions.ServerCertificate is null && _fallbackServerCertificateSelector is null)
                    {
                        throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
                    }

                    if (_fallbackServerCertificateSelector is null)
                    {
                        // Cache the fallback ServerCertificate since there's no fallback ServerCertificateSelector taking precedence.
                        sslOptions.ServerCertificate = fallbackHttpsOptions.ServerCertificate;
                    }
                }

                if (sslOptions.ServerCertificate != null)
                {
                    // This might be do blocking IO but it'll resolve the certificate chain up front before any connections are
                    // made to the server
                    sslOptions.ServerCertificateContext = SslStreamCertificateContext.Create((X509Certificate2)sslOptions.ServerCertificate, additionalCertificates: null);
                }

                if (!certifcateConfigLoader.IsTestMock && sslOptions.ServerCertificate is X509Certificate2 cert2)
                {
                    HttpsConnectionMiddleware.EnsureCertificateIsAllowedForServerAuth(cert2);
                }

                var clientCertificateMode = sniConfig.ClientCertificateMode ?? fallbackHttpsOptions.ClientCertificateMode;

                if (clientCertificateMode != ClientCertificateMode.NoCertificate)
                {
                    sslOptions.ClientCertificateRequired = clientCertificateMode == ClientCertificateMode.AllowCertificate ||
                                                           clientCertificateMode == ClientCertificateMode.RequireCertificate;
                    sslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
                                                                     HttpsConnectionMiddleware.RemoteCertificateValidationCallback(
                        clientCertificateMode, fallbackHttpsOptions.ClientCertificateValidation, certificate, chain, sslPolicyErrors);
                }

                var httpProtocols = sniConfig.Protocols ?? fallbackHttpProtocols;
                httpProtocols = HttpsConnectionMiddleware.ValidateAndNormalizeHttpProtocols(httpProtocols, logger);
                HttpsConnectionMiddleware.ConfigureAlpn(sslOptions, httpProtocols);

                var sniOptions = new SniOptions(sslOptions, httpProtocols, clientCertificateMode);

                if (name.Equals(WildcardHost, StringComparison.Ordinal))
                {
                    _wildcardOptions = sniOptions;
                }
                else if (name.StartsWith(WildcardPrefix, StringComparison.Ordinal))
                {
                    // Only slice off 1 character, the `*`. We want to match the leading `.` also.
                    _wildcardPrefixOptions.Add(name.Substring(1), sniOptions);
                }
                else
                {
                    _exactNameOptions.Add(name, sniOptions);
                }
            }
        }
Example #20
0
 public HttpConnectionMiddleware(ServiceContext serviceContext, IHttpApplication <TContext> application, HttpProtocols protocols, bool addAltSvcHeader)
 {
     _serviceContext           = serviceContext;
     _application              = application;
     _endpointDefaultProtocols = protocols;
     _addAltSvcHeader          = addAltSvcHeader;
 }
        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 #22
0
 private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int port, HttpProtocols protocols)
 {
     _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context =>
     {
         context.Response.StatusCode = 200;
         var reader = new StreamReader(context.Request.Body);
         var body   = await reader.ReadToEndAsync();
         await context.Response.WriteAsync(body);
     }, port, protocols);
 }