コード例 #1
0
        protected static HttpClientHandler CreateHttpClientHandler(bool useSocketsHttpHandler, bool useHttp2LoopbackServer = false)
        {
            HttpClientHandler handler;

            if (PlatformDetection.IsUap || PlatformDetection.IsFullFramework || useSocketsHttpHandler)
            {
                handler = new HttpClientHandler();
            }
            else
            {
                // Create platform specific handler.
                ConstructorInfo ctor = typeof(HttpClientHandler).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(bool) }, null);
                Debug.Assert(ctor != null, "Couldn't find test constructor on HttpClientHandler");

                handler = (HttpClientHandler)ctor.Invoke(new object[] { useSocketsHttpHandler });
                Debug.Assert(useSocketsHttpHandler == IsSocketsHttpHandler(handler), "Unexpected handler.");
            }

            TestHelper.EnsureHttp2Feature(handler);

            if (useHttp2LoopbackServer)
            {
                handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            }

            return(handler);
        }
コード例 #2
0
        public async Task Http2_InitialSettings_SentAndAcked()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    // Receive the initial client settings frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.Settings, receivedFrame.Type);

                    // Send the initial server settings frame.
                    Frame emptySettings = new Frame(0, FrameType.Settings, FrameFlags.None, 0);
                    await server.WriteFrameAsync(emptySettings).ConfigureAwait(false);

                    // Receive the server settings frame ACK.
                    receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.Settings, receivedFrame.Type);
                    Assert.True(receivedFrame.AckFlag);
                }
        }
コード例 #3
0
        public async Task Http2_StreamResetByServer_RequestFails()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    await server.SendConnectionPrefaceAsync();

                    // Receive the request header frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    // Send a reset stream frame so that stream 1 moves to a terminal state.
                    RstStreamFrame resetStream = new RstStreamFrame(FrameFlags.Padded, 0x1, 1);
                    await server.WriteFrameAsync(resetStream);

                    // This currently throws an IOException.
                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
コード例 #4
0
        public async Task ClosedStream_FrameReceived_ResetsStream()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    await server.SendConnectionPrefaceAsync();

                    // Receive the request header frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    // Send a reset stream frame so that stream 1 moves to a terminal state.
                    RstStreamFrame resetStream = new RstStreamFrame(FrameFlags.Padded, 0x1, 1);
                    await server.WriteFrameAsync(resetStream);

                    // Send a frame on the now-closed stream.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.Padded, 10, 1);
                    await server.WriteFrameAsync(invalidFrame);

                    // Receive a RST_STREAM frame.
                    receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.RstStream, receivedFrame.Type);

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
コード例 #5
0
        public async Task DataFrame_TooLong_ConnectionError()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    await server.SendConnectionPrefaceAsync();

                    // Receive the request header frame.
                    Frame receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    // Send a malformed frame.
                    DataFrame invalidFrame = new DataFrame(new byte[Frame.MaxFrameLength + 1], FrameFlags.None, 0, 0);
                    await server.WriteFrameAsync(invalidFrame);

                    // As this is a connection level error, the client should see the request fail.
                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);

                    // The server should receive a GOAWAY frame.
                    receivedFrame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    Assert.Equal(FrameType.GoAway, receivedFrame.Type);
                }
        }
コード例 #6
0
        public async Task Http2_ClientPreface_Sent()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    string connectionPreface = await server.AcceptConnectionAsync();

                    Assert.Equal("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", connectionPreface);
                }
        }
コード例 #7
0
        public async Task Http2_DataSentBeforeServerPreface_ProtocolError()
        {
            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task sendTask = client.GetAsync(server.Address);

                    await server.AcceptConnectionAsync();

                    // Send a frame despite not having sent the server connection preface.
                    DataFrame invalidFrame = new DataFrame(new byte[10], FrameFlags.Padded, 10, 1);
                    await server.WriteFrameAsync(invalidFrame);

                    // This currently throws an Http2ProtocolException, but that type is not public.
                    await Assert.ThrowsAsync <HttpRequestException>(async() => await sendTask);
                }
        }
