示例#1
0
            public async Task SendRequestBodyAsync(CancellationToken cancellationToken)
            {
                // Send request body, if any
                if (_request.Content != null)
                {
                    try
                    {
                        using (Http2WriteStream writeStream = new Http2WriteStream(this))
                        {
                            await _request.Content.CopyToAsync(writeStream, null, cancellationToken).ConfigureAwait(false);
                        }

                        // Don't wait for completion, which could happen asynchronously.
                        _ = _connection.SendEndStreamAsync(_streamId);
                    }
                    catch (Exception e)
                    {
                        // We did not finish sending body so notify server.
                        _ = _connection.SendRstStreamAsync(_streamId, Http2ProtocolErrorCode.Cancel);

                        // if we decided abandon sending request and we get ObjectDisposed as result of it, just eat exception.
                        if (_shouldSendRequestBody || (!(e is ObjectDisposedException) && !(e.InnerException is ObjectDisposedException)))
                        {
                            throw;
                        }
                    }
                }
            }
示例#2
0
            public async Task SendRequestBodyAsync(CancellationToken cancellationToken)
            {
                // Send request body, if any
                if (_request.Content != null)
                {
                    try
                    {
                        using (Http2WriteStream writeStream = new Http2WriteStream(this))
                        {
                            // TODO: until #9071 is fixed, cancellation on content.CopyToAsync does not apply for most content types,
                            // because most content types aren't passed the token given to this internal overload of CopyToAsync.
                            // To work around it, we register to set _abortException as needed; this won't preempt reads issued to
                            // the source content, but it will at least enable the writes then performed on our write stream to see
                            // that cancellation was requested and abort, rather than waiting for the whole copy to complete.
                            using (cancellationToken.UnsafeRegister(stream =>
                            {
                                var thisRef = (Http2Stream)stream;
                                if (thisRef._abortException == null)
                                {
                                    Interlocked.CompareExchange(ref thisRef._abortException, new OperationCanceledException(), null);
                                }
                            }, this))
                            {
                                await _request.Content.CopyToAsync(writeStream, null, cancellationToken).ConfigureAwait(false);
                            }
                        }

                        // Don't wait for completion, which could happen asynchronously.
                        _connection.LogExceptions(_connection.SendEndStreamAsync(_streamId));
                    }
                    catch (Exception e)
                    {
                        // Try to notify server if we did not finish sending request body.
                        IgnoreExceptions(_connection.SendRstStreamAsync(_streamId, Http2ProtocolErrorCode.Cancel));

                        // if we decided abandon sending request and we get ObjectDisposed as result of it, just eat exception.
                        if (!_shouldSendRequestBody && (e is ObjectDisposedException || e.InnerException is ObjectDisposedException))
                        {
                            return;
                        }

                        if (_abortException == null)
                        {
                            // If we are still processing the response after receiving response headers,
                            // this will give us a chance to propagate exception up.
                            Interlocked.CompareExchange(ref _abortException, e, null);
                        }

                        throw;
                    }
                }
            }
示例#3
0
            public async Task SendRequestBodyAsync()
            {
                // 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.

                // Send request body, if any
                if (_request.Content != null)
                {
                    using (Http2WriteStream writeStream = new Http2WriteStream(this))
                    {
                        await _request.Content.CopyToAsync(writeStream).ConfigureAwait(false);
                    }
                }
            }
示例#4
0
            public async Task SendRequestBodyAsync(CancellationToken cancellationToken)
            {
                // Send request body, if any
                if (_request.Content != null)
                {
                    try
                    {
                        using (Http2WriteStream writeStream = new Http2WriteStream(this))
                        {
                            // TODO: until #9071 is fixed, cancellation on content.CopyToAsync does not work.
                            // To work around it, register delegate and set _abortException as needed.
                            using (cancellationToken.UnsafeRegister(stream => { if (((Http2Stream)stream)._abortException == null)
                                                                                {
                                                                                    ((Http2Stream)stream)._abortException = new OperationCanceledException();
                                                                                }
                                                                    }, this))
                            {
                                await _request.Content.CopyToAsync(writeStream, null, cancellationToken).ConfigureAwait(false);
                            }
                        }

                        // Don't wait for completion, which could happen asynchronously.
                        _connection.LogExceptions(_connection.SendEndStreamAsync(_streamId));
                    }
                    catch (Exception e)
                    {
                        // Try to notify server if we did not finish sending request body.
                        IgnoreExceptions(_connection.SendRstStreamAsync(_streamId, Http2ProtocolErrorCode.Cancel));

                        // if we decided abandon sending request and we get ObjectDisposed as result of it, just eat exception.
                        if (!_shouldSendRequestBody && (e is ObjectDisposedException || e.InnerException is ObjectDisposedException))
                        {
                            return;
                        }

                        if (_abortException == null)
                        {
                            // If we are still the response after receiving response headers, this will give us a chance to propagate exception up.
                            // Since we failed while Copying stream, wrap it as IOException if needed.
                            _abortException = e;
                        }

                        throw;
                    }
                }
            }
示例#5
0
            public async Task SendRequestBodyAsync(CancellationToken cancellationToken)
            {
                // 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.

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

                    // Don't wait for completion, which could happen asynchronously.
                    Task ignored = _connection.SendEndStreamAsync(_streamId);
                }
            }
示例#6
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);
            }