コード例 #1
0
 public void ForceHTTPS()
 {
     URL          = URLHelpers.ForcePrefix(URL);
     ThumbnailURL = URLHelpers.ForcePrefix(ThumbnailURL);
     DeletionURL  = URLHelpers.ForcePrefix(DeletionURL);
     ShortenedURL = URLHelpers.ForcePrefix(ShortenedURL);
 }
コード例 #2
0
ファイル: AzureStorage.cs プロジェクト: rchcomm/ShareX
        public override UploadResult Upload(Stream stream, string fileName)
        {
            if (string.IsNullOrEmpty(AzureStorageAccountName))
            {
                Errors.Add("'Account Name' must not be empty");
            }
            if (string.IsNullOrEmpty(AzureStorageAccountAccessKey))
            {
                Errors.Add("'Access key' must not be empty");
            }
            if (string.IsNullOrEmpty(AzureStorageContainer))
            {
                Errors.Add("'Container' must not be empty");
            }

            if (IsError)
            {
                return(null);
            }

            CreateContainerIfNotExists();

            string date       = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture);
            string url        = $"https://{AzureStorageAccountName}.{AzureStorageEnvironment}/{AzureStorageContainer}/{fileName}";
            string urlForCopy = url;

            if (!string.IsNullOrEmpty(AzureStorageCustomDomain))
            {
                // Azure Blob Storage does not support https with custom domains at this time
                urlForCopy = URLHelpers.ForcePrefix(URLHelpers.CombineURL(AzureStorageCustomDomain, AzureStorageContainer, fileName), "http://");
            }

            string contentType = Helpers.GetMimeType(fileName);

            NameValueCollection requestHeaders = new NameValueCollection();

            requestHeaders["x-ms-date"]      = date;
            requestHeaders["x-ms-version"]   = APIVersion;
            requestHeaders["x-ms-blob-type"] = "BlockBlob";

            string canonicalizedHeaders  = $"x-ms-blob-type:BlockBlob\nx-ms-date:{date}\nx-ms-version:{APIVersion}\n";
            string canonicalizedResource = $"/{AzureStorageAccountName}/{AzureStorageContainer}/{fileName}";
            string stringToSign          = GenerateStringToSign(canonicalizedHeaders, canonicalizedResource, stream.Length.ToString(), contentType);

            requestHeaders["Authorization"] = $"SharedKey {AzureStorageAccountName}:{stringToSign}";

            NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, url, stream, contentType, null, requestHeaders, null);

            if (responseHeaders != null)
            {
                return(new UploadResult {
                    IsSuccess = true, URL = urlForCopy
                });
            }
            else
            {
                Errors.Add("Upload failed.");
                return(null);
            }
        }
コード例 #3
0
        private void TranscodeFile(UploadResult result)
        {
            StreamableTranscodeResponse transcodeResponse = JsonConvert.DeserializeObject <StreamableTranscodeResponse>(result.Response);

            if (!string.IsNullOrEmpty(transcodeResponse.Shortcode))
            {
                ProgressManager progress = new ProgressManager(100);
                OnProgressChanged(progress);

                while (!StopUploadRequested)
                {
                    string statusJson = SendRequest(HttpMethod.GET, URLHelpers.CombineURL(Host, "videos", transcodeResponse.Shortcode));
                    StreamableStatusResponse response = JsonConvert.DeserializeObject <StreamableStatusResponse>(statusJson);

                    if (response.status > 2)
                    {
                        Errors.Add(response.message);
                        result.IsSuccess = false;
                        break;
                    }
                    else if (response.status == 2)
                    {
                        progress.UpdateProgress(100 - progress.Position);
                        OnProgressChanged(progress);

                        result.IsSuccess = true;

                        if (UseDirectURL && response.files != null && response.files.mp4 != null && !string.IsNullOrEmpty(response.files.mp4.url))
                        {
                            result.URL = URLHelpers.ForcePrefix(response.files.mp4.url);
                        }
                        else
                        {
                            result.URL = URLHelpers.ForcePrefix(response.url);
                        }

                        break;
                    }

                    progress.UpdateProgress(response.percent - progress.Position);
                    OnProgressChanged(progress);

                    Thread.Sleep(1000);
                }
            }
            else
            {
                Errors.Add("Could not create video");
                result.IsSuccess = false;
            }
        }
