Пример #1
0
        // This will automatically handle the control stream, including validating its contents
        public async Task <Http3LoopbackStream> AcceptRequestStreamAsync()
        {
            Http3LoopbackStream requestStream = null;

            while (true)
            {
                var stream = await AcceptStreamAsync().ConfigureAwait(false);

                // Accepted request stream.
                if (stream.CanWrite)
                {
                    // Only one expected.
                    Assert.True(requestStream is null, "Expected single request stream, got a second");

                    // Control stream is set --> return the request stream.
                    if (_inboundControlStream is not null)
                    {
                        return(stream);
                    }

                    // Control stream not set --> need to accept another stream.
                    requestStream = stream;
                    continue;
                }

                // Must be the control stream.
                await HandleControlStreamAsync(stream);

                // We've already accepted request stream --> return it.
                if (requestStream is not null)
                {
                    return(requestStream);
                }
            }
        }
Пример #2
0
        public async Task EstablishControlStreamAsync()
        {
            _outboundControlStream = await OpenUnidirectionalStreamAsync();

            await _outboundControlStream.SendUnidirectionalStreamTypeAsync(Http3LoopbackStream.ControlStream);

            await _outboundControlStream.SendSettingsFrameAsync();
        }
Пример #3
0
        public async Task <(Http3LoopbackStream clientControlStream, Http3LoopbackStream requestStream)> AcceptControlAndRequestStreamAsync()
        {
            Http3LoopbackStream requestStream = await AcceptRequestStreamAsync();

            Http3LoopbackStream controlStream = _inboundControlStream;

            return(controlStream, requestStream);
        }
Пример #4
0
        public async Task <Http3LoopbackStream> AcceptStreamAsync()
        {
            QuicStream quicStream = await _connection.AcceptStreamAsync().ConfigureAwait(false);

            var stream = new Http3LoopbackStream(quicStream);

            _openStreams.Add(checked ((int)quicStream.StreamId), stream);
            _currentStream = stream;

            return(stream);
        }
Пример #5
0
        public override async Task SendResponseBodyAsync(byte[] content, bool isFinal = true, int requestId = 0)
        {
            Http3LoopbackStream stream = GetOpenRequest(requestId);

            if (content?.Length != 0)
            {
                await stream.SendDataFrameAsync(content).ConfigureAwait(false);
            }

            if (isFinal)
            {
                stream.ShutdownSend();
                stream.Dispose();
            }
        }
Пример #6
0
        public async Task <(Http3LoopbackStream clientControlStream, Http3LoopbackStream requestStream)> AcceptControlAndRequestStreamAsync()
        {
            Http3LoopbackStream streamA = null, streamB = null;

            try
            {
                streamA = await AcceptStreamAsync();

                streamB = await AcceptStreamAsync();

                return((streamA.CanWrite, streamB.CanWrite) switch
                {
                    (false, true) => (streamA, streamB),
                    (true, false) => (streamB, streamA),
                    _ => throw new Exception("Expected one unidirectional and one bidirectional stream; received something else.")
                });
            }
Пример #7
0
        public override async Task <HttpRequestData> HandleRequestAsync(HttpStatusCode statusCode = HttpStatusCode.OK, IList <HttpHeaderData> headers = null, string content = "")
        {
            Http3LoopbackStream stream = await AcceptRequestStreamAsync().ConfigureAwait(false);

            HttpRequestData request = await stream.ReadRequestDataAsync().ConfigureAwait(false);

            // We are about to close the connection, after we send the response.
            // So, send a GOAWAY frame now so the client won't inadvertantly try to reuse the connection.
            // Note that in HTTP3 (unlike HTTP2) there is no strict ordering between the GOAWAY and the response below;
            // so the client may race in processing them and we need to handle this.
            await _outboundControlStream.SendGoAwayFrameAsync(stream.StreamId + 4);

            await stream.SendResponseAsync(statusCode, headers, content).ConfigureAwait(false);

            await WaitForClientDisconnectAsync();

            return(request);
        }
Пример #8
0
        // This will automatically handle the control stream, including validating its contents
        public async Task <Http3LoopbackStream> AcceptRequestStreamAsync()
        {
            await EnsureControlStreamAcceptedAsync().ConfigureAwait(false);

            if (!_delayedStreams.TryDequeue(out QuicStream quicStream))
            {
                quicStream = await _connection.AcceptInboundStreamAsync().ConfigureAwait(false);
            }

            var stream = new Http3LoopbackStream(quicStream);

            Assert.True(quicStream.CanWrite, "Expected writeable stream.");

            _openStreams.Add(checked ((int)quicStream.Id), stream);
            _currentStream   = stream;
            _currentStreamId = quicStream.Id;

            return(stream);
        }
Пример #9
0
        private Task EnsureControlStreamAcceptedAsync()
        {
            if (_inboundControlStream != null)
            {
                return(Task.CompletedTask);
            }

            return(EnsureControlStreamAcceptedInternalAsync());

            async Task EnsureControlStreamAcceptedInternalAsync()
            {
                Http3LoopbackStream controlStream;

                while (true)
                {
                    QuicStream quicStream = await _connection.AcceptInboundStreamAsync().ConfigureAwait(false);

                    if (!quicStream.CanWrite)
                    {
                        // control stream accepted
                        controlStream = new Http3LoopbackStream(quicStream);
                        break;
                    }

                    // control streams are unidirectional, so this must be a request stream
                    // keep it for later and wait for another stream
                    _delayedStreams.Enqueue(quicStream);
                }

                long?streamType = await controlStream.ReadIntegerAsync();

                Assert.Equal(Http3LoopbackStream.ControlStream, streamType);

                List <(long settingId, long settingValue)> settings = await controlStream.ReadSettingsAsync();

                (long settingId, long settingValue) = Assert.Single(settings);

                Assert.Equal(Http3LoopbackStream.MaxHeaderListSize, settingId);
                MaxHeaderListSize = settingValue;

                _inboundControlStream = controlStream;
            }
        }
Пример #10
0
        private async Task HandleControlStreamAsync(Http3LoopbackStream controlStream)
        {
            if (_inboundControlStream is not null)
            {
                throw new Exception("Received second control stream from client???");
            }

            long?streamType = await controlStream.ReadIntegerAsync();

            Assert.Equal(Http3LoopbackStream.ControlStream, streamType);

            List <(long settingId, long settingValue)> settings = await controlStream.ReadSettingsAsync();

            (long settingId, long settingValue) = Assert.Single(settings);

            Assert.Equal(Http3LoopbackStream.MaxHeaderListSize, settingId);

            _inboundControlStream = controlStream;
        }
Пример #11
0
        public override async Task <HttpRequestData> ReadRequestDataAsync(bool readBody = true)
        {
            Http3LoopbackStream stream = await AcceptRequestStreamAsync().ConfigureAwait(false);

            return(await stream.ReadRequestDataAsync(readBody).ConfigureAwait(false));
        }