Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add md5 to parallel upload #36

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/Blob/BlobClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ private function uploadInBlocks(StreamInterface $content, UploadBlobOptions $opt

$pool->promise()->wait();

$this->putBlockList($blocks, $options);
$this->putBlockList(
$blocks,
$options->contentType,
StreamUtils::hash($content, 'md5', true),
);
}

private function putBlockAsync(Block $block, StreamInterface $content): PromiseInterface
Expand All @@ -218,15 +222,16 @@ private function putBlockAsync(Block $block, StreamInterface $content): PromiseI
/**
* @param Block[] $blocks
*/
private function putBlockList(array $blocks, UploadBlobOptions $options): void
private function putBlockList(array $blocks, ?string $contentType, string $contentMD5): void
{
try {
$this->client->put($this->uri, [
'query' => [
'comp' => 'blocklist',
],
'headers' => [
'x-ms-blob-content-type' => $options->contentType,
'x-ms-blob-content-type' => $contentType,
'x-ms-blob-content-md5' => base64_encode($contentMD5),
],
'body' => (new PutBlockRequestBody($blocks))->toXml()->asXML(),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

namespace AzureOss\Storage\Blob\Exceptions;

final class DateMalformedStringException extends \Exception {}
final class DeserializationException extends \Exception {}
12 changes: 12 additions & 0 deletions src/Blob/Helpers/DateHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace AzureOss\Storage\Blob\Helpers;

use AzureOss\Storage\Blob\Exceptions\DeserializationException;

/**
* @internal
*/
Expand All @@ -15,4 +17,14 @@ public static function formatAs8601Zulu(\DateTimeInterface $date): string
->setTimezone(new \DateTimeZone('UTC'))
->format('Y-m-d\TH:i:s\Z');
}

public static function deserializeDateRfc1123Date(string $date): \DateTimeInterface
{
$result = \DateTimeImmutable::createFromFormat(\DateTimeInterface::RFC1123, $date);
if ($result === false) {
throw new DeserializationException("Azure returned a malformed date.");
}

return $result;
}
}
6 changes: 3 additions & 3 deletions src/Blob/Models/BlobContainerProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace AzureOss\Storage\Blob\Models;

use AzureOss\Storage\Blob\Exceptions\DateMalformedStringException;
use AzureOss\Storage\Blob\Exceptions\DeserializationException;
use AzureOss\Storage\Blob\Helpers\MetadataHelper;
use Psr\Http\Message\ResponseInterface;

Expand All @@ -22,7 +22,7 @@ public static function fromResponseHeaders(ResponseInterface $response): self
{
$lastModified = \DateTimeImmutable::createFromFormat(\DateTimeInterface::RFC1123, $response->getHeaderLine('Last-Modified'));
if ($lastModified === false) {
throw new DateMalformedStringException("Azure returned a malformed date.");
throw new DeserializationException("Azure returned a malformed date.");
}

return new self($lastModified, MetadataHelper::headersToMetadata($response->getHeaders()));
Expand All @@ -32,7 +32,7 @@ public static function fromXml(\SimpleXMLElement $xml): self
{
$lastModified = \DateTimeImmutable::createFromFormat(\DateTimeInterface::RFC1123, (string) $xml->{'Last-Modified'});
if ($lastModified === false) {
throw new DateMalformedStringException("Azure returned a malformed date.");
throw new DeserializationException("Azure returned a malformed date.");
}

return new self(
Expand Down
32 changes: 16 additions & 16 deletions src/Blob/Models/BlobProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace AzureOss\Storage\Blob\Models;

use AzureOss\Storage\Blob\Exceptions\DateMalformedStringException;
use AzureOss\Storage\Blob\Helpers\DateHelper;
use AzureOss\Storage\Blob\Helpers\MetadataHelper;
use Psr\Http\Message\ResponseInterface;

Expand All @@ -17,39 +17,39 @@ public function __construct(
public readonly \DateTimeInterface $lastModified,
public readonly int $contentLength,
public readonly string $contentType,
public readonly string $contentMD5,
public readonly ?string $contentMD5,
public readonly array $metadata,
) {}

public static function fromResponseHeaders(ResponseInterface $response): self
{
$lastModified = \DateTimeImmutable::createFromFormat(\DateTimeInterface::RFC1123, $response->getHeaderLine('Last-Modified'));
if ($lastModified === false) {
throw new DateMalformedStringException("Azure returned a malformed date.");
}

return new BlobProperties(
$lastModified,
DateHelper::deserializeDateRfc1123Date($response->getHeaderLine('Last-Modified')),
(int) $response->getHeaderLine('Content-Length'),
$response->getHeaderLine('Content-Type'),
$response->getHeaderLine('Content-MD5'),
self::deserializeContentMD5($response->getHeaderLine('Content-MD5')),
MetadataHelper::headersToMetadata($response->getHeaders()),
);
}

public static function fromXml(\SimpleXMLElement $xml): self
{
$lastModified = \DateTimeImmutable::createFromFormat(\DateTimeInterface::RFC1123, (string) $xml->{'Last-Modified'});
if ($lastModified === false) {
throw new DateMalformedStringException("Azure returned a malformed date.");
}

return new self(
$lastModified,
DateHelper::deserializeDateRfc1123Date((string) $xml->{'Last-Modified'}),
(int) $xml->{'Content-Length'},
(string) $xml->{'Content-Type'},
(string) $xml->{'Content-MD5'},
self::deserializeContentMD5((string) $xml->{'Content-MD5'}),
[],
);
}

public static function deserializeContentMD5(string $contentMD5): ?string
{
$result = base64_decode($contentMD5, true);
if ($result === false) {
return null;
}

return bin2hex($result);
}
}
2 changes: 1 addition & 1 deletion src/Blob/Models/UploadBlobOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
final class UploadBlobOptions
{
/**
* @param int $initialTransferSize The size of the first range request in bytes. Blobs smaller than this limit will be downloaded in a single request. Blobs larger than this limit will continue being downloaded in chunks of size MaximumTransferSize.
* @param int $initialTransferSize The size of the first range request in bytes. Blobs smaller than this limit will be transferred in a single request. Blobs larger than this limit will continue being transferred in chunks of size MaximumTransferSize.
* @param int $maximumTransferSize The maximum length of a transfer in bytes.
* @param int $maximumConcurrency The maximum number of workers that may be used in a parallel transfer.
*/
Expand Down
5 changes: 3 additions & 2 deletions tests/Blob/Feature/BlobClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,10 @@ public function upload_works_with_parallel_upload(): void
self::assertEquals("text/plain", $properties->contentType);
self::assertEquals(1000, $properties->contentLength);

$afterUploadContent = $this->blobClient->downloadStreaming()->content;
$blob = $this->blobClient->downloadStreaming();

self::assertEquals($beforeUploadContent, $afterUploadContent);
self::assertEquals($beforeUploadContent, $blob->content);
self::assertEquals(md5($beforeUploadContent), $blob->properties->contentMD5);
});
}

Expand Down
Loading