private async Task <ReadHttpResponseMessage> SendAsync <TRequest>(RestMethod restMethod, string host, CallOptions options, TRequest request, CancellationToken deadlineToken) { // Ideally, add the header in the client builder instead of in the ServiceSettingsBase... var httpRequest = restMethod.CreateRequest((IMessage)request, host); foreach (var headerKeyValue in options.Headers .Where(mh => !mh.IsBinary) .Where(mh => mh.Key != VersionHeaderBuilder.HeaderName)) { httpRequest.Headers.Add(headerKeyValue.Key, headerKeyValue.Value); } httpRequest.Headers.Add(VersionHeaderBuilder.HeaderName, RestVersion); HttpResponseMessage httpResponseMessage; using (CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(options.CancellationToken, deadlineToken)) { try { await AddAuthHeadersAsync(httpRequest, restMethod, linkedCts.Token).ConfigureAwait(false); httpResponseMessage = await _httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseContentRead, linkedCts.Token).ConfigureAwait(false); } catch (TaskCanceledException ex) when(deadlineToken.IsCancellationRequested) { throw new RpcException(new Status(StatusCode.DeadlineExceeded, $"The timeout was reached when calling a method `{restMethod.FullName}`", ex)); } } try { string content = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); return(new ReadHttpResponseMessage(httpResponseMessage, content)); } catch (Exception ex) { // Let's defer the throwing of this exception to when it's actually needed, // so that we can at least read headers and other metadata. var exInfo = ExceptionDispatchInfo.Capture(ex); return(new ReadHttpResponseMessage(httpResponseMessage, exInfo)); } }
private async Task <HttpResponseMessage> SendAsync <TRequest>(RestMethod restMethod, string host, CallOptions options, TRequest request, CancellationToken cancellationToken) { // Ideally, add the header in the client builder instead of in the ServiceSettingsBase... // TODO: Use options. How do we set the timeout for an individual HTTP request? We probably need to create a linked cancellation token. var httpRequest = restMethod.CreateRequest((IMessage)request, host); foreach (var headerKeyValue in options.Headers .Where(mh => !mh.IsBinary) .Where(mh => mh.Key != VersionHeaderBuilder.HeaderName)) { httpRequest.Headers.Add(headerKeyValue.Key, headerKeyValue.Value); } httpRequest.Headers.Add(VersionHeaderBuilder.HeaderName, RestVersion); // TODO: How do we cancel this? await AddAuthHeadersAsync(httpRequest, restMethod).ConfigureAwait(false); var task = _httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseContentRead, cancellationToken); return(await task.ConfigureAwait(false)); }