コード例 #4
0
        public override UploadResult ShortenURL(string url)
        {
            UploadResult result = new UploadResult {
                URL = url
            };

            string RequestUrl      = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks";
            string longDynamicLink = URLHelpers.ForcePrefix(DynamicLinkDomain + ".app.goo.gl/?link=" + HttpUtility.UrlEncode(url));
            string option;

            Dictionary <string, string> args = new Dictionary <string, string>
            {
                { "key", WebAPIKey }
            };

            if (IsShort)
            {
                option = "SHORT";
            }
            else
            {
                option = "UNGUESSABLE";
            }

            FirebaseRequest request = new FirebaseRequest
            {
                longDynamicLink = longDynamicLink,
                suffix          = new FirebaseRequestSuffix
                {
                    option = option
                }
            };

            string json = JsonConvert.SerializeObject(request);

            result.Response     = SendRequest(HttpMethod.POST, RequestUrl, json, ContentTypeJSON, args);
            result.ShortenedURL = JsonConvert.DeserializeObject <FirebaseResponse>(result.Response).shortLink;

            return(result);
        }
コード例 #5
0
        public override UploadResult Upload(Stream stream, string fileName)
        {
            bool forcePathStyle = Settings.UsePathStyle;

            if (!forcePathStyle && Settings.Bucket.Contains("."))
            {
                forcePathStyle = true;
            }

            string endpoint            = URLHelpers.RemovePrefixes(Settings.Endpoint);
            string host                = forcePathStyle ? endpoint : $"{Settings.Bucket}.{endpoint}";
            string algorithm           = "AWS4-HMAC-SHA256";
            string credentialDate      = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
            string region              = GetRegion();
            string scope               = URLHelpers.CombineURL(credentialDate, region, "s3", "aws4_request");
            string credential          = URLHelpers.CombineURL(Settings.AccessKeyID, scope);
            string longDate            = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture);
            string expiresTotalSeconds = ((long)TimeSpan.FromHours(1).TotalSeconds).ToString();
            string contentType         = Helpers.GetMimeType(fileName);

            NameValueCollection headers = new NameValueCollection();

            headers["content-type"] = contentType;
            headers["host"]         = host;
            if (Settings.SetPublicACL)
            {
                headers["x-amz-acl"] = "public-read";
            }
            headers["x-amz-storage-class"] = Settings.StorageClass.ToString();

            string signedHeaders = GetSignedHeaders(headers);

            Dictionary <string, string> args = new Dictionary <string, string>();

            args.Add("X-Amz-Algorithm", algorithm);
            args.Add("X-Amz-Credential", credential);
            args.Add("X-Amz-Date", longDate);
            args.Add("X-Amz-Expires", expiresTotalSeconds);
            args.Add("X-Amz-SignedHeaders", signedHeaders);

            string uploadPath = GetUploadPath(fileName);

            string canonicalURI = uploadPath;

            if (forcePathStyle)
            {
                canonicalURI = URLHelpers.CombineURL(Settings.Bucket, canonicalURI);
            }
            canonicalURI = URLHelpers.AddSlash(canonicalURI, SlashType.Prefix);
            canonicalURI = URLHelpers.URLPathEncode(canonicalURI);

            string canonicalQueryString = URLHelpers.CreateQuery(args, true);
            string canonicalHeaders     = CreateCanonicalHeaders(headers);

            string canonicalRequest = "PUT" + "\n" +
                                      canonicalURI + "\n" +
                                      canonicalQueryString + "\n" +
                                      canonicalHeaders + "\n" +
                                      signedHeaders + "\n" +
                                      "UNSIGNED-PAYLOAD";

            string stringToSign = algorithm + "\n" +
                                  longDate + "\n" +
                                  scope + "\n" +
                                  Helpers.BytesToHex(Helpers.ComputeSHA256(canonicalRequest));

            byte[] dateKey              = Helpers.ComputeHMACSHA256(credentialDate, "AWS4" + Settings.SecretAccessKey);
            byte[] dateRegionKey        = Helpers.ComputeHMACSHA256(region, dateKey);
            byte[] dateRegionServiceKey = Helpers.ComputeHMACSHA256("s3", dateRegionKey);
            byte[] signingKey           = Helpers.ComputeHMACSHA256("aws4_request", dateRegionServiceKey);
            string signature            = Helpers.BytesToHex(Helpers.ComputeHMACSHA256(stringToSign, signingKey));

            args.Add("X-Amz-Signature", signature);

            headers.Remove("content-type");
            headers.Remove("host");

            string url = URLHelpers.CombineURL(host, canonicalURI);

            url = URLHelpers.CreateQuery(url, args, true);
            url = URLHelpers.ForcePrefix(url, "https://");

            NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, url, stream, contentType, null, headers);

            if (responseHeaders == null || responseHeaders.Count == 0)
            {
                Errors.Add("Upload to Amazon S3 failed. Check your access credentials.");
                return(null);
            }

            if (responseHeaders["ETag"] == null)
            {
                Errors.Add("Upload to Amazon S3 failed.");
                return(null);
            }

            return(new UploadResult
            {
                IsSuccess = true,
                URL = GenerateURL(uploadPath)
            });
        }
