Пример #1
0
 /**
  * Parse the AWS service name from a URL
  *
  * @param Url $url HTTP URL
  *
  * @return string Returns a service name (or empty string)
  * @link http://docs.aws.amazon.com/general/latest/gr/rande.html
  */
 public static function parseServiceName(Url $url)
 {
     // The service name is the first part of the host
     $parts = explode('.', $url->getHost(), 2);
     // Special handling for S3
     if (stripos($parts[0], 's3') === 0) {
         return 's3';
     }
     return $parts[0];
 }
Пример #2
0
 /**
  * Calculate string to sign
  *
  * @param RequestInterface $request   Request to generate a signature for
  * @param int              $timestamp Timestamp to use for nonce
  * @param string           $nonce
  *
  * @return string
  */
 public function getStringToSign(RequestInterface $request, $timestamp, $nonce)
 {
     $params = $this->getParamsToSign($request, $timestamp, $nonce);
     // Convert booleans to strings.
     $params = $this->prepareParameters($params);
     // Build signing string from combined params
     $parameterString = clone $request->getQuery();
     $parameterString->replace($params);
     $url = Url::factory($request->getUrl())->setQuery('')->setFragment(null);
     return strtoupper($request->getMethod()) . '&' . rawurlencode($url) . '&' . rawurlencode((string) $parameterString);
 }
Пример #3
0
 public function setUrl($url)
 {
     if ($url instanceof Url) {
         $this->url = $url;
     } else {
         $this->url = Url::factory($url);
     }
     // Update the port and host header
     $this->setPort($this->url->getPort());
     if ($this->url->getUsername() || $this->url->getPassword()) {
         $this->setAuth($this->url->getUsername(), $this->url->getPassword());
         // Remove the auth info from the URL
         $this->url->setUsername(null);
         $this->url->setPassword(null);
     }
     return $this;
 }
Пример #4
0
 public function signRequest(RequestInterface $request, CredentialsInterface $credentials)
 {
     $timestamp = $this->getTimestamp();
     $longDate = gmdate(DateFormat::ISO8601, $timestamp);
     $shortDate = substr($longDate, 0, 8);
     // Remove any previously set Authorization headers so that retries work
     $request->removeHeader('Authorization');
     // Requires a x-amz-date header or Date
     if ($request->hasHeader('x-amz-date') || !$request->hasHeader('Date')) {
         $request->setHeader('x-amz-date', $longDate);
     } else {
         $request->setHeader('Date', gmdate(DateFormat::RFC1123, $timestamp));
     }
     // Add the security token if one is present
     if ($credentials->getSecurityToken()) {
         $request->setHeader('x-amz-security-token', $credentials->getSecurityToken());
     }
     // Parse the service and region or use one that is explicitly set
     $region = $this->regionName;
     $service = $this->serviceName;
     if (!$region || !$service) {
         $url = Url::factory($request->getUrl());
         $region = $region ?: HostNameUtils::parseRegionName($url);
         $service = $service ?: HostNameUtils::parseServiceName($url);
     }
     $credentialScope = $this->createScope($shortDate, $region, $service);
     $payload = $this->getPayload($request);
     $signingContext = $this->createSigningContext($request, $payload);
     $signingContext['string_to_sign'] = $this->createStringToSign($longDate, $credentialScope, $signingContext['canonical_request']);
     // Calculate the signing key using a series of derived keys
     $signingKey = $this->getSigningKey($shortDate, $region, $service, $credentials->getSecretKey());
     $signature = hash_hmac('sha256', $signingContext['string_to_sign'], $signingKey);
     $request->setHeader('Authorization', "AWS4-HMAC-SHA256 " . "Credential={$credentials->getAccessKeyId()}/{$credentialScope}, " . "SignedHeaders={$signingContext['signed_headers']}, Signature={$signature}");
     // Add debug information to the request
     $request->getParams()->set('aws.signature', $signingContext);
 }
