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; } } } }
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; } } }
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); } } }
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; } } }
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); } }
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); }