/** @dataProvider provideEntityEnclosingInterfaceMethods */ public function testEntityEnclosingInterfaceMethods($method, array $params = []) { $this->wrappedEntityEnclosingRequest->expects($this->once())->method($method)->will($this->returnValue('ENTITY_ENCL_REQ'))->getMatcher()->parametersMatcher = new ParametersMatcher($params); $this->assertSame('ENTITY_ENCL_REQ', call_user_func_array([$this->unifiedEnclosingEntityRequest, $method], $params)); $this->wrappedRequest->expects($this->any())->method('getMethod')->will($this->returnValue('METHOD')); $this->wrappedRequest->expects($this->any())->method('getPath')->will($this->returnValue('/foo')); $this->setExpectedException('BadMethodCallException', sprintf('Cannot call method "%s" on a request that does not enclose an entity. Did you expect a POST/PUT request instead of METHOD /foo?', $method)); call_user_func_array([$this->unifiedRequest, $method], $params); }
protected function addExpectHeader(EntityEnclosingRequestInterface $request, EntityBodyInterface $body, $expect) { if ($expect === false) { $request->removeHeader('Expect'); } elseif ($expect !== true) { $expect = $expect ?: 1048576; if (is_numeric($expect) && $body->getSize()) { if ($body->getSize() < $expect) { $request->removeHeader('Expect'); } else { $request->setHeader('Expect', '100-Continue'); } } } }
/** * Add the appropriate expect header to a request * * @param EntityEnclosingRequestInterface $request Request to update * @param EntityBodyInterface $body Entity body of the request * @param string|int $expect Expect header setting */ protected function addExpectHeader(EntityEnclosingRequestInterface $request, EntityBodyInterface $body, $expect) { // Allow the `expect` data parameter to be set to remove the Expect header from the request if ($expect === false) { $request->removeHeader('Expect'); } elseif ($expect !== true) { // Default to using a MB as the point in which to start using the expect header $expect = $expect ?: 1048576; // If the expect_header value is numeric then only add if the size is greater than the cutoff if (is_numeric($expect) && $body->getSize()) { if ($body->getSize() < $expect) { $request->removeHeader('Expect'); } else { $request->setHeader('Expect', '100-Continue'); } } } }
/** * Helper method to extract the items from a request object for a BatchWriteItem operation * * @param EntityEnclosingRequestInterface $request * * @return array */ private function extractItemsFromRequestObject(EntityEnclosingRequestInterface $request) { $items = json_decode((string) $request->getBody(), true); return $this->convertResultsToUnprocessedRequests($items['RequestItems'] ?: array()); }
/** * @param RequestInterface|EntityEnclosingRequestInterface $request * @param Credentials $credentials */ public function signRequest($request, $credentials) { $request->setHeader('X-HMB-Signature-Method', self::DEFAULT_METHOD); $request->setHeader('X-HMB-Signature-Version', self::DEFAULT_SIGN_VERSION); $request->setHeader('X-HMB-TimeStamp', time()); $contentMd5 = $request instanceof EntityEnclosingRequestInterface ? md5($request->getBody()) : ''; if ($contentMd5) { $request->setHeader('Content-MD5', $contentMd5); } $sign = array(); $sign[] = strtoupper($request->getMethod()); $sign[] = $request->getHost(); if ($request->getHeader('Content-MD5')) { $sign[] = $request->getHeader('Content-MD5'); } if ($request->getHeader('Content-Type')) { $sign[] = $request->getHeader('Content-Type'); } $sign[] = $request->getHeader('X-HMB-Signature-Method'); $sign[] = $request->getHeader('X-HMB-Signature-Version'); $sign[] = $request->getHeader('X-HMB-TimeStamp'); if ($request->getHeader('X-HMB-User-Session-Token')) { $sign[] = $request->getHeader('X-HMB-User-Session-Token'); } $sign[] = $request->getQuery(true) ? $request->getPath() . '?' . $request->getQuery(true) : $request->getPath(); $signature = base64_encode(hash_hmac(strtolower($request->getHeader('X-HMB-Signature-Method')), implode("\n", $sign), $credentials->getSecret())); $request->setHeader('Authorization', sprintf('%s %s:%s', self::AUTHORIZATION_SCHME, $credentials->getKey(), $signature)); }
/** * Converts a POST request to a GET request by moving POST fields into the * query string. * * Useful for pre-signing query protocol requests. * * @param EntityEnclosingRequestInterface $request Request to clone * * @return RequestInterface * @throws \InvalidArgumentException if the method is not POST */ public static function convertPostToGet(EntityEnclosingRequestInterface $request) { if ($request->getMethod() !== 'POST') { throw new \InvalidArgumentException('Expected a POST request but ' . 'received a ' . $request->getMethod() . ' request.'); } $cloned = RequestFactory::getInstance()->cloneRequestWithMethod($request, 'GET'); // Move POST fields to the query if they are present foreach ($request->getPostFields() as $name => $value) { $cloned->getQuery()->set($name, $value); } return $cloned; }
protected function handleRequestBody(EntityEnclosingRequestInterface $request, array $data) { $files = array_filter($data, function ($element) { return is_string($element) && strpos($element, '@') === 0; }); $request->addPostFields($data); if ($files) { $request->addPostFiles($files); } }
/** * Handles exceptions caused by the request being too large (over 1 MB). The * response will have a status code of 413. In this case the batch should be * split up into smaller batches and retried. * * @param EntityEnclosingRequestInterface $request The failed request * @param UnprocessedWriteRequestsException $unprocessedRequests Collection of unprocessed items */ protected function retryLargeRequest(EntityEnclosingRequestInterface $request, UnprocessedWriteRequestsException $unprocessedRequests) { // Collect the items out from the request object $items = json_decode($request->getBody(true), true); $items = $this->convertResultsToUnprocessedRequests($items['RequestItems']); // Divide batch into smaller batches and transfer them via recursion // NOTE: Dividing the batch into 3 (instead of 2) batches resulted in less recursion during testing if ($items) { $newBatches = array_chunk($items, ceil(count($items) / 3)); foreach ($newBatches as $newBatch) { $this->performTransfer($newBatch, $unprocessedRequests); } } }
/** * Clone a request while changing the method to GET. Emulates the behavior of * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method. * * @param EntityEnclosingRequestInterface $request Request to clone * * @return RequestInterface Returns a GET request */ protected function cloneRequestWithGetMethod(EntityEnclosingRequestInterface $request) { // Create a new GET request using the original request's URL $redirectRequest = $request->getClient()->get($request->getUrl()); $redirectRequest->getCurlOptions()->replace($request->getCurlOptions()->getAll()); // Copy over the headers, while ensuring that the Content-Length is not copied $redirectRequest->setHeaders($request->getHeaders()->getAll())->removeHeader('Content-Length'); $redirectRequest->setEventDispatcher(clone $request->getEventDispatcher()); $redirectRequest->getParams()->replace($request->getParams()->getAll())->remove('curl_handle')->remove('queued_response')->remove('curl_multi'); return $redirectRequest; }