示例#1
0
        public void UpgradeRequestShouldBase64EncodeSettingsCorrectly(
            Settings settings, string expectedEncoding)
        {
            var upgrade =
                new ClientUpgradeRequestBuilder()
                .SetHttp2Settings(settings)
                .Build();

            Assert.Equal(expectedEncoding, upgrade.Base64EncodedSettings);
        }
示例#2
0
        public async Task ClientUpgradeRequestShouldYieldStream1()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            var upgrade = new ClientUpgradeRequestBuilder().Build();
            var config  = new ConnectionConfigurationBuilder(false)
                          .Build();

            var conn = new Connection(
                config, inPipe, outPipe,
                new Connection.Options
            {
                Logger = loggerProvider.CreateLogger("http2Con"),
                ClientUpgradeRequest = upgrade,
            });

            await conn.PerformHandshakes(inPipe, outPipe);

            var stream = await upgrade.UpgradeRequestStream;

            Assert.Equal(1u, stream.Id);
            Assert.Equal(1, conn.ActiveStreamCount);
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);

            var readHeadersTask = stream.ReadHeadersAsync();

            Assert.False(readHeadersTask.IsCompleted);

            var hEncoder = new Http2.Hpack.Encoder();
            await inPipe.WriteHeaders(hEncoder, 1u, false, DefaultStatusHeaders);

            Assert.True(
                await Task.WhenAny(
                    readHeadersTask,
                    Task.Delay(ReadableStreamTestExtensions.ReadTimeout))
                == readHeadersTask,
                "Expected to read headers, got timeout");
            var headers = await readHeadersTask;

            Assert.True(headers.SequenceEqual(DefaultStatusHeaders));
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);

            await inPipe.WriteData(1u, 100, 5, true);

            var data = await stream.ReadAllToArrayWithTimeout();

            Assert.True(data.Length == 100);
            Assert.Equal(StreamState.Closed, stream.State);
            Assert.Equal(0, conn.ActiveStreamCount);
        }
示例#3
0
    async Task <Connection> CreateUpgradeConnection(string host, int port)
    {
        // HTTP/2 settings
        var config =
            new ConnectionConfigurationBuilder(false)
            .UseSettings(Settings.Default)
            .UseHuffmanStrategy(HuffmanStrategy.IfSmaller)
            .Build();

        // Prepare connection upgrade
        var upgrade =
            new ClientUpgradeRequestBuilder()
            .SetHttp2Settings(config.Settings)
            .Build();

        // Create a TCP connection
        logger.LogInformation($"Starting to connect to {host}:{port}");
        var tcpClient = new TcpClient();
        await tcpClient.ConnectAsync(host, port);

        tcpClient.Client.NoDelay = true;
        logger.LogInformation("Connected to remote");

        // Create HTTP/2 stream abstraction on top of the socket
        var wrappedStreams    = tcpClient.Client.CreateStreams();
        var upgradeReadStream = new UpgradeReadStream(wrappedStreams.ReadableStream);

        var needExplicitStreamClose = true;

        try
        {
            // Send a HTTP/1.1 upgrade request with the necessary fields
            var upgradeHeader =
                "OPTIONS / HTTP/1.1\r\n" +
                "Host: " + host + "\r\n" +
                "Connection: Upgrade, HTTP2-Settings\r\n" +
                "Upgrade: h2c\r\n" +
                "HTTP2-Settings: " + upgrade.Base64EncodedSettings + "\r\n\r\n";
            logger.LogInformation("Sending upgrade request:\n" + upgradeHeader);
            var encodedHeader = Encoding.ASCII.GetBytes(upgradeHeader);
            await wrappedStreams.WriteableStream.WriteAsync(
                new ArraySegment <byte>(encodedHeader));

            // Wait for the upgrade response
            await upgradeReadStream.WaitForHttpHeader();

            var headerBytes = upgradeReadStream.HeaderBytes;

            logger.LogInformation(
                "Received HTTP/1.1 response: " +
                Encoding.ASCII.GetString(headerBytes.Array, 0, headerBytes.Count));

            // Try to parse the upgrade response as HTTP/1 status and check whether
            // the upgrade was successful.
            var response = Http1Response.ParseFrom(
                Encoding.ASCII.GetString(
                    headerBytes.Array, headerBytes.Offset, headerBytes.Count - 4));
            // Mark the HTTP/1.1 bytes as read
            upgradeReadStream.ConsumeHttpHeader();

            if (response.StatusCode != "101")
            {
                throw new Exception("Upgrade failed");
            }
            if (!response.Headers.Any(hf => hf.Key == "connection" && hf.Value == "Upgrade") ||
                !response.Headers.Any(hf => hf.Key == "upgrade" && hf.Value == "h2c"))
            {
                throw new Exception("Upgrade failed");
            }

            logger.LogInformation("Connection upgrade succesful!");

            // If we get here then the connection will be reponsible for closing
            // the stream
            needExplicitStreamClose = false;

            // Build a HTTP connection on top of the stream abstraction
            var connLogger = verbose ? logProvider.CreateLogger("HTTP2Conn") : null;
            var conn       = new Connection(
                config, upgradeReadStream, wrappedStreams.WriteableStream,
                options: new Connection.Options
            {
                Logger = connLogger,
                ClientUpgradeRequest = upgrade,
            });

            // Retrieve the response stream for the connection upgrade.
            var upgradeStream = await upgrade.UpgradeRequestStream;
            // As we made the upgrade via a dummy OPTIONS request we are not
            // really interested in the result of the upgrade request
            upgradeStream.Cancel();

            return(conn);
        }
        finally
        {
            if (needExplicitStreamClose)
            {
                await wrappedStreams.WriteableStream.CloseAsync();
            }
        }
    }