コード例 #8
0
        public async Task Http2_FlowControl_ClientDoesNotExceedWindows()
        {
            const int InitialWindowSize = 65535;
            const int ContentSize       = 100_000;

            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            var content = new ByteArrayContent(TestHelper.GenerateRandomContent(ContentSize));

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> clientTask = client.PostAsync(server.Address, content);

                    await server.EstablishConnectionAsync();

                    Frame frame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    int streamId = frame.StreamId;
                    Assert.Equal(FrameType.Headers, frame.Type);
                    Assert.Equal(FrameFlags.EndHeaders, frame.Flags);

                    // Receive up to initial window size
                    int bytesReceived = 0;
                    while (bytesReceived < InitialWindowSize)
                    {
                        frame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                        Assert.Equal(streamId, frame.StreamId);
                        Assert.Equal(FrameType.Data, frame.Type);
                        Assert.Equal(FrameFlags.None, frame.Flags);
                        Assert.True(frame.Length > 0);

                        bytesReceived += frame.Length;
                    }

                    Assert.Equal(InitialWindowSize, bytesReceived);

                    // Issue another read. It shouldn't complete yet. Wait a brief period of time to ensure it doesn't complete.
                    Task <Frame> readFrameTask = server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase connection window by one. This should still not complete the read.
                    await server.WriteFrameAsync(new WindowUpdateFrame(1, 0));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase stream window by two. This should complete the read with a single byte.
                    await server.WriteFrameAsync(new WindowUpdateFrame(2, streamId));

                    frame = await readFrameTask;
                    Assert.Equal(1, frame.Length);
                    bytesReceived++;

                    // Issue another read and ensure it doesn't complete yet.
                    readFrameTask = server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase connection window by two. This should complete the read with a single byte.
                    await server.WriteFrameAsync(new WindowUpdateFrame(2, 0));

                    frame = await readFrameTask;
                    Assert.Equal(1, frame.Length);
                    bytesReceived++;

                    // Issue another read and ensure it doesn't complete yet.
                    readFrameTask = server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase connection window to allow exactly the remaining request size. This should still not complete the read.
                    await server.WriteFrameAsync(new WindowUpdateFrame(ContentSize - bytesReceived - 1, 0));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase stream window to allow exactly the remaining request size. This should allow the rest of the request to be sent.
                    await server.WriteFrameAsync(new WindowUpdateFrame(ContentSize - bytesReceived, streamId));

                    frame = await readFrameTask;
                    Assert.Equal(streamId, frame.StreamId);
                    Assert.Equal(FrameType.Data, frame.Type);
                    Assert.Equal(FrameFlags.None, frame.Flags);
                    Assert.True(frame.Length > 0);

                    bytesReceived += frame.Length;

                    // Read to end of stream
                    while (true)
                    {
                        frame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                        if (frame.EndStreamFlag)
                        {
                            break;
                        }

                        Assert.Equal(streamId, frame.StreamId);
                        Assert.Equal(FrameType.Data, frame.Type);
                        Assert.Equal(FrameFlags.None, frame.Flags);
                        Assert.True(frame.Length > 0);

                        bytesReceived += frame.Length;
                    }

                    Assert.Equal(ContentSize, bytesReceived);

                    // Verify EndStream frame
                    Assert.Equal(streamId, frame.StreamId);
                    Assert.Equal(FrameType.Data, frame.Type);
                    Assert.Equal(FrameFlags.EndStream, frame.Flags);
                    Assert.True(frame.Length == 0);

                    await server.SendDefaultResponseAsync(streamId);

                    HttpResponseMessage response = await clientTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }
        }
