/// <summary> /// Upload a file to B2 in a single HTTP payload /// </summary> /// <param name="fileName">The full name of the file (including relative path)</param> /// <param name="sha1Hash">The 40-character SHA1 hash of the file's content</param> /// <param name="size">The size of the file in bytes</param> /// <param name="bucketId">The bucket ID of the bucket where the file will be uploaded</param> /// <param name="stream">The <see cref="Stream"/> that exposes the file content</param> /// <returns>(async) The file upload response</returns> /// <remarks>See https://www.backblaze.com/b2/docs/b2_upload_file.html for additional information</remarks> public async Task <BackblazeB2FileUploadResponse> UploadFile( string fileName, string sha1Hash, long size, string bucketId, Stream stream) { // Get the upload information (destination URL and temporary auth token) GetUploadUrlResponse uploadUrlResponse = await GetUploadUrl(bucketId); BackblazeB2FileUploadResponse uploadResponse; HttpRequestMessage request = CreateRequestMessage( HttpMethod.Post, uploadUrlResponse.UploadUrl); using (request) { // Add the authorization header for the temporary authorization token request.Headers.TryAddWithoutValidation( "Authorization", uploadUrlResponse.AuthorizationToken); // Add the B2 require headers. Note that the filename needs to be URL encoded request.Headers.Add(Constants.Headers.FileName, UrlEncode(fileName)); request.Headers.Add(Constants.Headers.ContentSha1, sha1Hash); request.Content = new DelayedDisposeStreamContent(stream); // Set the content type to 'auto' where B2 will determine the content type request.Content.Headers.ContentType = new MediaTypeHeaderValue("b2/x-auto"); HttpResponseMessage responseMessage = await SendRequestAsync(request).ConfigureAwait(false); using (responseMessage) { uploadResponse = await responseMessage.Content.TryReadAsJsonAsync <BackblazeB2FileUploadResponse>(); } } return(uploadResponse); }
/// <summary> /// /// </summary> /// <param name="file"></param> /// <param name="hash"></param> /// <param name="data"></param> /// <returns>fileId</returns> private async Task <(byte[] encryptedHash, string fileId)> StoreFileAsync(string file, byte[] hash, byte[] data, bool preventEncryption = false) { async Task <GetUploadUrlResponse> GetUploadUrl(int attempts = 0) { if (AuthResp == null) { AuthResp = await AuthorizeAccount(); } Delay(); try { var urlresp = await AuthResp.apiUrl .AppendPathSegment("/b2api/v1/b2_get_upload_url") .WithHeaders(new { Authorization = AuthResp.authorizationToken }) .PostJsonAsync(new { bucketId = BucketId }) .ReceiveJson <GetUploadUrlResponse>().ConfigureAwait(false); SuccessfulTransmission(); return(urlresp); } catch (FlurlHttpException ex) { if (ex.Call.HttpStatus != null && ex.Call.HttpStatus == System.Net.HttpStatusCode.Unauthorized) { AuthResp = null; } else { // Other classes of errors may be congestion related so we increase the delay FailedTransmission(); } if (attempts < Retries) { return(await GetUploadUrl(attempts + 1).ConfigureAwait(false)); } throw; } } var hashFileId = await UploadData(); async Task <(byte[] encryptedHash, string fileId)> UploadData(int attempts = 0) { if (UploadUrlResp == null) { UploadUrlResp = await GetUploadUrl(); } Delay(); try { if (Encryptor != null && !preventEncryption) { data = Encryptor.EncryptBytes(data); hash = HashTools.GetSHA1Hasher().ComputeHash(data); } var filecontent = new ByteArrayContent(data); filecontent.Headers.Add("Content-Type", "application/octet-stream"); var uploadresp = await UploadUrlResp.uploadUrl .WithHeaders(new { Authorization = UploadUrlResp.authorizationToken, X_Bz_File_Name = file, Content_Length = data.Length, X_Bz_Content_Sha1 = HashTools.ByteArrayToHexViaLookup32(hash) }) .PostAsync(filecontent) .ReceiveJson <UploadResponse>().ConfigureAwait(false); SuccessfulTransmission(); return(hash, uploadresp.fileId); } catch (FlurlHttpException ex) { if (ex.Call.HttpStatus != null && ex.Call.HttpStatus == System.Net.HttpStatusCode.Unauthorized) { UploadUrlResp = null; } else { // Other classes of errors may be congestion related so we increase the delay FailedTransmission(); } if (attempts < Retries) { return(await UploadData(attempts + 1).ConfigureAwait(false)); } throw; } } return(hashFileId); }