private static async Task <HttpResponseMessage> GetHttpRequestResponseAsync( HttpClient httpClient, string method, string url, HttpContent content, IDictionary <string, string> headers, Options options, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // Only POST, PUT, PATCH and DELETE can have content, otherwise the HttpClient will fail var isContentAllowed = Enum.TryParse(method, ignoreCase: true, result: out SendMethod _); using (var request = new HttpRequestMessage(new HttpMethod(method), new Uri(url)) { Content = isContentAllowed ? content : null, }) { //Clear default headers content.Headers.Clear(); foreach (var header in headers) { var requestHeaderAddedSuccessfully = request.Headers.TryAddWithoutValidation(header.Key, header.Value); if (!requestHeaderAddedSuccessfully && request.Content != null) { //Could not add to request headers try to add to content headers // this check is probably not needed anymore as the new HttpClient does not seem fail on malformed headers var contentHeaderAddedSuccessfully = content.Headers.TryAddWithoutValidation(header.Key, header.Value); if (!contentHeaderAddedSuccessfully) { Trace.TraceWarning($"Could not add header {header.Key}:{header.Value}"); } } } var credentials = new ImmutableCredentials(options.AWSConnectionInfo.AccessKey, options.AWSConnectionInfo.SecretKey, null); string regionName = options.AWSConnectionInfo.Region.ToCodeString(); string serviceName = options.AWSConnectionInfo.ServiceName; HttpResponseMessage response; try { response = await httpClient.SendAsync(request, cancellationToken, regionName, serviceName, credentials).ConfigureAwait(false); } catch (TaskCanceledException canceledException) { if (cancellationToken.IsCancellationRequested) { // Cancellation is from outside -> Just throw throw; } // Cancellation is from inside of the request, mostly likely a timeout throw new Exception("HttpRequest was canceled, most likely due to a timeout.", canceledException); } // this check is probably not needed anymore as the new HttpClient does not fail on invalid charsets if (options.AllowInvalidResponseContentTypeCharSet && response.Content.Headers?.ContentType != null) { response.Content.Headers.ContentType.CharSet = null; } return(response); } }
/// <summary> /// Generic http request task that signs the request using AWS Signature Version 4. Uses 3rd party library AwsSignatureVersion4 to perform the signing. /// Documentation: https://github.com/CommunityHiQ/Frends.Community.AWS.Http /// </summary> /// <param name="input">Input parameters</param> /// <param name="options">AWS authentication and optional parameters</param> /// <param name="cancellationToken"></param> /// <returns>Object with the following properties: string Body, Dictionary(string,string) Headers. int StatusCode</returns> public static async Task <object> HttpRequestWithAWSSigV4([PropertyTab] Input input, [PropertyTab] Options options, CancellationToken cancellationToken) { var httpClient = GetHttpClientForOptions(options); var headers = GetHeaderDictionary(input.Headers); using (var content = GetContent(input, headers)) { using (var responseMessage = await GetHttpRequestResponseAsync( httpClient, input.Method.ToString(), input.Url, content, headers, options, cancellationToken) .ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); var response = new HttpResponse() { Body = responseMessage.Content != null ? await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false) : null, StatusCode = (int)responseMessage.StatusCode, Headers = GetResponseHeaderDictionary(responseMessage.Headers, responseMessage.Content?.Headers) }; if (!responseMessage.IsSuccessStatusCode && options.ThrowExceptionOnErrorResponse) { throw new WebException( $"Request to '{input.Url}' failed with status code {(int)responseMessage.StatusCode}. Response body: {response.Body}"); } return(response); } } }