Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/Api/Serializer/AbstractRpcV2Serializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public function __invoke(
// Content-Type must not be set
if ($operation['input'] !== null) {
$body = $this->serialize($operation->getInput(), $commandArgs);
$headers['Content-Length'] = strlen($body);
$headers['Content-Length'] = (string) strlen($body);
} else {
unset($headers['Content-Type']);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Api/Serializer/JsonRpcSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function __invoke(
$headers = [
'X-Amz-Target' => $this->api->getMetadata('targetPrefix') . '.' . $operationName,
'Content-Type' => $this->contentType,
'Content-Length' => strlen($body)
'Content-Length' => (string) strlen($body)
];

if ($endpoint instanceof RulesetEndpoint) {
Expand Down
2 changes: 1 addition & 1 deletion src/Api/Serializer/QuerySerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function __invoke(
}
$body = http_build_query($body, '', '&', PHP_QUERY_RFC3986);
$headers = [
'Content-Length' => strlen($body),
'Content-Length' => (string) strlen($body),
'Content-Type' => 'application/x-www-form-urlencoded'
];
$requestUri = $operation['http']['requestUri'] ?? null;
Expand Down
2 changes: 1 addition & 1 deletion src/Api/Serializer/RestJsonSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected function payload(StructureShape $member, array|string $value, array &$
{
$opts['headers']['Content-Type'] = $this->contentType;
$body = $this->jsonFormatter->build($member, $value);
$opts['headers']['Content-Length'] = strlen($body);
$opts['headers']['Content-Length'] = (string) strlen($body);
$opts['body'] = $body;
}
}
58 changes: 53 additions & 5 deletions src/Api/Serializer/RestSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ private function applyPayload(StructureShape $input, $name, array $args, array &

$body = $args[$name];
if (!$m['streaming'] && is_string($body)) {
$opts['headers']['Content-Length'] = strlen($body);
$opts['headers']['Content-Length'] = (string) strlen($body);
}

// Streaming bodies or payloads that are strings are
Expand All @@ -173,20 +173,36 @@ private function applyPayload(StructureShape $input, $name, array $args, array &

private function applyHeader($name, Shape $member, $value, array &$opts)
{
// Handle lists by recursively applying header logic to each element
if ($value === null) {
return;
}

// Handle lists by applying header logic to each element
if ($member instanceof ListShape) {
if (!is_array($value)) {
throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
}

$listMember = $member->getMember();
$headerValues = [];

foreach ($value as $listValue) {
if ($listValue === null) {
throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
}

$tempOpts = ['headers' => []];
$this->applyHeader('temp', $listMember, $listValue, $tempOpts);
if (!array_key_exists('temp', $tempOpts['headers'])) {
throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
}

$convertedValue = $tempOpts['headers']['temp'];
$headerValues[] = $convertedValue;
}

$value = $headerValues;
} elseif (!is_null($value)) {
} else {
switch ($member->getType()) {
case 'timestamp':
$timestampFormat = $member['timestampFormat'] ?? 'rfc822';
Expand All @@ -208,7 +224,7 @@ private function applyHeader($name, Shape $member, $value, array &$opts)
$value = base64_encode($value);
}

$opts['headers'][$member['locationName'] ?: $name] = $value;
$opts['headers'][$member['locationName'] ?: $name] = self::prepareHeaderValue($value);
}

/**
Expand All @@ -218,10 +234,42 @@ private function applyHeaderMap($name, Shape $member, array $value, array &$opts
{
$prefix = $member['locationName'];
foreach ($value as $k => $v) {
$opts['headers'][$prefix . $k] = $v;
if ($v === null) {
continue;
}

$opts['headers'][$prefix . $k] = self::prepareHeaderValue($v);
}
}

/**
* @return string|string[]
*/
private static function prepareHeaderValue($value)
{
if (is_scalar($value)) {
return (string) $value;
}

if (is_array($value)) {
if ($value === []) {
return '';
}

foreach ($value as $key => $item) {
if (!is_scalar($item)) {
throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
}

$value[$key] = (string) $item;
}

return $value;
}

throw new \InvalidArgumentException('Header values must be scalar or an array of scalars.');
}

private function applyQuery($name, Shape $member, $value, array &$opts)
{
if ($member instanceof MapShape) {
Expand Down
2 changes: 1 addition & 1 deletion src/Api/Serializer/RestXmlSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected function payload(StructureShape $member, array $value, array &$opts)
{
$opts['headers']['Content-Type'] = 'application/xml';
$body = $this->getXmlBody($member, $value);
$opts['headers']['Content-Length'] = strlen($body);
$opts['headers']['Content-Length'] = (string) strlen($body);
$opts['body'] = $body;
}

Expand Down
2 changes: 1 addition & 1 deletion src/CloudSearchDomain/CloudSearchDomainClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public static function convertGetToPost(RequestInterface $r)
$query = $r->getUri()->getQuery();
$req = $r->withMethod('POST')
->withBody(Psr7\Utils::streamFor($query))
->withHeader('Content-Length', strlen($query))
->withHeader('Content-Length', (string) strlen($query))
->withHeader('Content-Type', 'application/x-www-form-urlencoded')
->withUri($r->getUri()->withQuery(''));
return $req;
Expand Down
2 changes: 1 addition & 1 deletion src/StreamRequestPayloadMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function __invoke(CommandInterface $command, RequestInterface $request)
}
$request = $request->withHeader(
'Content-Length',
$size
(string) $size
);
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/Api/Serializer/JsonRpcSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function () {}
$request->getHeaderLine('Content-Type')
);
$this->assertSame('test.foo', $request->getHeaderLine('X-Amz-Target'));
$this->assertSame(['13'], $request->getHeader('Content-Length'));
$this->assertSame('{"baz":"bam"}', (string) $request->getBody());
}

Expand Down
1 change: 1 addition & 0 deletions tests/Api/Serializer/QuerySerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function () {}
$request = $q($cmd);
$this->assertSame('POST', $request->getMethod());
$this->assertSame('http://foo.com/', (string) $request->getUri());
$this->assertSame(['25'], $request->getHeader('Content-Length'));
$this->assertSame('Action=foo&Version=1&baz=', (string) $request->getBody());
}

Expand Down
80 changes: 80 additions & 0 deletions tests/Api/Serializer/RestJsonSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ private function getTestService(): Service
'http' => ['method' => 'POST'],
'input' => ['shape' => 'BoolHeaderInput']
],
'intHeader' => [
'http' => ['method' => 'POST'],
'input' => ['shape' => 'IntHeaderInput']
],
'nullHeader' => [
'http' => ['method' => 'POST'],
'input' => ['shape' => 'NullHeaderInput']
],
'listHeader' => [
'http' => ['method' => 'POST'],
'input' => ['shape' => 'ListHeaderInput']
],
'requestUriOperation' =>[
'http' => [
'method' => 'POST',
Expand Down Expand Up @@ -182,9 +194,44 @@ private function getTestService(): Service
],
]
],
'IntHeaderInput' => [
'type' => 'structure',
'members' => [
'int' => [
'shape' => 'IntShape',
'location' => 'header',
'locationName' => 'Is-Int',
],
]
],
'NullHeaderInput' => [
'type' => 'structure',
'members' => [
'null' => [
'shape' => 'BazShape',
'location' => 'header',
'locationName' => 'Is-Null',
],
]
],
'ListHeaderInput' => [
'type' => 'structure',
'members' => [
'list' => [
'shape' => 'ListShape',
'location' => 'header',
'locationName' => 'Is-List',
],
]
],
'BlobShape' => ['type' => 'blob'],
'BazShape' => ['type' => 'string'],
'BoolShape' => ['type' => 'boolean'],
'IntShape' => ['type' => 'integer'],
'ListShape' => [
'type' => 'list',
'member' => ['shape' => 'BazShape'],
],
'PathSegmentShape' => ['type' => 'string'],
]
],
Expand Down Expand Up @@ -223,6 +270,7 @@ public function testPreparesRequestsWithContentType(): void
'application/json',
$request->getHeaderLine('Content-Type')
);
$this->assertSame(['13'], $request->getHeader('Content-Length'));
}