コード例 #6
0
ファイル: AmazonS3.cs プロジェクト: ralic/ShareX
        public override UploadResult Upload(Stream stream, string fileName)
        {
            bool isPathStyleRequest = Settings.UsePathStyle;

            if (!isPathStyleRequest && Settings.Bucket.Contains("."))
            {
                isPathStyleRequest = true;
            }

            string endpoint       = URLHelpers.RemovePrefixes(Settings.Endpoint);
            string host           = isPathStyleRequest ? endpoint : $"{Settings.Bucket}.{endpoint}";
            string algorithm      = "AWS4-HMAC-SHA256";
            string credentialDate = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
            string region         = GetRegion();
            string scope          = URLHelpers.CombineURL(credentialDate, region, "s3", "aws4_request");
            string credential     = URLHelpers.CombineURL(Settings.AccessKeyID, scope);
            string timeStamp      = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture);
            string contentType    = Helpers.GetMimeType(fileName);
            string uploadPath     = GetUploadPath(fileName);
            string hashedPayload  = "UNSIGNED-PAYLOAD";

            NameValueCollection headers = new NameValueCollection();

            headers["host"]                 = host;
            headers["content-type"]         = contentType;
            headers["x-amz-date"]           = timeStamp;
            headers["x-amz-content-sha256"] = hashedPayload;
            headers["x-amz-storage-class"]  = Settings.StorageClass.ToString();
            if (Settings.SetPublicACL)
            {
                headers["x-amz-acl"] = "public-read";
            }

            string canonicalURI = uploadPath;

            if (isPathStyleRequest)
            {
                canonicalURI = URLHelpers.CombineURL(Settings.Bucket, canonicalURI);
            }
            canonicalURI = URLHelpers.AddSlash(canonicalURI, SlashType.Prefix);
            canonicalURI = URLHelpers.URLPathEncode(canonicalURI);
            string canonicalQueryString = "";
            string canonicalHeaders     = CreateCanonicalHeaders(headers);
            string signedHeaders        = GetSignedHeaders(headers);

            string canonicalRequest = "PUT" + "\n" +
                                      canonicalURI + "\n" +
                                      canonicalQueryString + "\n" +
                                      canonicalHeaders + "\n" +
                                      signedHeaders + "\n" +
                                      hashedPayload;

            string stringToSign = algorithm + "\n" +
                                  timeStamp + "\n" +
                                  scope + "\n" +
                                  Helpers.BytesToHex(Helpers.ComputeSHA256(canonicalRequest));

            byte[] dateKey              = Helpers.ComputeHMACSHA256(credentialDate, "AWS4" + Settings.SecretAccessKey);
            byte[] dateRegionKey        = Helpers.ComputeHMACSHA256(region, dateKey);
            byte[] dateRegionServiceKey = Helpers.ComputeHMACSHA256("s3", dateRegionKey);
            byte[] signingKey           = Helpers.ComputeHMACSHA256("aws4_request", dateRegionServiceKey);

            string signature = Helpers.BytesToHex(Helpers.ComputeHMACSHA256(stringToSign, signingKey));

            headers["Authorization"] = algorithm + " " +
                                       "Credential=" + credential + "," +
                                       "SignedHeaders=" + signedHeaders + "," +
                                       "Signature=" + signature;

            headers.Remove("host");
            headers.Remove("content-type");

            string url = URLHelpers.CombineURL(host, canonicalURI);

            url = URLHelpers.ForcePrefix(url, "https://");

            NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, url, stream, contentType, null, headers);

            if (responseHeaders == null || responseHeaders.Count == 0 || responseHeaders["ETag"] == null)
            {
                Errors.Add("Upload to Amazon S3 failed.");
                return(null);
            }

            return(new UploadResult
            {
                IsSuccess = true,
                URL = GenerateURL(uploadPath)
            });
        }