コード例 #9
0
        public async Task Http2_InitialWindowSize_ClientDoesNotExceedWindows()
        {
            const int DefaultInitialWindowSize = 65535;
            const int ContentSize = 100_000;

            HttpClientHandler handler = CreateHttpClientHandler();

            handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
            TestHelper.EnsureHttp2Feature(handler);

            var content = new ByteArrayContent(TestHelper.GenerateRandomContent(ContentSize));

            using (var server = Http2LoopbackServer.CreateServer())
                using (var client = new HttpClient(handler))
                {
                    Task <HttpResponseMessage> clientTask = client.PostAsync(server.Address, content);

                    await server.EstablishConnectionAsync();

                    // Bump connection window so it won't block the client.
                    await server.WriteFrameAsync(new WindowUpdateFrame(ContentSize - DefaultInitialWindowSize, 0));

                    Frame frame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    int streamId = frame.StreamId;
                    Assert.Equal(FrameType.Headers, frame.Type);
                    Assert.Equal(FrameFlags.EndHeaders, frame.Flags);

                    // Receive up to initial window size
                    int bytesReceived = 0;
                    while (bytesReceived < DefaultInitialWindowSize)
                    {
                        frame = await server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                        Assert.Equal(streamId, frame.StreamId);
                        Assert.Equal(FrameType.Data, frame.Type);
                        Assert.Equal(FrameFlags.None, frame.Flags);
                        Assert.True(frame.Length > 0);

                        bytesReceived += frame.Length;
                    }

                    Assert.Equal(DefaultInitialWindowSize, bytesReceived);

                    // Issue another read. It shouldn't complete yet. Wait a brief period of time to ensure it doesn't complete.
                    Task <Frame> readFrameTask = server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Change SETTINGS_INITIAL_WINDOW_SIZE to 0. This will make the client's credit go negative.
                    server.ExpectSettingsAck();
                    await server.WriteFrameAsync(new SettingsFrame(new SettingsEntry {
                        SettingId = SettingId.InitialWindowSize, Value = 0
                    }));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase stream window by one. Client credit will still be negative.
                    await server.WriteFrameAsync(new WindowUpdateFrame(1, streamId));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Change SETTINGS_INITIAL_WINDOW_SIZE to 1. Client credit will still be negative.
                    server.ExpectSettingsAck();
                    await server.WriteFrameAsync(new SettingsFrame(new SettingsEntry {
                        SettingId = SettingId.InitialWindowSize, Value = 1
                    }));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase stream window so client credit will be 0.
                    await server.WriteFrameAsync(new WindowUpdateFrame(DefaultInitialWindowSize - 2, streamId));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase stream window by one, so client can now send a single byte.
                    await server.WriteFrameAsync(new WindowUpdateFrame(1, streamId));

                    frame = await readFrameTask;
                    Assert.Equal(FrameType.Data, frame.Type);
                    Assert.Equal(1, frame.Length);
                    bytesReceived++;

                    // Issue another read and ensure it doesn't complete yet.
                    readFrameTask = server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase SETTINGS_INITIAL_WINDOW_SIZE to 2, so client can now send a single byte.
                    server.ExpectSettingsAck();
                    await server.WriteFrameAsync(new SettingsFrame(new SettingsEntry {
                        SettingId = SettingId.InitialWindowSize, Value = 2
                    }));

                    frame = await readFrameTask;
                    Assert.Equal(FrameType.Data, frame.Type);
                    Assert.Equal(1, frame.Length);
                    bytesReceived++;

                    // Issue another read and ensure it doesn't complete yet.
                    readFrameTask = server.ReadFrameAsync(TimeSpan.FromSeconds(30));

                    await Task.Delay(500);

                    Assert.False(readFrameTask.IsCompleted);

                    // Increase SETTINGS_INITIAL_WINDOW_SIZE to be enough that the client can send the rest of the content.
                    server.ExpectSettingsAck();
                    await server.WriteFrameAsync(new SettingsFrame(new SettingsEntry {
                        SettingId = SettingId.InitialWindowSize, Value = ContentSize - (DefaultInitialWindowSize - 1)
                    }));

                    frame = await readFrameTask;
                    Assert.Equal(streamId, frame.StreamId);
                    Assert.Equal(FrameType.Data, frame.Type);
                    Assert.Equal(FrameFlags.None, frame.Flags);
                    Assert.True(frame.Length > 0);

                    bytesReceived += frame.Length;

                    // Read to end of stream
                    bytesReceived += await ReadToEndOfStream(server, streamId);

                    Assert.Equal(ContentSize, bytesReceived);

                    await server.SendDefaultResponseAsync(streamId);

                    HttpResponseMessage response = await clientTask;
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }
        }
コード例 #10
0
        public async Task SendAsync_RemoteServersWithCookies_Success(Uri remoteServer)
        {
            // CurlHandler: cookies from container are not sent if a Cookie header is manually added #26983.
            if (IsCurlHandler)
            {
                return;
            }

            var expectedVersion       = new Version(1, 1);
            HttpClientHandler handler = CreateHttpClientHandler();

            if (remoteServer.Host == Configuration.Http.Http2Host && BackendSupportsAlpn)
            {
                // Windows 10 Anniversary release a.k.a Windows 10 Version 1607 added support to native WinHTTP for HTTP/2 protocol support.
                if (IsWinHttpHandler && !PlatformDetection.IsWindows10Version1607OrGreater)
                {
                    return;
                }

                expectedVersion = new Version(2, 0);
                TestHelper.EnsureHttp2Feature(handler);
            }

            using (HttpClient client = new HttpClient(handler))
            {
                var request = new HttpRequestMessage(HttpMethod.Get, remoteServer)
                {
                    Version = expectedVersion,
                };

                // Make remote server send SetCookie header.
                request.Headers.Add("X-SetCookie", "name=value");
                request.Headers.Add("X-SetCookie", "name1=value1");
                request.Headers.Add("X-SetCookie", "name2=value2");

                using (HttpResponseMessage response = await client.SendAsync(request))
                {
                    Assert.Equal(expectedVersion, response.Version);
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    // Verify server sends back SetCookie header.
                    Assert.Contains("Set-Cookie: name=value, name1=value1, name2=value2", response.Headers.ToString());

                    // Server does not have any cookies yet.
                    Assert.Contains("\"Cookies\": {}", await response.Content.ReadAsStringAsync());
                }

                // Send next request to see if the cookie has been wrote to the header.
                var newRequest = new HttpRequestMessage(HttpMethod.Get, remoteServer)
                {
                    Version = expectedVersion,
                };

                // Send additional cookie (along with the ones from CookieContainer).
                newRequest.Headers.Add("Cookie", "cookie=c1");

                using (HttpResponseMessage response = await client.SendAsync(newRequest))
                {
                    Assert.Equal(expectedVersion, response.Version);
                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

                    // Verify server received all cookies.
                    string body = await response.Content.ReadAsStringAsync();

                    Assert.Contains("\"Cookies\": ", body);
                    Assert.Contains("\"name\": \"value\"", body);
                    Assert.Contains("\"name1\": \"value1\"", body);
                    Assert.Contains("\"name2\": \"value2\"", body);
                    Assert.Contains("\"cookie\": \"c1\"", body);
                }
            }
        }