public function testPreparesRequestsWithEndpointWithPath(): void
Expand Down Expand Up @@ -409,6 +457,38 @@ public static function boolProvider(): iterable
];
}

public function testSerializesIntegerHeaderValueToString(): void
{
$request = $this->getRequest('intHeader', ['int' => 5]);
$this->assertSame(['5'], $request->getHeader('Is-Int'));
}

public function testOmitsNullHeaderValue(): void
{
$request = $this->getRequest('nullHeader', ['null' => null]);
$this->assertFalse($request->hasHeader('Is-Null'));
}

public function testSerializesEmptyHeaderListToEmptyString(): void
{
$request = $this->getRequest('listHeader', ['list' => []]);
$this->assertSame([''], $request->getHeader('Is-List'));
}

public function testSerializesHeaderListValuesToStrings(): void
{
$request = $this->getRequest('listHeader', ['list' => ['foo', 5, true, false]]);
$this->assertSame(['foo', '5', '1', ''], $request->getHeader('Is-List'));
}

public function testRejectsInvalidHeaderListValue(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Header values must be scalar or an array of scalars.');

$this->getRequest('listHeader', ['list' => ['foo', null]]);
}

public function testDoesNotOverrideScheme(): void
{
$serializer = new RestJsonSerializer($this->getTestService(), 'http://foo.com');
Expand Down
1 change: 1 addition & 0 deletions tests/Api/Serializer/RestXmlSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public function testPreparesRequestsWithStructurePayloadXmlContentType()
'application/xml',
$request->getHeaderLine('Content-Type')
);
$this->assertSame([(string) strlen((string) $request->getBody())], $request->getHeader('Content-Length'));
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/Api/Serializer/RpcV2CborSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,6 @@ public function testSetsCborHeaders(): void
'rpc-v2-cbor',
$request->getHeaderLine('Smithy-Protocol')
);
$this->assertTrue($request->hasHeader('Content-Length'));
$this->assertSame([(string) strlen((string) $request->getBody())], $request->getHeader('Content-Length'));
}
}
1 change: 1 addition & 0 deletions tests/CloudSearchDomain/CloudSearchDomainTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function testConvertGetToPost()
$request = CloudSearchDomainClient::convertGetToPost($request);
$this->assertSame('POST', $request->getMethod());
$this->assertSame('application/x-www-form-urlencoded', $request->getHeaderLine('Content-Type'));
$this->assertSame(['7'], $request->getHeader('Content-Length'));
$this->assertSame('7', $request->getHeaderLine('Content-Length'));
$this->assertSame('foo=bar', (string)$request->getBody());
$this->assertSame('', $request->getUri()->getQuery());
Expand Down
6 changes: 3 additions & 3 deletions tests/StreamRequestPayloadMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static function addsProperHeadersDataProvider(): array
'InputStream' => $inputStream,
]
],
[ 'Content-Length' => [26] ],
[ 'Content-Length' => ['26'] ],
[ 'transfer-encoding' ],
],
[
Expand All @@ -86,7 +86,7 @@ public static function addsProperHeadersDataProvider(): array
'InputStream' => $inputStream,
]
],
[ 'Content-Length' => [26] ],
[ 'Content-Length' => ['26'] ],
[ 'transfer-encoding' ],
],
[
Expand All @@ -96,7 +96,7 @@ public static function addsProperHeadersDataProvider(): array
'InputStream' => $inputStream,
]
],
[ 'Content-Length' => [26] ],
[ 'Content-Length' => ['26'] ],
[ 'transfer-encoding' ],
],
];
Expand Down