コード例 #7
0
ファイル: AmazonS3.cs プロジェクト: zhangjianxi2008/ShareX
        public override UploadResult Upload(Stream stream, string fileName)
        {
            if (string.IsNullOrEmpty(s3Settings.AccessKeyID))
            {
                Errors.Add("'Access Key' must not be empty.");
            }
            if (string.IsNullOrEmpty(s3Settings.SecretAccessKey))
            {
                Errors.Add("'Secret Access Key' must not be empty.");
            }
            if (string.IsNullOrEmpty(s3Settings.Bucket))
            {
                Errors.Add("'Bucket' must not be empty.");
            }
            if (GetCurrentRegion(s3Settings) == UnknownEndpoint)
            {
                Errors.Add("Please select an endpoint.");
            }

            if (IsError)
            {
                return(null);
            }

            AmazonS3Region region = GetCurrentRegion(s3Settings);

            AmazonS3Config s3ClientConfig = new AmazonS3Config();

            if (region.AmazonRegion == null)
            {
                s3ClientConfig.ServiceURL = URLHelpers.ForcePrefix(region.Hostname);
            }
            else
            {
                s3ClientConfig.RegionEndpoint = region.AmazonRegion;
            }

            using (AmazonS3Client client = new AmazonS3Client(GetCurrentCredentials(), s3ClientConfig))
            {
                GetPreSignedUrlRequest putRequest = new GetPreSignedUrlRequest
                {
                    BucketName  = s3Settings.Bucket,
                    Key         = GetObjectKey(fileName),
                    Verb        = HttpVerb.PUT,
                    Expires     = DateTime.UtcNow.AddMinutes(5),
                    ContentType = Helpers.GetMimeType(fileName)
                };

                NameValueCollection requestHeaders = new NameValueCollection();
                requestHeaders["x-amz-acl"]           = "public-read";
                requestHeaders["x-amz-storage-class"] = GetObjectStorageClass();

                putRequest.Headers["x-amz-acl"]           = "public-read";
                putRequest.Headers["x-amz-storage-class"] = GetObjectStorageClass();

                NameValueCollection responseHeaders = SendRequestStreamGetHeaders(client.GetPreSignedURL(putRequest), stream, Helpers.GetMimeType(fileName), requestHeaders, method: HttpMethod.PUT);
                if (responseHeaders.Count == 0)
                {
                    Errors.Add("Upload to Amazon S3 failed. Check your access credentials.");
                    return(null);
                }

                string eTag = responseHeaders.Get("ETag");
                if (eTag == null)
                {
                    Errors.Add("Upload to Amazon S3 failed.");
                    return(null);
                }

                if (GetMd5Hash(stream) == eTag.Replace("\"", ""))
                {
                    return(new UploadResult {
                        IsSuccess = true, URL = GetObjectURL(putRequest.Key)
                    });
                }

                Errors.Add("Upload to Amazon S3 failed, uploaded data did not match.");
                return(null);
            }
        }
