XmlBody.php000064400000013434150031100160006623 0ustar00api = $api; } /** * Builds the XML body based on an array of arguments. * * @param Shape $shape Operation being constructed * @param array $args Associative array of arguments * * @return string */ public function build(Shape $shape, array $args) { $xml = new XMLWriter(); $xml->openMemory(); $xml->startDocument('1.0', 'UTF-8'); $this->format($shape, $shape['locationName'] ?: $shape['name'], $args, $xml); $xml->endDocument(); return $xml->outputMemory(); } private function startElement(Shape $shape, $name, XMLWriter $xml) { $xml->startElement($name); if ($ns = $shape['xmlNamespace']) { $xml->writeAttribute( isset($ns['prefix']) ? "xmlns:{$ns['prefix']}" : 'xmlns', $shape['xmlNamespace']['uri'] ); } } private function format(Shape $shape, $name, $value, XMLWriter $xml) { // Any method mentioned here has a custom serialization handler. static $methods = [ 'add_structure' => true, 'add_list' => true, 'add_blob' => true, 'add_timestamp' => true, 'add_boolean' => true, 'add_map' => true, 'add_string' => true ]; $type = 'add_' . $shape['type']; if (isset($methods[$type])) { $this->{$type}($shape, $name, $value, $xml); } else { $this->defaultShape($shape, $name, $value, $xml); } } private function defaultShape(Shape $shape, $name, $value, XMLWriter $xml) { $this->startElement($shape, $name, $xml); $xml->text($value); $xml->endElement(); } private function add_structure( StructureShape $shape, $name, array $value, \XMLWriter $xml ) { $this->startElement($shape, $name, $xml); foreach ($this->getStructureMembers($shape, $value) as $k => $definition) { $this->format( $definition['member'], $definition['member']['locationName'] ?: $k, $definition['value'], $xml ); } $xml->endElement(); } private function getStructureMembers(StructureShape $shape, array $value) { $members = []; foreach ($value as $k => $v) { if ($v !== null && $shape->hasMember($k)) { $definition = [ 'member' => $shape->getMember($k), 'value' => $v, ]; if ($definition['member']['xmlAttribute']) { // array_unshift_associative $members = [$k => $definition] + $members; } else { $members[$k] = $definition; } } } return $members; } private function add_list( ListShape $shape, $name, array $value, XMLWriter $xml ) { $items = $shape->getMember(); if ($shape['flattened']) { $elementName = $name; } else { $this->startElement($shape, $name, $xml); $elementName = $items['locationName'] ?: 'member'; } foreach ($value as $v) { $this->format($items, $elementName, $v, $xml); } if (!$shape['flattened']) { $xml->endElement(); } } private function add_map( MapShape $shape, $name, array $value, XMLWriter $xml ) { $xmlEntry = $shape['flattened'] ? $shape['locationName'] : 'entry'; $xmlKey = $shape->getKey()['locationName'] ?: 'key'; $xmlValue = $shape->getValue()['locationName'] ?: 'value'; $this->startElement($shape, $name, $xml); foreach ($value as $key => $v) { $this->startElement($shape, $xmlEntry, $xml); $this->format($shape->getKey(), $xmlKey, $key, $xml); $this->format($shape->getValue(), $xmlValue, $v, $xml); $xml->endElement(); } $xml->endElement(); } private function add_blob(Shape $shape, $name, $value, XMLWriter $xml) { $this->startElement($shape, $name, $xml); $xml->writeRaw(base64_encode($value)); $xml->endElement(); } private function add_timestamp( TimestampShape $shape, $name, $value, XMLWriter $xml ) { $this->startElement($shape, $name, $xml); $timestampFormat = !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : 'iso8601'; $xml->writeRaw(TimestampShape::format($value, $timestampFormat)); $xml->endElement(); } private function add_boolean( Shape $shape, $name, $value, XMLWriter $xml ) { $this->startElement($shape, $name, $xml); $xml->writeRaw($value ? 'true' : 'false'); $xml->endElement(); } private function add_string( Shape $shape, $name, $value, XMLWriter $xml ) { if ($shape['xmlAttribute']) { $xml->writeAttribute($shape['locationName'] ?: $name, $value); } else { $this->defaultShape($shape, $name, $value, $xml); } } } QuerySerializer.php000064400000003275150031100160010406 0ustar00api = $api; $this->endpoint = $endpoint; $this->paramBuilder = $paramBuilder ?: new QueryParamBuilder(); } /** * When invoked with an AWS command, returns a serialization array * containing "method", "uri", "headers", and "body" key value pairs. * * @param CommandInterface $command * * @return RequestInterface */ public function __invoke(CommandInterface $command) { $operation = $this->api->getOperation($command->getName()); $body = [ 'Action' => $command->getName(), 'Version' => $this->api->getMetadata('apiVersion') ]; $params = $command->toArray(); // Only build up the parameters when there are parameters to build if ($params) { $body += call_user_func( $this->paramBuilder, $operation->getInput(), $params ); } $body = http_build_query($body, '', '&', PHP_QUERY_RFC3986); return new Request( 'POST', $this->endpoint, [ 'Content-Length' => strlen($body), 'Content-Type' => 'application/x-www-form-urlencoded' ], $body ); } } JsonRpcSerializer.php000064400000003400150031100160010645 0ustar00endpoint = $endpoint; $this->api = $api; $this->jsonFormatter = $jsonFormatter ?: new JsonBody($this->api); $this->contentType = JsonBody::getContentType($api); } /** * When invoked with an AWS command, returns a serialization array * containing "method", "uri", "headers", and "body" key value pairs. * * @param CommandInterface $command * * @return RequestInterface */ public function __invoke(CommandInterface $command) { $name = $command->getName(); $operation = $this->api->getOperation($name); return new Request( $operation['http']['method'], $this->endpoint, [ 'X-Amz-Target' => $this->api->getMetadata('targetPrefix') . '.' . $name, 'Content-Type' => $this->contentType ], $this->jsonFormatter->build( $operation->getInput(), $command->toArray() ) ); } } JsonBody.php000064400000006014150031100160006770 0ustar00api = $api; } /** * Gets the JSON Content-Type header for a service API * * @param Service $service * * @return string */ public static function getContentType(Service $service) { if ($service->getMetadata('protocol') === 'rest-json') { return 'application/json'; } $jsonVersion = $service->getMetadata('jsonVersion'); if (empty($jsonVersion)) { throw new \InvalidArgumentException('invalid json'); } else { return 'application/x-amz-json-' . @number_format($service->getMetadata('jsonVersion'), 1); } } /** * Builds the JSON body based on an array of arguments. * * @param Shape $shape Operation being constructed * @param array $args Associative array of arguments * * @return string */ public function build(Shape $shape, array $args) { $result = json_encode($this->format($shape, $args)); return $result == '[]' ? '{}' : $result; } private function format(Shape $shape, $value) { switch ($shape['type']) { case 'structure': $data = []; if (isset($shape['document']) && $shape['document']) { return $value; } foreach ($value as $k => $v) { if ($v !== null && $shape->hasMember($k)) { $valueShape = $shape->getMember($k); $data[$valueShape['locationName'] ?: $k] = $this->format($valueShape, $v); } } if (empty($data)) { return new \stdClass; } return $data; case 'list': $items = $shape->getMember(); foreach ($value as $k => $v) { $value[$k] = $this->format($items, $v); } return $value; case 'map': if (empty($value)) { return new \stdClass; } $values = $shape->getValue(); foreach ($value as $k => $v) { $value[$k] = $this->format($values, $v); } return $value; case 'blob': return base64_encode($value); case 'timestamp': $timestampFormat = !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : 'unixTimestamp'; return TimestampShape::format($value, $timestampFormat); default: return $value; } } } RestSerializer.php000064400000020124150031100160010206 0ustar00api = $api; $this->endpoint = Psr7\Utils::uriFor($endpoint); } /** * @param CommandInterface $command Command to serialized * * @return RequestInterface */ public function __invoke(CommandInterface $command) { $operation = $this->api->getOperation($command->getName()); $args = $command->toArray(); $opts = $this->serialize($operation, $args); $uri = $this->buildEndpoint($operation, $args, $opts); return new Psr7\Request( $operation['http']['method'], $uri, isset($opts['headers']) ? $opts['headers'] : [], isset($opts['body']) ? $opts['body'] : null ); } /** * Modifies a hash of request options for a payload body. * * @param StructureShape $member Member to serialize * @param array $value Value to serialize * @param array $opts Request options to modify. */ abstract protected function payload( StructureShape $member, array $value, array &$opts ); private function serialize(Operation $operation, array $args) { $opts = []; $input = $operation->getInput(); // Apply the payload trait if present if ($payload = $input['payload']) { $this->applyPayload($input, $payload, $args, $opts); } foreach ($args as $name => $value) { if ($input->hasMember($name)) { $member = $input->getMember($name); $location = $member['location']; if (!$payload && !$location) { $bodyMembers[$name] = $value; } elseif ($location == 'header') { $this->applyHeader($name, $member, $value, $opts); } elseif ($location == 'querystring') { $this->applyQuery($name, $member, $value, $opts); } elseif ($location == 'headers') { $this->applyHeaderMap($name, $member, $value, $opts); } } } if (isset($bodyMembers)) { $this->payload($operation->getInput(), $bodyMembers, $opts); } else if (!isset($opts['body']) && $this->hasPayloadParam($input, $payload)) { $this->payload($operation->getInput(), [], $opts); } return $opts; } private function applyPayload(StructureShape $input, $name, array $args, array &$opts) { if (!isset($args[$name])) { return; } $m = $input->getMember($name); if ($m['streaming'] || ($m['type'] == 'string' || $m['type'] == 'blob') ) { // Streaming bodies or payloads that are strings are // always just a stream of data. $opts['body'] = Psr7\Utils::streamFor($args[$name]); return; } $this->payload($m, $args[$name], $opts); } private function applyHeader($name, Shape $member, $value, array &$opts) { if ($member->getType() === 'timestamp') { $timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'rfc822'; $value = TimestampShape::format($value, $timestampFormat); } elseif ($member->getType() === 'boolean') { $value = $value ? 'true' : 'false'; } if ($member['jsonvalue']) { $value = json_encode($value); if (empty($value) && JSON_ERROR_NONE !== json_last_error()) { throw new \InvalidArgumentException('Unable to encode the provided value' . ' with \'json_encode\'. ' . json_last_error_msg()); } $value = base64_encode($value); } $opts['headers'][$member['locationName'] ?: $name] = $value; } /** * Note: This is currently only present in the Amazon S3 model. */ private function applyHeaderMap($name, Shape $member, array $value, array &$opts) { $prefix = $member['locationName']; foreach ($value as $k => $v) { $opts['headers'][$prefix . $k] = $v; } } private function applyQuery($name, Shape $member, $value, array &$opts) { if ($member instanceof MapShape) { $opts['query'] = isset($opts['query']) && is_array($opts['query']) ? $opts['query'] + $value : $value; } elseif ($value !== null) { $type = $member->getType(); if ($type === 'boolean') { $value = $value ? 'true' : 'false'; } elseif ($type === 'timestamp') { $timestampFormat = !empty($member['timestampFormat']) ? $member['timestampFormat'] : 'iso8601'; $value = TimestampShape::format($value, $timestampFormat); } $opts['query'][$member['locationName'] ?: $name] = $value; } } private function buildEndpoint(Operation $operation, array $args, array $opts) { $varspecs = []; // Create an associative array of varspecs used in expansions foreach ($operation->getInput()->getMembers() as $name => $member) { if ($member['location'] == 'uri') { $varspecs[$member['locationName'] ?: $name] = isset($args[$name]) ? $args[$name] : null; } } $relative = preg_replace_callback( '/\{([^\}]+)\}/', function (array $matches) use ($varspecs) { $isGreedy = substr($matches[1], -1, 1) == '+'; $k = $isGreedy ? substr($matches[1], 0, -1) : $matches[1]; if (!isset($varspecs[$k])) { return ''; } if ($isGreedy) { return str_replace('%2F', '/', rawurlencode($varspecs[$k])); } return rawurlencode($varspecs[$k]); }, $operation['http']['requestUri'] ); // Add the query string variables or appending to one if needed. if (!empty($opts['query'])) { $append = Psr7\Query::build($opts['query']); $relative .= strpos($relative, '?') ? "&{$append}" : "?$append"; } // If endpoint has path, remove leading '/' to preserve URI resolution. $path = $this->endpoint->getPath(); if ($path && $relative[0] === '/') { $relative = substr($relative, 1); } // Expand path place holders using Amazon's slightly different URI // template syntax. return UriResolver::resolve($this->endpoint, new Uri($relative)); } /** * @param StructureShape $input */ private function hasPayloadParam(StructureShape $input, $payload) { if ($payload) { $potentiallyEmptyTypes = ['blob','string']; if ($this->api->getMetadata('protocol') == 'rest-xml') { $potentiallyEmptyTypes[] = 'structure'; } $payloadMember = $input->getMember($payload); if (in_array($payloadMember['type'], $potentiallyEmptyTypes)) { return false; } } foreach ($input->getMembers() as $member) { if (!isset($member['location'])) { return true; } } return false; } } RestJsonSerializer.php000064400000002160150031100160011040 0ustar00contentType = JsonBody::getContentType($api); $this->jsonFormatter = $jsonFormatter ?: new JsonBody($api); } protected function payload(StructureShape $member, array $value, array &$opts) { $body = isset($value) ? ((string) $this->jsonFormatter->build($member, $value)) : "{}"; $opts['headers']['Content-Type'] = $this->contentType; $opts['body'] = $body; } } Ec2ParamBuilder.php000064400000001542150031100160010143 0ustar00getMember(); foreach ($value as $k => $v) { $this->format($items, $v, $prefix . '.' . ($k + 1), $query); } } } } RestXmlSerializer.php000064400000002403150031100160010667 0ustar00xmlBody = $xmlBody ?: new XmlBody($api); } protected function payload(StructureShape $member, array $value, array &$opts) { $opts['headers']['Content-Type'] = 'application/xml'; $opts['body'] = $this->getXmlBody($member, $value); } /** * @param StructureShape $member * @param array $value * @return string */ private function getXmlBody(StructureShape $member, array $value) { $xmlBody = (string)$this->xmlBody->build($member, $value); $xmlBody = str_replace("'", "'", $xmlBody); $xmlBody = str_replace('\r', " ", $xmlBody); $xmlBody = str_replace('\n', " ", $xmlBody); return $xmlBody; } } QueryParamBuilder.php000064400000007663150031100160010651 0ustar00isFlat($shape) && !empty($shape['member']['locationName'])) { return $shape['member']['locationName']; } return $default; } protected function isFlat(Shape $shape) { return $shape['flattened'] === true; } public function __invoke(StructureShape $shape, array $params) { if (!$this->methods) { $this->methods = array_fill_keys(get_class_methods($this), true); } $query = []; $this->format_structure($shape, $params, '', $query); return $query; } protected function format(Shape $shape, $value, $prefix, array &$query) { $type = 'format_' . $shape['type']; if (isset($this->methods[$type])) { $this->{$type}($shape, $value, $prefix, $query); } else { $query[$prefix] = (string) $value; } } protected function format_structure( StructureShape $shape, array $value, $prefix, &$query ) { if ($prefix) { $prefix .= '.'; } foreach ($value as $k => $v) { if ($shape->hasMember($k)) { $member = $shape->getMember($k); $this->format( $member, $v, $prefix . $this->queryName($member, $k), $query ); } } } protected function format_list( ListShape $shape, array $value, $prefix, &$query ) { // Handle empty list serialization if (!$value) { $query[$prefix] = ''; return; } $items = $shape->getMember(); if (!$this->isFlat($shape)) { $locationName = $shape->getMember()['locationName'] ?: 'member'; $prefix .= ".$locationName"; } elseif ($name = $this->queryName($items)) { $parts = explode('.', $prefix); $parts[count($parts) - 1] = $name; $prefix = implode('.', $parts); } foreach ($value as $k => $v) { $this->format($items, $v, $prefix . '.' . ($k + 1), $query); } } protected function format_map( MapShape $shape, array $value, $prefix, array &$query ) { $vals = $shape->getValue(); $keys = $shape->getKey(); if (!$this->isFlat($shape)) { $prefix .= '.entry'; } $i = 0; $keyName = '%s.%d.' . $this->queryName($keys, 'key'); $valueName = '%s.%s.' . $this->queryName($vals, 'value'); foreach ($value as $k => $v) { $i++; $this->format($keys, $k, sprintf($keyName, $prefix, $i), $query); $this->format($vals, $v, sprintf($valueName, $prefix, $i), $query); } } protected function format_blob(Shape $shape, $value, $prefix, array &$query) { $query[$prefix] = base64_encode($value); } protected function format_timestamp( TimestampShape $shape, $value, $prefix, array &$query ) { $timestampFormat = !empty($shape['timestampFormat']) ? $shape['timestampFormat'] : 'iso8601'; $query[$prefix] = TimestampShape::format($value, $timestampFormat); } protected function format_boolean(Shape $shape, $value, $prefix, array &$query) { $query[$prefix] = ($value) ? 'true' : 'false'; } }