예제 #1
0
            public Http2Stream(HttpRequestMessage request, Http2Connection connection, int streamId, int initialWindowSize)
            {
                _connection = connection;
                _streamId   = streamId;

                _request         = request;
                _responseContent = new HttpConnectionResponseContent();
                _response        = new HttpResponseMessage()
                {
                    Version = HttpVersion.Version20, RequestMessage = request, Content = _responseContent
                };

                _syncObject = new object();
                _disposed   = false;

                _responseBuffer = new ArrayBuffer(InitialBufferSize);

                _streamWindow = new CreditManager(initialWindowSize);

                _responseHeadersAvailable = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

                // TODO: ISSUE 31313: Avoid allocating a TaskCompletionSource repeatedly by using a resettable ValueTaskSource.
                // See: https://github.com/dotnet/corefx/blob/master/src/Common/tests/System/Threading/Tasks/Sources/ManualResetValueTaskSource.cs
                _responseDataAvailable = null;
            }
예제 #2
0
            public async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                // TODO: ISSUE 31310: Cancellation support

                try
                {
                    HttpConnectionResponseContent responseContent = new HttpConnectionResponseContent();
                    _response = new HttpResponseMessage()
                    {
                        Version = HttpVersion.Version20, RequestMessage = request, Content = responseContent
                    };

                    // TODO: ISSUE 31312: Expect: 100-continue and early response handling
                    // Note that in an "early response" scenario, where we get a response before we've finished sending the request body
                    // (either with a 100-continue that timed out, or without 100-continue),
                    // we can stop send a RST_STREAM on the request stream and stop sending the request without tearing down the entire connection.

                    // TODO: ISSUE 31313: Avoid allocating a TaskCompletionSource repeatedly by using a resettable ValueTaskSource.
                    // See: https://github.com/dotnet/corefx/blob/master/src/Common/tests/System/Threading/Tasks/Sources/ManualResetValueTaskSource.cs
                    Debug.Assert(_responseDataAvailable == null);
                    _responseDataAvailable = new TaskCompletionSource <bool>();
                    Task readDataAvailableTask = _responseDataAvailable.Task;

                    // Send headers
                    await _connection.SendHeadersAsync(_streamId, request).ConfigureAwait(false);

                    // Send request body, if any
                    if (request.Content != null)
                    {
                        using (Http2WriteStream writeStream = new Http2WriteStream(this))
                        {
                            await request.Content.CopyToAsync(writeStream).ConfigureAwait(false);
                        }
                    }

                    // Wait for response headers to be read.
                    await readDataAvailableTask.ConfigureAwait(false);

                    // Start to process the response body.
                    bool emptyResponse = false;
                    lock (_syncObject)
                    {
                        if (_responseComplete && _responseBuffer.ActiveSpan.Length == 0)
                        {
                            if (_responseAborted)
                            {
                                throw new IOException(SR.net_http_invalid_response);
                            }

                            emptyResponse = true;
                        }
                    }

                    if (emptyResponse)
                    {
                        responseContent.SetStream(EmptyReadStream.Instance);
                    }
                    else
                    {
                        responseContent.SetStream(new Http2ReadStream(this));
                    }

                    // Process Set-Cookie headers.
                    if (_connection._pool.Settings._useCookies)
                    {
                        CookieHelper.ProcessReceivedCookies(_response, _connection._pool.Settings._cookieContainer);
                    }
                }
                catch (Exception e)
                {
                    Dispose();

                    if (e is IOException ioe)
                    {
                        throw new HttpRequestException(SR.net_http_client_execution_error, ioe);
                    }
                    else if (e is ObjectDisposedException)
                    {
                        throw new HttpRequestException(SR.net_http_client_execution_error);
                    }
                    else if (e is Http2ProtocolException)
                    {
                        // ISSUE 31315: Determine if/how to expose HTTP2 error codes
                        throw new HttpRequestException(SR.net_http_client_execution_error);
                    }
                    else
                    {
                        throw;
                    }
                }

                return(_response);
            }
예제 #3
0
            public async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                // TODO: ISSUE 31310: Cancellation support

                WriteHeaders(request);

                // Send request body, if any
                if (request.Content != null)
                {
                    throw new NotImplementedException("Request body not supported yet");
                }

                // Construct response

                HttpConnectionResponseContent responseContent = new HttpConnectionResponseContent();

                _response = new HttpResponseMessage()
                {
                    Version = HttpVersion.Version20, RequestMessage = request, Content = responseContent
                };

                // TODO: ISSUE 31312: Expect: 100-continue and early response handling
                // Note that in an "early response" scenario, where we get a response before we've finished sending the request body
                // (either with a 100-continue that timed out, or without 100-continue),
                // we can stop send a RST_STREAM on the request stream and stop sending the request without tearing down the entire connection.

                // TODO: ISSUE 31313: Avoid allocating a TaskCompletionSource repeatedly by using a resettable ValueTaskSource.
                // See: https://github.com/dotnet/corefx/blob/master/src/Common/tests/System/Threading/Tasks/Sources/ManualResetValueTaskSource.cs
                Debug.Assert(_responseDataAvailable == null);
                _responseDataAvailable = new TaskCompletionSource <bool>();
                Task readDataAvailableTask = _responseDataAvailable.Task;

                await _connection.SendFramesAsync(_requestBuffer.ActiveMemory).ConfigureAwait(false);

                _requestBuffer.Discard(_requestBuffer.ActiveSpan.Length);

                // Wait for response headers to be read.
                await readDataAvailableTask.ConfigureAwait(false);

                // Start to process the response body.
                bool emptyResponse = false;

                lock (_syncObject)
                {
                    if (_responseComplete && _responseBuffer.ActiveSpan.Length == 0)
                    {
                        if (_responseAborted)
                        {
                            throw new IOException(SR.net_http_invalid_response);
                        }

                        emptyResponse = true;
                    }
                }

                if (emptyResponse)
                {
                    responseContent.SetStream(EmptyReadStream.Instance);
                }
                else
                {
                    responseContent.SetStream(new Http2ReadStream(this));
                }

                return(_response);
            }