コード例 #8
0
ファイル: AmazonS3.cs プロジェクト: zhangjianxi2008/ShareX
 private string GetEndpoint()
 {
     return(URLHelpers.ForcePrefix(URLHelpers.CombineURL(GetCurrentRegion(s3Settings).Hostname, s3Settings.Bucket)));
 }
コード例 #9
0
        public override UploadResult Upload(Stream stream, string fileName)
        {
            bool isPathStyleRequest = Settings.UsePathStyle;

            if (!isPathStyleRequest && Settings.Bucket.Contains("."))
            {
                isPathStyleRequest = true;
            }

            string endpoint       = URLHelpers.RemovePrefixes(Settings.Endpoint);
            string host           = isPathStyleRequest ? endpoint : $"{Settings.Bucket}.{endpoint}";
            string algorithm      = "AWS4-HMAC-SHA256";
            string credentialDate = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
            string region         = GetRegion();
            string scope          = URLHelpers.CombineURL(credentialDate, region, "s3", "aws4_request");
            string credential     = URLHelpers.CombineURL(Settings.AccessKeyID, scope);
            string timeStamp      = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture);
            string contentType    = RequestHelpers.GetMimeType(fileName);
            string hashedPayload;

            if (Settings.SignedPayload)
            {
                hashedPayload = Helpers.BytesToHex(Helpers.ComputeSHA256(stream));
            }
            else
            {
                hashedPayload = "UNSIGNED-PAYLOAD";
            }

            string uploadPath = GetUploadPath(fileName);
            string resultURL  = GenerateURL(uploadPath);

            OnEarlyURLCopyRequested(resultURL);

            NameValueCollection headers = new NameValueCollection
            {
                ["Host"]                 = host,
                ["Content-Length"]       = stream.Length.ToString(),
                ["Content-Type"]         = contentType,
                ["x-amz-date"]           = timeStamp,
                ["x-amz-content-sha256"] = hashedPayload,
                // If you don't specify, S3 Standard is the default storage class. Amazon S3 supports other storage classes.
                // Valid Values: STANDARD | REDUCED_REDUNDANCY | STANDARD_IA | ONEZONE_IA | INTELLIGENT_TIERING | GLACIER | DEEP_ARCHIVE
                // https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html
                ["x-amz-storage-class"] = Settings.StorageClass.ToString()
            };

            if (Settings.SetPublicACL)
            {
                // The canned ACL to apply to the object. For more information, see Canned ACL.
                // https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl
                headers["x-amz-acl"] = "public-read";
            }

            string canonicalURI = uploadPath;

            if (isPathStyleRequest)
            {
                canonicalURI = URLHelpers.CombineURL(Settings.Bucket, canonicalURI);
            }
            canonicalURI = URLHelpers.AddSlash(canonicalURI, SlashType.Prefix);
            canonicalURI = URLHelpers.URLEncode(canonicalURI, true);
            string canonicalQueryString = "";
            string canonicalHeaders     = CreateCanonicalHeaders(headers);
            string signedHeaders        = GetSignedHeaders(headers);

            string canonicalRequest = "PUT" + "\n" +
                                      canonicalURI + "\n" +
                                      canonicalQueryString + "\n" +
                                      canonicalHeaders + "\n" +
                                      signedHeaders + "\n" +
                                      hashedPayload;

            string stringToSign = algorithm + "\n" +
                                  timeStamp + "\n" +
                                  scope + "\n" +
                                  Helpers.BytesToHex(Helpers.ComputeSHA256(canonicalRequest));

            byte[] dateKey              = Helpers.ComputeHMACSHA256(credentialDate, "AWS4" + Settings.SecretAccessKey);
            byte[] dateRegionKey        = Helpers.ComputeHMACSHA256(region, dateKey);
            byte[] dateRegionServiceKey = Helpers.ComputeHMACSHA256("s3", dateRegionKey);
            byte[] signingKey           = Helpers.ComputeHMACSHA256("aws4_request", dateRegionServiceKey);

            string signature = Helpers.BytesToHex(Helpers.ComputeHMACSHA256(stringToSign, signingKey));

            headers["Authorization"] = algorithm + " " +
                                       "Credential=" + credential + "," +
                                       "SignedHeaders=" + signedHeaders + "," +
                                       "Signature=" + signature;

            headers.Remove("Host");
            headers.Remove("Content-Type");

            string url = URLHelpers.CombineURL(host, canonicalURI);

            url = URLHelpers.ForcePrefix(url, "https://");

            SendRequest(HttpMethod.PUT, url, stream, contentType, null, headers);

            if (LastResponseInfo != null && LastResponseInfo.IsSuccess)
            {
                return(new UploadResult
                {
                    IsSuccess = true,
                    URL = resultURL
                });
            }

            Errors.Add("Upload to Amazon S3 failed.");
            return(null);
        }
