/// <summary> /// Constructs a HttpRequestMessage builder. For AWS, this function has the side-effect of overriding the baseUrl /// in the HttpClient with region specific host path or virtual style path. /// </summary> /// <param name="method">HTTP method</param> /// <param name="bucketName">Bucket Name</param> /// <param name="objectName">Object Name</param> /// <param name="headerMap">headerMap</param> /// <param name="contentType">Content Type</param> /// <param name="body">request body</param> /// <param name="resourcePath">query string</param> /// <returns>A HttpRequestMessage builder</returns> internal async Task <HttpRequestMessageBuilder> CreateRequest( HttpMethod method, string bucketName = null, string objectName = null, Dictionary <string, string> headerMap = null, string contentType = "application/octet-stream", byte[] body = null, string resourcePath = null) { string region = string.Empty; if (bucketName != null) { utils.ValidateBucketName(bucketName); // Fetch correct region for bucket region = await GetRegion(bucketName).ConfigureAwait(false); } if (objectName != null) { utils.ValidateObjectName(objectName); } // This section reconstructs the url with scheme followed by location specific endpoint (s3.region.amazonaws.com) // or Virtual Host styled endpoint (bucketname.s3.region.amazonaws.com) for Amazon requests. string resource = string.Empty; bool usePathStyle = false; if (bucketName != null) { if (s3utils.IsAmazonEndPoint(this.BaseUrl)) { usePathStyle = false; if (method == HttpMethod.Put && objectName == null && resourcePath == null) { // use path style for make bucket to workaround "AuthorizationHeaderMalformed" error from s3.amazonaws.com usePathStyle = true; } else if (resourcePath != null && resourcePath.Contains("location")) { // use path style for location query usePathStyle = true; } else if (bucketName != null && bucketName.Contains(".") && this.Secure) { // use path style where '.' in bucketName causes SSL certificate validation error usePathStyle = true; } if (usePathStyle) { resource += utils.UrlEncode(bucketName) + "/"; } } else { resource += utils.UrlEncode(bucketName) + "/"; } } // Set Target URL Uri requestUrl = RequestUtil.MakeTargetURL(this.BaseUrl, this.Secure, bucketName, region, usePathStyle); if (objectName != null) { resource += utils.EncodePath(objectName); } // Append query string passed in if (resourcePath != null) { resource += resourcePath; } var messageBuilder = new HttpRequestMessageBuilder(method, requestUrl, resource); if (body != null) { messageBuilder.SetBody(body); } if (headerMap != null) { foreach (var entry in headerMap) { messageBuilder.AddHeaderParameter(entry.Key, entry.Value); } } return(messageBuilder); }
/// <summary> /// Constructs an HttpRequestMessage builder. For AWS, this function has the side-effect of overriding the baseUrl /// in the HttpClient with region specific host path or virtual style path. /// </summary> /// <param name="method">HTTP method</param> /// <param name="bucketName">Bucket Name</param> /// <param name="objectName">Object Name</param> /// <param name="headerMap">headerMap</param> /// <param name="contentType">Content Type</param> /// <param name="body">request body</param> /// <param name="resourcePath">query string</param> /// <returns>A HttpRequestMessage builder</returns> /// <exception cref="BucketNotFoundException">When bucketName is invalid</exception> internal async Task <HttpRequestMessageBuilder> CreateRequest( HttpMethod method, string bucketName = null, string objectName = null, Dictionary <string, string> headerMap = null, string contentType = "application/octet-stream", byte[] body = null, string resourcePath = null) { string region = string.Empty; if (bucketName != null) { utils.ValidateBucketName(bucketName); // Fetch correct region for bucket if this is not a bucket creation if (!string.IsNullOrEmpty(objectName) && method != HttpMethod.Put) { region = await GetRegion(bucketName).ConfigureAwait(false); } } if (objectName != null) { utils.ValidateObjectName(objectName); } if (this.Provider != null) { bool isAWSEnvProvider = (this.Provider is AWSEnvironmentProvider) || (this.Provider is ChainedProvider ch && ch.CurrentProvider is AWSEnvironmentProvider); bool isIAMAWSProvider = (this.Provider is IAMAWSProvider) || (this.Provider is ChainedProvider chained && chained.CurrentProvider is AWSEnvironmentProvider); AccessCredentials creds = null; if (isAWSEnvProvider) { var aWSEnvProvider = (AWSEnvironmentProvider)this.Provider; creds = await aWSEnvProvider.GetCredentialsAsync(); } else if (isIAMAWSProvider) { var iamAWSProvider = (IAMAWSProvider)this.Provider; creds = iamAWSProvider.Credentials; } else { creds = await this.Provider.GetCredentialsAsync(); } if (creds != null) { this.AccessKey = creds.AccessKey; this.SecretKey = creds.SecretKey; } } // This section reconstructs the url with scheme followed by location specific endpoint (s3.region.amazonaws.com) // or Virtual Host styled endpoint (bucketname.s3.region.amazonaws.com) for Amazon requests. string resource = string.Empty; bool usePathStyle = false; if (bucketName != null) { if (s3utils.IsAmazonEndPoint(this.BaseUrl)) { if (method == HttpMethod.Put && objectName == null && resourcePath == null) { // use path style for make bucket to workaround "AuthorizationHeaderMalformed" error from s3.amazonaws.com usePathStyle = true; } else if (resourcePath != null && resourcePath.Contains("location")) { // use path style for location query usePathStyle = true; } else if (bucketName != null && bucketName.Contains(".") && this.Secure) { // use path style where '.' in bucketName causes SSL certificate validation error usePathStyle = true; } if (usePathStyle) { resource += utils.UrlEncode(bucketName) + "/"; } } } // Set Target URL Uri requestUrl = RequestUtil.MakeTargetURL(this.BaseUrl, this.Secure, bucketName, region, usePathStyle); if (objectName != null) { resource += utils.EncodePath(objectName); } // Append query string passed in if (resourcePath != null) { resource += resourcePath; } HttpRequestMessageBuilder messageBuilder; if (!string.IsNullOrEmpty(resource)) { messageBuilder = new HttpRequestMessageBuilder(method, requestUrl, resource); } else { messageBuilder = new HttpRequestMessageBuilder(method, requestUrl); } if (body != null) { messageBuilder.SetBody(body); messageBuilder.AddOrUpdateHeaderParameter("Content-Type", contentType); } if (headerMap != null) { if (headerMap.ContainsKey(messageBuilder.ContentTypeKey) && (!string.IsNullOrEmpty(headerMap[messageBuilder.ContentTypeKey]))) { headerMap[messageBuilder.ContentTypeKey] = contentType; } foreach (var entry in headerMap) { messageBuilder.AddOrUpdateHeaderParameter(entry.Key, entry.Value); } } return(messageBuilder); }
internal virtual HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder) { return(requestMessageBuilder); }
internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder) { requestMessageBuilder.AddQueryParameter("lifecycle", ""); return(requestMessageBuilder); }
internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder) { requestMessageBuilder.AddQueryParameter("replication", ""); return(requestMessageBuilder); }
internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder) { requestMessageBuilder.AddQueryParameter("object-lock", ""); return(requestMessageBuilder); }
/// <summary> /// Set 'Host' http header. /// </summary> /// <param name="requestBuilder">Instantiated requestBuilder object</param> /// <param name="hostUrl">Host url</param> private void SetHostHeader(HttpRequestMessageBuilder requestBuilder, string hostUrl) { requestBuilder.AddHeaderParameter("Host", hostUrl); }
/// <summary> /// Sets 'x-amz-date' http header. /// </summary> /// <param name="requestBuilder">Instantiated requestBuilder object</param> /// <param name="signingDate">Date for signature to be signed</param> private void SetDateHeader(HttpRequestMessageBuilder requestBuilder, DateTime signingDate) { requestBuilder.AddHeaderParameter("x-amz-date", signingDate.ToString("yyyyMMddTHHmmssZ")); }
/// <summary> /// Presigns any input client object with a requested expiry. /// </summary> /// <param name="requestBuilder">Instantiated requestBuilder</param> /// <param name="expires">Expiration in seconds</param> /// <param name="region">Region of storage</param> /// <param name="sessionToken">Value for session token</param> /// <param name="reqDate"> Optional requestBuilder date and time in UTC</param> /// <returns>Presigned url</returns> internal string PresignURL(HttpRequestMessageBuilder requestBuilder, int expires, string region = "", string sessionToken = "", DateTime?reqDate = null) { var signingDate = reqDate ?? DateTime.UtcNow; if (string.IsNullOrWhiteSpace(region)) { region = this.GetRegion(requestBuilder.RequestUri.Host); } Uri requestUri = requestBuilder.RequestUri; string requestQuery = requestUri.Query; SortedDictionary <string, string> headersToSign = this.GetHeadersToSign(requestBuilder); if (!string.IsNullOrEmpty(sessionToken)) { headersToSign["X-Amz-Security-Token"] = sessionToken; } if (requestQuery.Length > 0) { requestQuery += "&"; } requestQuery += "X-Amz-Algorithm=AWS4-HMAC-SHA256&"; requestQuery += "X-Amz-Credential=" + Uri.EscapeDataString(this.accessKey + "/" + this.GetScope(region, signingDate)) + "&"; requestQuery += "X-Amz-Date=" + signingDate.ToString("yyyyMMddTHHmmssZ") + "&"; requestQuery += "X-Amz-Expires=" + expires + "&"; requestQuery += "X-Amz-SignedHeaders=host"; var presignUri = new UriBuilder(requestUri) { Query = requestQuery }.Uri; string canonicalRequest = this.GetPresignCanonicalRequest(requestBuilder.Method, presignUri, headersToSign); string headers = string.Concat(headersToSign.Select(p => $"&{p.Key}={utils.UrlEncode(p.Value)}")); byte[] canonicalRequestBytes = System.Text.Encoding.UTF8.GetBytes(canonicalRequest); string canonicalRequestHash = this.BytesToHex(ComputeSha256(canonicalRequestBytes)); string stringToSign = this.GetStringToSign(region, signingDate, canonicalRequestHash); byte[] signingKey = this.GenerateSigningKey(region, signingDate); byte[] stringToSignBytes = System.Text.Encoding.UTF8.GetBytes(stringToSign); byte[] signatureBytes = this.SignHmac(signingKey, stringToSignBytes); string signature = this.BytesToHex(signatureBytes); // Return presigned url. var signedUri = new UriBuilder(presignUri) { Query = $"{requestQuery}{headers}&X-Amz-Signature={signature}" }; if (signedUri.Uri.IsDefaultPort) { signedUri.Port = -1; } return(signedUri.ToString()); }
/// <summary> /// private helper method to remove list of objects from bucket /// </summary> /// <param name="args">GetObjectArgs Arguments Object encapsulates information like - bucket name, object name etc </param> /// <param name="objectStat"> ObjectStat object encapsulates information like - object name, size, etag etc, represents Object Information </param> /// <param name="cb"> Action object of type Stream, callback to send Object contents, if assigned </param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> private async Task getObjectStreamAsync(GetObjectArgs args, ObjectStat objectStat, Action <Stream> cb, CancellationToken cancellationToken = default(CancellationToken)) { HttpRequestMessageBuilder requestMessageBuilder = await CreateRequest(args).ConfigureAwait(false); await ExecuteTaskAsync(this.NoErrorHandlers, requestMessageBuilder, cancellationToken).ConfigureAwait(false); }