示例#4
0
        /// <summary>
        /// Http2Client
        /// </summary>
        /// <param name="host"></param>
        /// <param name="ip"></param>
        /// <param name="scheme"></param>
        /// <param name="path"></param>
        /// <param name="authority"></param>
        /// <param name="useHttp1Upgrade"></param>
        /// <param name="size"></param>
        /// <param name="timeOut"></param>
        public Http2Client(string host, int ip, string scheme, string path, string authority, bool useHttp1Upgrade = false, int size = 1024, int timeOut = 180 * 1000)
        {
            _path = path;

            _authority = authority;

            var options = SocketOptionBuilder.Instance.SetSocket(Sockets.Model.SAEASocketType.Tcp)
                          .UseStream()
                          .SetIP(host)
                          .SetPort(ip)
                          .SetReadBufferSize(size)
                          .SetWriteBufferSize(size)
                          .SetTimeOut(timeOut)
                          .Build();

            _clientSocket = SocketFactory.CreateClientSocket(options);

            _clientSocket.ConnectAsync().GetAwaiter();

            var config = new ConnectionConfigurationBuilder(false)
                         .UseSettings(Settings.Default)
                         .UseHuffmanStrategy(HuffmanStrategy.IfSmaller)
                         .Build();

            var wrappedStreams = _clientSocket.Socket.CreateStreams();

            if (useHttp1Upgrade)
            {
                var upgrade = new ClientUpgradeRequestBuilder()
                              .SetHttp2Settings(config.Settings)
                              .Build();

                var upgradeReadStream = new UpgradeReadStream(wrappedStreams.ReadableStream);

                var needExplicitStreamClose = true;

                try
                {
                    var upgradeHeader = "OPTIONS / HTTP/1.1\r\n" +
                                        "Host: " + host + "\r\n" +
                                        "Connection: Upgrade, HTTP2-Settings\r\n" +
                                        "Upgrade: h2c\r\n" +
                                        "HTTP2-Settings: " + upgrade.Base64EncodedSettings + "\r\n\r\n";

                    var encodedHeader = Encoding.ASCII.GetBytes(upgradeHeader);

                    wrappedStreams.WriteableStream.WriteAsync(new ArraySegment <byte>(encodedHeader)).GetAwaiter();

                    upgradeReadStream.WaitForHttpHeader().GetAwaiter();

                    var headerBytes = upgradeReadStream.HeaderBytes;

                    upgradeReadStream.ConsumeHttpHeader();

                    var response = Http1Response.ParseFrom(Encoding.ASCII.GetString(headerBytes.Array, headerBytes.Offset, headerBytes.Count - 4));

                    if (response.StatusCode != "101")
                    {
                        throw new Exception("升级失败");
                    }

                    if (!response.Headers.Any(hf => hf.Key == "connection" && hf.Value == "Upgrade") ||
                        !response.Headers.Any(hf => hf.Key == "upgrade" && hf.Value == "h2c"))
                    {
                        throw new Exception("升级失败");
                    }

                    needExplicitStreamClose = false;

                    var conn = new Connection(config, upgradeReadStream, wrappedStreams.WriteableStream, options: new Connection.Options
                    {
                        ClientUpgradeRequest = upgrade,
                    });


                    var upgradeStream = upgrade.UpgradeRequestStream.GetAwaiter().GetResult();

                    upgradeStream.Cancel();

                    _conn = conn;
                }
                finally
                {
                    if (needExplicitStreamClose)
                    {
                        wrappedStreams.WriteableStream.CloseAsync();
                    }
                }
            }
            else
            {
                _conn = new Connection(config, wrappedStreams.ReadableStream, wrappedStreams.WriteableStream, options: new Connection.Options());
            }
        }