コード例 #10
0
        private void DoAfterUploadJobs()
        {
            try
            {
                if (Info.TaskSettings.AdvancedSettings.ResultForceHTTPS)
                {
                    Info.Result.URL          = URLHelpers.ForcePrefix(Info.Result.URL);
                    Info.Result.ThumbnailURL = URLHelpers.ForcePrefix(Info.Result.ThumbnailURL);
                    Info.Result.DeletionURL  = URLHelpers.ForcePrefix(Info.Result.DeletionURL);
                }

                if (Info.Job != TaskJob.ShareURL && (Info.TaskSettings.AfterUploadJob.HasFlag(AfterUploadTasks.UseURLShortener) || Info.Job == TaskJob.ShortenURL ||
                                                     (Info.TaskSettings.AdvancedSettings.AutoShortenURLLength > 0 && Info.Result.URL.Length > Info.TaskSettings.AdvancedSettings.AutoShortenURLLength)))
                {
                    UploadResult result = ShortenURL(Info.Result.URL);

                    if (result != null)
                    {
                        Info.Result.ShortenedURL = result.ShortenedURL;
                        Info.Result.Errors.AddRange(result.Errors);
                    }
                }

                if (Info.Job != TaskJob.ShortenURL && (Info.TaskSettings.AfterUploadJob.HasFlag(AfterUploadTasks.ShareURL) || Info.Job == TaskJob.ShareURL))
                {
                    UploadResult result = ShareURL(Info.Result.ToString());

                    if (result != null)
                    {
                        Info.Result.Errors.AddRange(result.Errors);
                    }

                    if (Info.Job == TaskJob.ShareURL)
                    {
                        Info.Result.IsURLExpected = false;
                    }
                }

                if (Info.TaskSettings.AfterUploadJob.HasFlag(AfterUploadTasks.CopyURLToClipboard))
                {
                    string txt;

                    if (!string.IsNullOrEmpty(Info.TaskSettings.AdvancedSettings.ClipboardContentFormat))
                    {
                        txt = new UploadInfoParser().Parse(Info, Info.TaskSettings.AdvancedSettings.ClipboardContentFormat);
                    }
                    else
                    {
                        txt = Info.Result.ToString();
                    }

                    if (!string.IsNullOrEmpty(txt))
                    {
                        ClipboardHelpers.CopyText(txt);
                    }
                }

                if (Info.TaskSettings.AfterUploadJob.HasFlag(AfterUploadTasks.OpenURL))
                {
                    string result;

                    if (!string.IsNullOrEmpty(Info.TaskSettings.AdvancedSettings.OpenURLFormat))
                    {
                        result = new UploadInfoParser().Parse(Info, Info.TaskSettings.AdvancedSettings.OpenURLFormat);
                    }
                    else
                    {
                        result = Info.Result.ToString();
                    }

                    URLHelpers.OpenURL(result);
                }

                if (Info.TaskSettings.AfterUploadJob.HasFlag(AfterUploadTasks.ShowQRCode))
                {
                    threadWorker.InvokeAsync(() => new QRCodeForm(Info.Result.ToString()).Show());
                }
            }
            catch (Exception e)
            {
                DebugHelper.WriteException(e);
                AddErrorMessage(e.ToString());
            }
        }