Пример #5
0
 /**
  * Create a redirect request for a specific request object
  *
  * Takes into account strict RFC compliant redirection (e.g. redirect POST with POST) vs doing what most clients do
  * (e.g. redirect POST with GET).
  *
  * @param RequestInterface $request    Request being redirected
  * @param RequestInterface $original   Original request
  * @param int              $statusCode Status code of the redirect
  * @param string           $location   Location header of the redirect
  *
  * @return RequestInterface Returns a new redirect request
  * @throws CouldNotRewindStreamException If the body needs to be rewound but cannot
  */
 protected function createRedirectRequest(RequestInterface $request, $statusCode, $location, RequestInterface $original)
 {
     $redirectRequest = null;
     $strict = $original->getParams()->get(self::STRICT_REDIRECTS);
     // Switch method to GET for 303 redirects.  301 and 302 redirects also switch to GET unless we are forcing RFC
     // compliance to emulate what most browsers do.  NOTE: IE only switches methods on 301/302 when coming from a POST.
     if ($request instanceof EntityEnclosingRequestInterface && ($statusCode == 303 || !$strict && $statusCode <= 302)) {
         $redirectRequest = RequestFactory::getInstance()->cloneRequestWithMethod($request, 'GET');
     } else {
         $redirectRequest = clone $request;
     }
     $redirectRequest->setIsRedirect(true);
     // Always use the same response body when redirecting
     $redirectRequest->setResponseBody($request->getResponseBody());
     $location = Url::factory($location);
     // If the location is not absolute, then combine it with the original URL
     if (!$location->isAbsolute()) {
         $originalUrl = $redirectRequest->getUrl(true);
         // Remove query string parameters and just take what is present on the redirect Location header
         $originalUrl->getQuery()->clear();
         $location = $originalUrl->combine((string) $location, true);
     }
     $redirectRequest->setUrl($location);
     // Add the parent request to the request before it sends (make sure it's before the onRequestClone event too)
     $redirectRequest->getEventDispatcher()->addListener('request.before_send', $func = function ($e) use(&$func, $request, $redirectRequest) {
         $redirectRequest->getEventDispatcher()->removeListener('request.before_send', $func);
         $e['request']->getParams()->set(RedirectPlugin::PARENT_REQUEST, $request);
     });
     // Rewind the entity body of the request if needed
     if ($redirectRequest instanceof EntityEnclosingRequestInterface && $redirectRequest->getBody()) {
         $body = $redirectRequest->getBody();
         // Only rewind the body if some of it has been read already, and throw an exception if the rewind fails
         if ($body->ftell() && !$body->rewind()) {
             throw new CouldNotRewindStreamException('Unable to rewind the non-seekable entity body of the request after redirecting. cURL probably ' . 'sent part of body before the redirect occurred. Try adding acustom rewind function using on the ' . 'entity body of the request using setRewindFunction().');
         }
     }
     return $redirectRequest;
 }
Пример #6
0
 /**
  * Get the URL that this handle is connecting to
  *
  * @return Url
  */
 public function getUrl()
 {
     return Url::factory($this->options->get(CURLOPT_URL));
 }
Пример #7
0
 public function createRequest($method = 'GET', $uri = null, $headers = null, $body = null, array $options = array())
 {
     if (!$uri) {
         $url = $this->getBaseUrl();
     } else {
         if (!is_array($uri)) {
             $templateVars = null;
         } else {
             list($uri, $templateVars) = $uri;
         }
         if (strpos($uri, '://')) {
             // Use absolute URLs as-is
             $url = $this->expandTemplate($uri, $templateVars);
         } else {
             $url = Url::factory($this->getBaseUrl())->combine($this->expandTemplate($uri, $templateVars));
         }
     }
     // If default headers are provided, then merge them under any explicitly provided headers for the request
     if (count($this->defaultHeaders)) {
         if (!$headers) {
             $headers = $this->defaultHeaders->toArray();
         } elseif (is_array($headers)) {
             $headers += $this->defaultHeaders->toArray();
         } elseif ($headers instanceof Collection) {
             $headers = $headers->toArray() + $this->defaultHeaders->toArray();
         }
     }
     return $this->prepareRequest($this->requestFactory->create($method, (string) $url, $headers, $body), $options);
 }