示例#5
0
        public async Task TheNextOutgoingStreamAfterUpgradeShouldUseId3()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            var upgrade = new ClientUpgradeRequestBuilder().Build();
            var config  = new ConnectionConfigurationBuilder(false)
                          .Build();

            var conn = new Connection(
                config, inPipe, outPipe,
                new Connection.Options
            {
                Logger = loggerProvider.CreateLogger("http2Con"),
                ClientUpgradeRequest = upgrade,
            });

            await conn.PerformHandshakes(inPipe, outPipe);

            var stream = await upgrade.UpgradeRequestStream;

            Assert.Equal(1u, stream.Id);

            var readHeadersTask = stream.ReadHeadersAsync();

            Assert.False(readHeadersTask.IsCompleted);

            var nextStream = await conn.CreateStreamAsync(DefaultGetHeaders);

            await outPipe.ReadAndDiscardHeaders(3u, false);

            Assert.Equal(3u, nextStream.Id);
            Assert.True(stream != nextStream);
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);
            Assert.Equal(StreamState.Open, nextStream.State);

            var hEncoder = new Http2.Hpack.Encoder();
            await inPipe.WriteHeaders(hEncoder, 3u, true, DefaultStatusHeaders);

            var nextStreamHeaders = await nextStream.ReadHeadersAsync();

            Assert.True(nextStreamHeaders.SequenceEqual(DefaultStatusHeaders));
            Assert.False(readHeadersTask.IsCompleted);
            Assert.Equal(StreamState.HalfClosedRemote, nextStream.State);
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);
            Assert.Equal(2, conn.ActiveStreamCount);

            await nextStream.WriteAsync(new ArraySegment <byte>(new byte[0]), true);

            await outPipe.ReadAndDiscardData(3u, true, 0);

            Assert.Equal(StreamState.Closed, nextStream.State);
            Assert.Equal(1, conn.ActiveStreamCount);

            var headers2 = DefaultStatusHeaders.Append(
                new HeaderField()
            {
                Name = "hh", Value = "vv"
            });
            await inPipe.WriteHeaders(hEncoder, 1u, false, headers2);

            var streamHeaders = await readHeadersTask;

            Assert.True(streamHeaders.SequenceEqual(headers2));
            await inPipe.WriteData(1u, 10, 0, true);

            var data = await stream.ReadAllToArrayWithTimeout();

            Assert.True(data.Length == 10);
            Assert.Equal(StreamState.Closed, stream.State);
            Assert.Equal(0, conn.ActiveStreamCount);
        }