コード例 #11
0
ファイル: AmazonS3.cs プロジェクト: Gigabait/ShareX
        public override UploadResult Upload(Stream stream, string fileName)
        {
            string hostname            = URLHelpers.RemovePrefixes(Settings.RegionHostname);
            string host                = $"{Settings.Bucket}.{hostname}";
            string algorithm           = "AWS4-HMAC-SHA256";
            string credentialDate      = DateTime.UtcNow.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
            string scope               = $"{credentialDate}/{Settings.RegionIdentifier}/s3/aws4_request";
            string credential          = $"{Settings.AccessKeyID}/{scope}";
            string longDate            = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture);
            string expiresTotalSeconds = ((long)TimeSpan.FromHours(1).TotalSeconds).ToString();
            string contentType         = Helpers.GetMimeType(fileName);

            NameValueCollection headers = new NameValueCollection();

            headers["content-type"]        = contentType;
            headers["host"]                = host;
            headers["x-amz-acl"]           = "public-read";
            headers["x-amz-storage-class"] = Settings.UseReducedRedundancyStorage ? "REDUCED_REDUNDANCY" : "STANDARD";

            string signedHeaders = GetSignedHeaders(headers);

            Dictionary <string, string> args = new Dictionary <string, string>();

            args.Add("X-Amz-Algorithm", algorithm);
            args.Add("X-Amz-Credential", credential);
            args.Add("X-Amz-Date", longDate);
            args.Add("X-Amz-Expires", expiresTotalSeconds);
            args.Add("X-Amz-SignedHeaders", signedHeaders);

            string uploadPath   = GetUploadPath(fileName);
            string canonicalURI = URLHelpers.AddSlash(uploadPath, SlashType.Prefix);

            canonicalURI = URLHelpers.URLPathEncode(canonicalURI);

            string canonicalQueryString = CreateQueryString(args);
            string canonicalHeaders     = CreateCanonicalHeaders(headers);

            string canonicalRequest = "PUT" + "\n" +
                                      canonicalURI + "\n" +
                                      canonicalQueryString + "\n" +
                                      canonicalHeaders + "\n" +
                                      signedHeaders + "\n" +
                                      "UNSIGNED-PAYLOAD";

            string stringToSign = algorithm + "\n" +
                                  longDate + "\n" +
                                  scope + "\n" +
                                  BytesToHex(ComputeHash(canonicalRequest));

            byte[] secretKey            = Encoding.UTF8.GetBytes("AWS4" + Settings.SecretAccessKey);
            byte[] dateKey              = ComputeHMAC(Encoding.UTF8.GetBytes(credentialDate), secretKey);
            byte[] dateRegionKey        = ComputeHMAC(Encoding.UTF8.GetBytes(Settings.RegionIdentifier), dateKey);
            byte[] dateRegionServiceKey = ComputeHMAC(Encoding.UTF8.GetBytes("s3"), dateRegionKey);
            byte[] signingKey           = ComputeHMAC(Encoding.UTF8.GetBytes("aws4_request"), dateRegionServiceKey);
            string signature            = BytesToHex(ComputeHMAC(Encoding.UTF8.GetBytes(stringToSign), signingKey));

            args.Add("X-Amz-Signature", signature);

            headers.Remove("content-type");
            headers.Remove("host");

            string url = URLHelpers.CombineURL(host, canonicalURI) + "?" + CreateQueryString(args);

            url = URLHelpers.ForcePrefix(url, "https://");

            NameValueCollection responseHeaders = SendRequestGetHeaders(HttpMethod.PUT, url, stream, contentType, null, headers);

            if (responseHeaders == null || responseHeaders.Count == 0)
            {
                Errors.Add("Upload to Amazon S3 failed. Check your access credentials.");
                return(null);
            }

            if (responseHeaders["ETag"] == null)
            {
                Errors.Add("Upload to Amazon S3 failed.");
                return(null);
            }

            return(new UploadResult
            {
                IsSuccess = true,
                URL = GenerateURL(fileName)
            });
        }