Пример #8
0
 /**
  * Parse the bucket name from a request object
  *
  * @param RequestInterface $request Request to parse
  *
  * @return string
  */
 private function parseBucketName(RequestInterface $request)
 {
     $baseUrl = Url::factory($request->getClient()->getBaseUrl());
     $baseHost = $baseUrl->getHost();
     $host = $request->getHost();
     if (strpos($host, $baseHost) === false) {
         // Does not contain the base URL, so it's either a redirect, CNAME, or using a different region
         $baseHost = '';
         // For every known S3 host, check if that host is present on the request
         $regions = $request->getClient()->getDescription()->getData('regions');
         foreach ($regions as $region) {
             if (strpos($host, $region['hostname']) !== false) {
                 // This host matches the request host. Tells use the region and endpoint-- we can derive the bucket
                 $baseHost = $region['hostname'];
                 break;
             }
         }
         // If no matching base URL was found, then assume that this is a CNAME, and the CNAME is the bucket
         if (!$baseHost) {
             return $host;
         }
     }
     // Remove the baseURL from the host of the request to attempt to determine the bucket name
     return trim(str_replace($baseHost, '', $request->getHost()), ' .');
 }
Пример #9
0
 public function fromParts($method, array $urlParts, $headers = null, $body = null, $protocol = 'HTTP', $protocolVersion = '1.1')
 {
     return $this->create($method, Url::buildUrl($urlParts), $headers, $body)->setProtocolVersion($protocolVersion);
 }
Пример #10
0
 /**
  * Analyzes the provided data and turns it into useful data that can be
  * consumed and used to build an upload form
  *
  * @return PostObject
  */
 public function prepareData()
 {
     // Validate required options
     $options = Collection::fromConfig($this->data, array('ttd' => '+1 hour', 'key' => '^${filename}'));
     // Format ttd option
     $ttd = $options['ttd'];
     $ttd = is_numeric($ttd) ? (int) $ttd : strtotime($ttd);
     unset($options['ttd']);
     // If a policy or policy callback were provided, extract those from the options
     $rawJsonPolicy = $options['policy'];
     $policyCallback = $options['policy_callback'];
     unset($options['policy'], $options['policy_callback']);
     // Setup policy document
     $policy = array('expiration' => gmdate(DateFormat::ISO8601_S3, $ttd), 'conditions' => array(array('bucket' => $this->bucket)));
     // Configure the endpoint/action
     $url = Url::factory($this->client->getBaseUrl());
     if ($url->getScheme() === 'https' && strpos($this->bucket, '.') !== false) {
         // Use path-style URLs
         $url->setPath($this->bucket);
     } else {
         // Use virtual-style URLs
         $url->setHost($this->bucket . '.' . $url->getHost());
     }
     // Setup basic form
     $this->formAttributes = array('action' => (string) $url, 'method' => 'POST', 'enctype' => 'multipart/form-data');
     $this->formInputs = array('AWSAccessKeyId' => $this->client->getCredentials()->getAccessKeyId());
     // Add success action status
     $status = (int) $options->get('success_action_status');
     if ($status && in_array($status, array(200, 201, 204))) {
         $this->formInputs['success_action_status'] = (string) $status;
         $policy['conditions'][] = array('success_action_status' => (string) $status);
         unset($options['success_action_status']);
     }
     // Add other options
     foreach ($options as $key => $value) {
         $value = (string) $value;
         if ($value[0] === '^') {
             $value = substr($value, 1);
             $this->formInputs[$key] = $value;
             $value = preg_replace('/\\$\\{(\\w*)\\}/', '', $value);
             $policy['conditions'][] = array('starts-with', '$' . $key, $value);
         } else {
             $this->formInputs[$key] = $value;
             $policy['conditions'][] = array($key => $value);
         }
     }
     // Handle the policy
     $policy = is_callable($policyCallback) ? $policyCallback($policy, $this) : $policy;
     $this->jsonPolicy = $rawJsonPolicy ?: json_encode($policy);
     $this->applyPolicy();
     return $this;
 }